Skip to content

Commit

Permalink
fix(mini-runner): 修复 watch 时文件过多爆栈的问题 && 修改 app.js 时出错的问题,closes #5630
Browse files Browse the repository at this point in the history
…closes #5433
  • Loading branch information
luckyadam committed Mar 8, 2020
1 parent c2d4c3c commit 7480ff7
Show file tree
Hide file tree
Showing 9 changed files with 293 additions and 348 deletions.
59 changes: 59 additions & 0 deletions packages/taro-mini-runner/src/loaders/pitcher.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import * as path from 'path'
import * as qs from 'querystring'

import { stringifyRequest, getOptions } from 'loader-utils'
import { MINI_APP_FILES, NODE_MODULES_REG, NODE_MODULES } from '../utils/constants'

const isPitcher = l => l.path !== __filename
const isPreLoader = l => !l.pitchExecuted
const isPostLoader = l => l.pitchExecuted

export default code => code

const genRequest = (loaderRequest, loaders) => {
const seen = new Map()
const loaderStrings: string[] = []
loaders.forEach(loader => {
const identifier = typeof loader === 'string'
? loader
: (loader.path + loader.query)
const request = typeof loader === 'string' ? loader : loader.request
if (!seen.has(identifier)) {
seen.set(identifier, true)
loaderStrings.push(request)
}
})

return stringifyRequest(loaderRequest, '-!' + [
...loaderStrings,
loaderRequest.resourcePath + loaderRequest.resourceQuery
].join('!'))
}

export function pitch () {
const { sourceDir, buildAdapter } = getOptions(this)
const query = qs.parse(this.resourceQuery.slice(1))

let loaders = this.loaders
loaders = loaders.filter(isPitcher)
if (query.type === 'template') {
const preLoaders = loaders.filter(isPreLoader)
const postLoaders = loaders.filter(isPostLoader)
let fileLoaderRequest = `file-loader?name=[path][name]${MINI_APP_FILES[buildAdapter].TEMPL}`
if (NODE_MODULES_REG.test(this.resourcePath)) {
const baseContext = path.join(process.cwd(), NODE_MODULES)
fileLoaderRequest += `&context=${baseContext}&outputPath=npm`
} else {
fileLoaderRequest += `&context=${sourceDir}`
}
const request = genRequest(this, [
...postLoaders,
fileLoaderRequest,
require.resolve('./miniTemplateLoader'),
...preLoaders
])
return `export * from ${request}`
}
const request = genRequest(this, loaders)
return `import mod from ${request}; export default mod; export * from ${request}`
}
138 changes: 130 additions & 8 deletions packages/taro-mini-runner/src/loaders/wxTransformerLoader.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,147 @@
import { getOptions } from 'loader-utils'
import * as qs from 'querystring'
import * as path from 'path'

import { getOptions, stringifyRequest } from 'loader-utils'
import wxTransformer from '@tarojs/transformer-wx'
import { transform, transformFromAst } from 'babel-core'
import * as t from 'babel-types'
import generate from 'better-babel-generator'

import {
REG_TYPESCRIPT,
PARSE_AST_TYPE,
NODE_MODULES_REG,
BUILD_TYPES
} from '../utils/constants'
import processAst from '../utils/processAst'
import { npmCodeHack, isEmptyObject } from '../utils'
import parseAst from '../utils/parseAst'

import { REG_TYPESCRIPT } from '../utils/constants'
const cannotRemoves = ['@tarojs/taro', 'react', 'nervjs']

const cachedResults = new Map()

export default function wxTransformerLoader (source) {
const { buildAdapter } = getOptions(this)
const {
babel: babelConfig,
alias,
buildAdapter,
designWidth,
deviceRatio,
sourceDir
} = getOptions(this)
const filePath = this.resourcePath
const { resourceQuery } = this
const rawQuery = resourceQuery.slice(1)
const inheritQuery = `&${rawQuery}`
const incomingQuery = qs.parse(rawQuery)
const isQuickApp = buildAdapter === BUILD_TYPES.QUICKAPP
try {
const stringifyRequestFn = r => stringifyRequest(this, r)
const miniType = (incomingQuery.parse ? incomingQuery.parse : this._module.miniType) || PARSE_AST_TYPE.NORMAL
const rootProps: { [key: string]: any } = {}
if (isQuickApp && miniType === PARSE_AST_TYPE.PAGE) {
// 如果是快应用,需要提前解析一次 ast,获取 config
const aheadTransformResult = wxTransformer({
code: source,
sourcePath: filePath,
sourceDir,
isRoot: miniType === PARSE_AST_TYPE.PAGE,
isTyped: REG_TYPESCRIPT.test(filePath),
adapter: buildAdapter
})
const res = parseAst(aheadTransformResult.ast, buildAdapter)
const appConfig = this._compiler.appConfig
if (res.configObj.enablePullDownRefresh || (appConfig.window && appConfig.window.enablePullDownRefresh)) {
rootProps.enablePullDownRefresh = true
}
if (appConfig.tabBar) {
rootProps.tabBar = appConfig.tabBar
}
rootProps.pagePath = filePath.replace(sourceDir, '').replace(path.extname(filePath), '')
if (res.hasEnablePageScroll) {
rootProps.enablePageScroll = true
}
}
const wxTransformerParams: any = {
code: source,
sourceDir: sourceDir,
sourcePath: filePath,
isTyped: REG_TYPESCRIPT.test(filePath),
adapter: buildAdapter,
isNormal: true
rootProps: isEmptyObject(rootProps) || rootProps
}
if (miniType === PARSE_AST_TYPE.ENTRY) {
wxTransformerParams.isApp = true
} else if (miniType === PARSE_AST_TYPE.PAGE) {
wxTransformerParams.isRoot = true
} else if (miniType === PARSE_AST_TYPE.NORMAL) {
wxTransformerParams.isNormal = true
}
let template, transCode
if (!incomingQuery.parse) {
const transformResult = wxTransformer(wxTransformerParams)
const ast = transformResult.ast
template = transformResult.template
const newAst = transformFromAst(ast, '', {
plugins: [
[require('babel-plugin-preval')],
[require('babel-plugin-danger-remove-unused-import'), { ignore: cannotRemoves }]
]
}).ast as t.File
const result = processAst({
ast: newAst,
buildAdapter,
type: miniType,
designWidth,
deviceRatio,
sourceFilePath: filePath,
sourceDir,
alias
})
const code = generate(result).code
const res = transform(code, babelConfig)
if (NODE_MODULES_REG.test(filePath) && res.code) {
res.code = npmCodeHack(filePath, res.code, buildAdapter)
}
transCode = res.code
cachedResults.set(filePath, {
template,
transCode
})
} else {
const cache = cachedResults.get(filePath)
template = cache.template
transCode = cache.transCode
}

let resultCode = ''
if (miniType === PARSE_AST_TYPE.ENTRY || miniType === PARSE_AST_TYPE.PAGE || miniType === PARSE_AST_TYPE.COMPONENT) {
if (incomingQuery.type === 'template') {
return this.callback(null, template)
}
if (incomingQuery.type === 'script') {
return this.callback(null, transCode)
}
if (template && template.length) {
const query = `?taro&type=template&parse=${miniType}${inheritQuery}`
const templateImport = `import { template } from ${stringifyRequestFn(filePath + query)};\n`
resultCode += templateImport
}
const scriptQuery = `?taro&type=script&parse=${miniType}${inheritQuery}`
const scriptRequest = stringifyRequestFn(filePath + scriptQuery)
const scriptImport = (
`import script from ${scriptRequest}\n` +
`export * from ${scriptRequest}` // support named exports
)
resultCode += scriptImport
return resultCode
}
const transformResult = wxTransformer(wxTransformerParams)
this.callback(null, transformResult.code, transformResult.ast)
return transformResult.code
return transCode
} catch (error) {
console.log(error)
this.emitError(error)
this.callback(null, source, null)
this.callback(null, source)
return source
}
}
51 changes: 51 additions & 0 deletions packages/taro-mini-runner/src/plugins/MiniLoaderPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import * as qs from 'querystring'

import * as RuleSet from 'webpack/lib/RuleSet'

import { BUILD_TYPES } from '../utils/constants'

const PLUGIN_NAME = 'MiniLoaderPlugin'
const NS = 'TARO'

interface IOptions {
sourceDir: string,
buildAdapter: BUILD_TYPES
}

export default class MiniLoaderPlugin {
options: IOptions
constructor (options) {
this.options = options
}

apply (compiler) {
const {
sourceDir,
buildAdapter
} = this.options
compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => {
const normalModuleLoader = compilation.hooks.normalModuleLoader
normalModuleLoader.tap(PLUGIN_NAME, loaderContext => {
loaderContext[NS] = true
})
})
const rawRules = compiler.options.module.rules
const { rules } = new RuleSet(rawRules)

const pitcher = {
loader: require.resolve('../loaders/pitcher'),
resourceQuery: query => {
const parsed = qs.parse(query.slice(1))
return parsed.taro != null
},
options: {
sourceDir,
buildAdapter
}
}
compiler.options.module.rules = [
pitcher,
...rules
]
}
}
Loading

0 comments on commit 7480ff7

Please sign in to comment.