Skip to content

Commit

Permalink
feat(cli): 拆分逻辑到 loader
Browse files Browse the repository at this point in the history
  • Loading branch information
luckyadam committed Dec 31, 2019
1 parent 338650a commit e5a9fca
Show file tree
Hide file tree
Showing 10 changed files with 1,151 additions and 59 deletions.
11 changes: 9 additions & 2 deletions packages/taro-cli/src/mini/webpack.ts
Expand Up @@ -4,6 +4,7 @@ import * as path from 'path'
import { IMiniAppBuildConfig } from '../util/types'
import { BUILD_TYPES } from '../util/constants'
import * as npmProcess from '../util/npm'
import { getBabelConfig } from '../util'

import {
setBuildData,
Expand All @@ -27,14 +28,20 @@ export async function build (appPath: string, { watch, adapter = BUILD_TYPES.WEA
}

async function buildWithWebpack ({ appPath }: { appPath: string }) {
const { entryFilePath, outputDir, sourceDir } = getBuildData()
const { entryFilePath, outputDir, sourceDir, buildAdapter, projectConfig, isProduction } = getBuildData()
console.log(entryFilePath, outputDir)
const miniRunner = await npmProcess.getNpmPkg('@tarojs/mini-runner', appPath)
const babelConfig = getBabelConfig(projectConfig!.plugins!.babel)
const miniRunnerOpts = {
entry: {
app: entryFilePath
},
outputDir
outputDir,
buildAdapter,
plugins: {
babel: babelConfig
},
isWatch: !isProduction
}
miniRunner(miniRunnerOpts)
}
30 changes: 21 additions & 9 deletions packages/taro-mini-runner/package.json
Expand Up @@ -31,23 +31,35 @@
"url": "https://github.com/NervJS/taro/issues"
},
"homepage": "https://github.com/NervJS/taro#readme",
"devDependencies": {
"@types/node": "^12.0.0",
"jest": "^24.8.0",
"npm-run-all": "^4.1.5",
"ts-jest": "^24.0.2",
"typescript": "^3.4.5"
},
"dependencies": {
"@types/lodash": "^4.14.126",
"@types/webpack": "^4.4.31",
"@tarojs/taro": "1.3.0-beta.2",
"@tarojs/transformer-wx": "1.3.0-beta.2",
"babel-core": "^6.26.3",
"babel-generator": "^6.26.1",
"babel-loader": "^8.0.6",
"babel-traverse": "^6.26.0",
"babel-types": "^6.26.0",
"chalk": "^2.4.2",
"fs-extra": "^8.0.1",
"loader-utils": "^1.2.3",
"lodash": "^4.17.11",
"ora": "^3.4.0",
"webpack": "^4.31.0",
"webpack-chain": "^6.0.0",
"webpack-format-messages": "^2.0.5"
},
"devDependencies": {
"@types/babel-core": "^6.25.6",
"@types/babel-generator": "^6.25.3",
"@types/babel-traverse": "^6.25.5",
"@types/babel-types": "^7.0.7",
"@types/loader-utils": "^1.1.3",
"@types/lodash": "^4.14.126",
"@types/node": "^12.0.0",
"@types/webpack": "^4.4.31",
"jest": "^24.8.0",
"npm-run-all": "^4.1.5",
"ts-jest": "^24.0.2",
"typescript": "^3.4.5"
}
}
28 changes: 27 additions & 1 deletion packages/taro-mini-runner/src/index.ts
@@ -1,19 +1,45 @@
import * as path from 'path'
import * as webpack from 'webpack'

import { IBuildConfig } from './utils/types'
import { printBuildError, bindProdLogger } from './utils/logHelper'
import MiniPlugin from './plugins/miniPlugin'

export default function build (config: IBuildConfig) {
const compilePlugins = config.plugins
const { babel } = compilePlugins
const webpackConfig = {
mode: config.isWatch ? 'development' : 'production',
entry: config.entry,
output: {
filename: '[name].js',
publicPath: '/',
path: config.outputDir,
},
module: {
rules: [
{
test: /\.(tsx?|jsx?)$/,
include: /src/,
exclude: /node_modules/,
use: [{
loader: path.resolve(__dirname, './loaders/fileParseLoader'),
options: {
babel
}
}, {
loader: path.resolve(__dirname, './loaders/wxTransformerLoader'),
options: {
buildAdapter: config.buildAdapter
}
}]
}
]
},
plugins: [
new MiniPlugin()
new MiniPlugin({
buildAdapter: config.buildAdapter
})
]
}

Expand Down
9 changes: 9 additions & 0 deletions packages/taro-mini-runner/src/loaders/fileParseLoader.ts
@@ -0,0 +1,9 @@
import { getOptions } from 'loader-utils'
import { transform } from 'babel-core'

export default function fileParseLoader (source, ast) {
const options = getOptions(this)
const babelConfig = options.babel
const res = transform(source, babelConfig)
return res.code
}
19 changes: 19 additions & 0 deletions packages/taro-mini-runner/src/loaders/wxTransformerLoader.ts
@@ -0,0 +1,19 @@
import { getOptions } from 'loader-utils'
import * as wxTransformer from '@tarojs/transformer-wx'

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

export default function wxTransformerLoader (source) {
const options = getOptions(this)
const filePath = this.resourcePath
const { buildAdapter } = options
const transformResult = wxTransformer({
code: source,
sourcePath: filePath,
isTyped: REG_TYPESCRIPT.test(filePath),
adapter: buildAdapter
})
this.callback(null, transformResult.code, transformResult.ast)
console.log('wxTransformerLoader')
return transformResult.code
}
138 changes: 130 additions & 8 deletions packages/taro-mini-runner/src/plugins/miniPlugin.ts
@@ -1,25 +1,42 @@
import * as path from 'path'
import * as fs from 'fs-extra'

import * as wxTransformer from '@tarojs/transformer-wx'
import * as webpack from 'webpack'
import { defaults } from 'lodash'
import * as t from 'babel-types'
import traverse from 'babel-traverse'
import { Config as IConfig } from '@tarojs/taro'

import { REG_TYPESCRIPT, BUILD_TYPES } from '../utils/constants'
import { traverseObjectNode, resolveScriptPath } from '../utils'

interface IMiniPluginOptions {
appEntry?: string
appEntry?: string,
buildAdapter: BUILD_TYPES
}

const PLUGIN_NAME = 'MiniPlugin'

export default class MiniPlugin {
options: IMiniPluginOptions
appEntry: string
pages: Set<string>
components: Set<string>
sourceDir: string

constructor (options = {}) {
this.options = defaults(options || {}, {

buildAdapter: BUILD_TYPES.WEAPP
})

this.pages = new Set()
this.components = new Set()
}

try = handler => async (arg, callback) => {
tryAsync = fn => async (arg, callback) => {
try {
await handler(arg)
await fn(arg)
callback()
} catch (err) {
callback(err)
Expand All @@ -28,8 +45,8 @@ export default class MiniPlugin {

apply (compiler: webpack.Compiler) {
compiler.hooks.run.tapAsync(
'MiniPlugin run',
this.try(async (compiler: webpack.Compiler) => {
PLUGIN_NAME,
this.tryAsync(async (compiler: webpack.Compiler) => {
await this.run(compiler)
})
)
Expand All @@ -50,11 +67,116 @@ export default class MiniPlugin {
return entry
}
const appEntryPath = getEntryPath(entry)
this.sourceDir = path.dirname(appEntryPath)
return appEntryPath
}

run (compiler) {
parseAst (
ast: t.File,
buildAdapter: BUILD_TYPES
): {
configObj: IConfig
} {
let configObj = {}
traverse(ast, {
ClassDeclaration (astPath) {
const node = astPath.node
let hasCreateData = false
if (node.superClass) {
astPath.traverse({
ClassMethod (astPath) {
if (astPath.get('key').isIdentifier({ name: '_createData' })) {
hasCreateData = true
}
}
})
if (hasCreateData) {
astPath.traverse({
ClassMethod (astPath) {
const node = astPath.node
if (node.kind === 'constructor') {
astPath.traverse({
ExpressionStatement (astPath) {
const node = astPath.node
if (node.expression &&
node.expression.type === 'AssignmentExpression' &&
node.expression.operator === '=') {
const left = node.expression.left
if (left.type === 'MemberExpression' &&
left.object.type === 'ThisExpression' &&
left.property.type === 'Identifier' &&
left.property.name === 'config') {
configObj = traverseObjectNode(node.expression.right, buildAdapter)
}
}
}
})
}
}
})
}
}
},
ClassProperty (astPath) {
const node = astPath.node
const keyName = node.key.name
if (keyName === 'config') {
configObj = traverseObjectNode(node, buildAdapter)
}
}
})

return {
configObj
}
}

getPages () {
const { buildAdapter } = this.options
const appEntry = this.appEntry
const code = fs.readFileSync(appEntry).toString()
const transformResult = wxTransformer({
code,
sourcePath: appEntry,
isTyped: REG_TYPESCRIPT.test(appEntry),
isApp: true,
adapter: buildAdapter
})
const { configObj } = this.parseAst(transformResult.ast, buildAdapter)
const appPages = configObj.pages
if (!appPages || appPages.length === 0) {
throw new Error('缺少页面')
}
this.pages = new Set([...appPages.map(item => resolveScriptPath(path.join(this.sourceDir, item)))])
}

getComponents (fileList: Set<string>, isRoot: boolean) {
const { buildAdapter } = this.options
fileList.forEach(file => {
const code = fs.readFileSync(file).toString()
const transformResult = wxTransformer({
code,
sourcePath: file,
isTyped: REG_TYPESCRIPT.test(file),
isRoot,
adapter: buildAdapter
})
let depComponents = transformResult.components
if (depComponents && depComponents.length) {
depComponents.forEach(item => {
const componentPath = resolveScriptPath(path.resolve(path.dirname(file), item.path))
if (fs.existsSync(componentPath)) {
this.components.add(componentPath)
this.getComponents(new Set([componentPath]), false)
}
})
}
})
}

run (compiler: webpack.Compiler) {
this.appEntry = this.getAppEntry(compiler)
console.log(this.appEntry)
this.getPages()
this.getComponents(this.pages, true)
}
}

0 comments on commit e5a9fca

Please sign in to comment.