webpack-cli 如何调用 webpack
- 在 demo 目录运行 webpack-cli,会自动把 src/index.js 打包为 dist/main.js
- 显然会调用 webpack 来打包,是如何做到的
打开webpack-cli源码
packages/webpack-cli/bin/cli.js
packages/webpack-cli/lib/bootstrap.js
packages/webpack-cli/lib/webpack-cli.js 构造函数中没东西
packages/webpack-cli/lib/webpack-cli.js run
packages/webpack-cli/lib/webpack-cli.js createCompiler
结论
webpack-cli通过调用webpack()这个函数创建了一个编译器
webpack = require(‘webpack’)
compiler = webpack(options, callback)
webpack-cli就这样调用了webpack
webpack 如何分析 index.js
打开webpack项目
package.json
lib/index.js
lib/webpack.js webpack
lib/webpack.js createCompiler
/lib/Compiler 构造函数,都是初始化 go back
hooks.xxx.call()
Tapable
这是 webpack 团队为了写 webpack 而写的一个事件/钩子库
- 用法
- 定义一个事件/钩子
this.hooks.eventName = new SyncHook(["arg1", "arg2"]);
- 监听一个事件/钩子
this.hooks.eventName.tap('监听理由', fn)
- 触发一个事件/钩子
this.hooks.eventName.call('arg1', 'arg2')
webpack的流程
lib/webpack.js createCompiler
lib/webpack.js
lib/Compiler.js run
lib/Compiler.js run run
lib/Compiler.js onCompiled
目前看来大概有这些执行过程
- environment
- afterEnvironment
- initialize
- beforeRun
- run
- ——this.readRecords——
- ——this.compile(x)——
- —-onCompiled——
- shouldEmit
- ——nextTick——
- ——this.emitAssets——
- ——this.emitRecords——
- done
看——this.compile()——
/lib/compile
这一部分的过程
——this.compile——
beforeCompile
compile
——this.newCompilation(x)——
make
finishMake
——nextTick——
——compilation.finish(x)——
——compilation.seal(x)——
afterCompile
看this.newCompilation()
/lib/Compiler
/lib/Compilation 都是初始化 go back
看compilation.finish(x)
/lib/Compilation.js finish
过程
——compilation.finish(x)——
finishModules
看compilation.seal(x)
/lib/Compilation.js seal
这一部分的过程
——compilation.seal(x)——
seal
afterOptimizeDependencies
beforeChunks
——this.addChunk——
——buildChunkGraph——
afterChunks
optimize
optimizeModules
optimizeChunks
optimizeTree
optimizeChunkModules
总结webpack的打包流程
- environment
- afterEnvironment
- initialize
- beforeRun
- run
- ——this.readRecords——
- ——this.compile(x)——
- beforeCompile
- compile
- ——this.newCompilation(x)——
- make
- finishMake
- ——nextTick——
- ——compilation.finish(x)——
- finishModules
- ——compilation.seal(x)——
- seal
- afterOptimizeDependencies
- beforeChunks
- ——this.addChunk——
- ——buildChunkGraph——
- afterChunks
- optimize
- optimizeModules
- optimizeChunks
- optimizeTree
- optimizeChunkModules
- afterCompile
- ——compilation.finish(x)——
- ——nextTick——
- finishMake
- beforeCompile
- —-onCompiled——
- shouldEmit
- ——nextTick——
- ——this.emitAssets——
- ——this.emitRecords——
- done
Webpack 是如何处理 Entry
读取 index.js 并分析和收集依赖是在哪个阶段?
- 用排除法可以知道,肯定不是 env 和 emit,肯定在 beforeCompile 和 afterCompile 之间
- 最有可能是在 make - finishMake 阶段
- C 语言中make 是编译时必然会用到的工具
/lib/Compiler.js
全局搜索 make.tap
/lib/EntryPlugin.js
/lib/Compilation.js
/lib/NormalModuleFactory.js
搜索factorize.tap
搜索createModule.tap
/lib/sharing/ConsumeSharedPlugin.js
代码到factorizeQueue就没有后续代码了
factory.create是什么
- factory从factorizeModule(options)的options.factory来的
- options.factory从moduleFactory来的
- moduleFactory是用this.dependencyFactories.get(Dep)得到的
- this.dependencyFactories.get(Dep)是normalModuleFactory简称
- 结论 factory就是nmf,所以factory.create 就是 nmf.create
nmf.create做了什么
- NormalModuleFactory.js中
- beforeResolve.call 和 factorize.call
- 搜索对应tap ,factorize.tap中
- 触发resolve,而resolve主要手机loaders
- 然后触发createModule,得到createdModule
- 也就是nmf.create得到了一个module对象
- 等价于factory.create得到了一个module对象
- 综上,从factorizeModule来到factory.create的
- 回到factorizeMOdule,发现后续操作是addModule和buildModule
addModule做了什么
- 把module添加到compilation.modules里
- 而且还通过检查id防止重复添加
buildModule做了什么
- 调用module.build()
- NormaModule.js中发现runLoaders
- 然后来到processResult(),发现了_source = … 和 _ast = null
- 这一步就是把_source 变成 _ast
- doBuild回调,发现this.parser.parse()
- parse就是把code变成ast
- 后面就是parser来自acorn库