webpack 基础流程
核心构建流程
初始化
- 初始化参数:从配置文件、配置对象、
shell
脚本中读取配置参数,与默认配置合并出最终配置 - 创建编译器对象:基于最终配置创建
compiler
对象 - 初始化编译环境:注入内置插件、注册各种模块工厂、初始化
RuleSet
集合、加载配置的插件等 - 开始编译:执行
compiler
对象的run
方法 - 循环遍历入口:根据配置的
entry
找出所有的入口文件,调用compilition.addEntry
将入口文件转换为dependence
对象,也就是依赖关系。
开始构建
make
执行编译:根据entry
对应的dependence
创建module
对象,然后调用loader
将模块转译为标准的js
,再调用js
解释器将内容转换为ast
对象,从中找出该模块的依赖模块,然后在递归编译直到所有依赖文件都经过此步骤处理- 完成模块编译:上一步递归编译处理得到他们之间的依赖关系,构造出一个依赖关系图
打包输出
- 输出资源(
seal
):根据入口和模块之间的依赖关系,组合成包含多个模块的Chunk
,再把每个Chunk
转换成单独的文件加入到输出列表,这里是可以修改输出内容的最后一步 - 写入文件到磁盘:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件写入到文件系统
以上就是从一个宏观的角度看一次构建的主流程和相关步骤,下面对名词做个简单的介绍
- entry
:编译的入口,起点
Compiler
:编译管理器,webpack
启动之后会创建compiler
对象,这个对象全局只存在一个,一直到整个构建任务结束为止。Compilation
:单次编辑过程的管理器,比如:watch=true
时,每次的文件内容变更触发重新编译时。都会创建一个新的这个对象Depenence
:依赖对象,webpack
基于这个寻找依赖关系,转换关系图Module
:一切接模块,所有内容的操作都是基于模块的,是webpack
的基本单位Chunk
:由module
打包组成的产物Loader
:资源转换器,因为webpack
只认识js
模块Plugin
:在打包过程中的扩展功能,让打包流程能做更多事情。
流程详解
初始化阶段
- 把
process.args
和webpack.config.js
合并成为用户配置 - 调用
validateSchema
对配置经行校验 getNormalizedWebpackOptions
+applyWebpackOptionsBaseDefaults
合并出最终配置- 创建
compiler
对象 - 遍历用户的
plugins
集合数组,执行插件的apply
方法来执行插件 - 调用
new WebpackOptionsApply().process
方法,加载各种内置插件
主要是 WebpackOptionsApply
类,会自动执行 webpack
内置的各种插件,并会在初始化阶段根据配置内容动态注入对应的插件:
- 注入
EntryOptionPlugin
插件,处理entry
配置 - 根据
devtool
值判断用什么插件处理sourcemap
,可选的插件有:EvalSourceMapDevToolPlugin、SourceMapDevToolPlugin、EvalDevToolModulePlugin
- 注入
RuntimePlugin
,根据代码内容动态注入webpack
运行时
这样 compiler
实例就被创建出来了,环境参数也设置好了,接着就是调用 compiler.compile
函数
js
// 取自 webpack/lib/compiler.js
compile(callback) {
const params = this.newCompilationParams();
this.hooks.beforeCompile.callAsync(params, err => {
// ...
const compilation = this.newCompilation(params);
this.hooks.make.callAsync(compilation, err => {
// ...
this.hooks.finishMake.callAsync(compilation, err => {
// ...
process.nextTick(() => {
compilation.finish(err => {
compilation.seal(err => {...});
});
});
});
});
});
}