Kernel
packages/taro-service/src/Kernel.ts
Kernel 是继承 EventEmitter 的一个类。
根据 taro-cli 中对命令行的解析并调用 kernel 可以知道最终是调用了 kernel 的 run 方法,下面我们重点看 run 方法。以 taro build --type weapp -- --watch 为例
- 【282-294】初始化参数
- 【295】初始化操作:项目配置、项目路径信息、项目插件;执行完成之后,所有的编译插件、平台编译插件都将挂载到
Kernel实例上,供后续编译程序使用。在装载完成后,将触发Kernel第一个钩子 -onReady。
- 【297】执行
onStart钩子 - 【301】对
taro [command] -h帮助命令行做输出。 eg:taro build -h/taro init -h
- 【313】命令行
type参数。根据平台类型获取对应编译配置 - 【322】执行钩子。也就是
kernel.run传入的钩子。build钩子
build 钩子
packages/taro-cli/src/presets/commands/build.ts
注册
- 调用
Kernel实例的run方法会调用Kernel实例的init方法 - 调用
initPresetsAndPlugins
- 调用
initPlugin - 调用
packages/taro-cli/src/presets/commands/build.ts中registerCommand完成注册。
执行
在 kernel.run最后一步调用 applyPlugins执行 build钩子,钩子被触发,最终执行
packages/taro-cli/src/presets/commands/build.ts
- 【52】检查项目相关配置,这里的配置对应的就是项目中的
config/index.js文件中的配置 - 【81】构建开始,触发
onBuildStart钩子。taro 官方文档 编译过程扩展 中有对其做介绍。
- 【82】触发对应平台的钩子。这里是
weapp。 - 【159】构建完成,触发
onBuildComplete钩子。
weapp 钩子
注册
packages/taro-weapp/src/index.ts
执行
在 packages/taro-cli/src/presets/commands/build.ts
- 【82】行执行了
ctx.applyPlugins, 调用weapp钩子。
- 【16】获取
Weapp实例
Weapp: packages/taro-weapp/src/program.ts
TaroPlatformBase: packages/taro-service/src/platform-plugin-base.ts
- 【17】执行实例的
start方法:packages/taro-service/src/platform-plugin-base.ts
【191】setup
- 【76】清空 dist 文件夹
- 【78-80】输出编译提示
- 【82】生成 project.config.json
【192】build 调用 mini-runner 开始编译
- 【147】
const runner = await this.getRunner(),加载miniRunner包
-
- 【115】获取当前项目内的
@tarojs/mini-runner
- 【148】准备
miniRunner配置参数 - 【152】运行
miniRunner包
mini-runner
可以看到实际上,最终就是运行了 webpack。
webpackConfig【40】 是 【37】通过 webpackChain.toConfig()
/mini-runner/src/index.ts
/mini-runner/src/webpack/build.conf.ts
/mini-runner/src/webpack/chain.ts
/mini-runner/src/plugins/BuildNativePlugin.ts
/mini-runner/src/plugins/MiniPlugin.ts
TaroMiniPlugin也就是小程序编译的核心部分
- 【326】compiler 钩子 - emit:输出 assets 到 output 目录之前执行。这个钩子不会被复制到子编译器。
- 【329】生成小程序相关文件
webpack相关
taro 使用 webpack4
可以看到编译vue => 小程序核心是使用 compiler.hooks + assets 实现生成小程序相关文件。
以下 demo 模拟了这一过程:
const webpack = require('webpack')
const path = require('path')
const config = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
}
const tryAsync = fn => async (arg, callback) => {
try {
await fn(arg)
callback()
} catch (err) {
callback(err)
}
}
async function generateMiniFiles(compilation) {
const fileConfigName = 'app.json'
const fileConfigStr = `
{
"pages": ["pages/index/index"],
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#fff",
"navigationBarTitleText": "WeChat",
"navigationBarTextStyle": "black"
},
"usingComponents": {}
}
`
compilation.assets[fileConfigName] = {
size: () => fileConfigStr.length,
source: () => fileConfigStr
}
}
const compiler = webpack(config)
compiler.hooks.emit.tapAsync(
'TaroMiniPlugin',
tryAsync(async compilation => {
await generateMiniFiles(compilation)
})
)
const watching = compiler.watch(
{
aggregateTimeout: 300,
poll: undefined
},
async (err, stats) => {
if (err || stats.hasErrors()) {
}
}
)
- 【40】生成 compilation 实例
- 【42】注册钩子 emit
- 【45】触发钩子,执行 generateMiniFiles
-
- 【21-33】定义 assets 文件和内容
- 【34】为 compilation.assets 添加内容
最终生成 app.json 文件并写入内容。