webpack流程小解
这篇主要小小的介绍webpack的强大的强大的强大的强大的编译过程。
前言
在介绍正式编译过程之前,首先明确webpack是一个事件流驱动的组件,通过事件注册和事件触发完成整个编译过程。其中事件流的实现主要是依赖Tapable插件,Tapable的实现也很简单。
//函数只有一个是参数,私有属性_plugins,用于记录注册的事件,事件名:回调函数
function Tapable() {
this._plugins = {};
}
//事件注册 往_plugins中注册事件
Tapable.prototype.plugin = function plugin(name, fn) {
if(Array.isArray(name)) {
name.forEach(function(name) {
this.plugin(name, fn);
}, this);
return;
}
if(!this._plugins[name]) this._plugins[name] = [fn];
else this._plugins[name].push(fn);
};
//其中一个事件触发的函数
Tapable.prototype.applyPlugins = function applyPlugins(name) {
if(!this._plugins[name]) return;
var args = Array.prototype.slice.call(arguments, 1);
var plugins = this._plugins[name];
for(var i = 0; i < plugins.length; i++)
plugins[i].apply(this, args);
};
然后weback通过组合继承的方式继承Tapable
var Tapable = require("tapable");
function Compiler() {
Tapable.call(this);
...
}
Compiler.prototype = Object.create(Tapable.prototype);
Compiler.prototype.constructor = Compiler;
知道事件流机制之后,再来理解webpack的编译过程,大致如下图
流程详解
官方文档:
complier钩子:https://www.webpackjs.com/api/compiler-hooks/
compilation钩子:https://www.webpackjs.com/api/compilation-hooks/
0. 部分名词解释
- loader:能转换各类资源,并处理成对应模块的加载器。loader 间可以串行使用。
- chunk:code splitting 后的产物,也就是按需加载的分块,装载了不同的 module。
- Complier: webpack的完整编译过程,通过Complier.run方法开始执行编译,然后调用Complier.compile创建出compilation对象。
- Compilation:webpack的每次编译过程,由Complier.compile创建,多个入口会生成多个Compilation,其中包含了当前编译过程的入口和出口以及依赖等等。
1. shell 与 config 解析
这一步使用了nodejs的library中的optimist工具
var optimist = require("optimist");
optimist
.boolean("json").alias("json", "j").describe("json")
.boolean("colors").alias("colors", "c").describe("colors")
.boolean("watch").alias("watch", "w").describe("watch")
...
==》
// webpack --hot -w
{
hot: true,
profile: false,
watch: true,
...
}
2. config合并于插件加载
将配置文件中的各项配置拷贝到options对象中,并根据启动命令中的args加载对应的插件
3. 编译与构建流程
开始初始化webpack,生成complier对象,通过complier的run方法开始进行真正的编译过程,以下是编译过程中重要的事件节点
compile
开始编译make
从入口点分析模块及其依赖的模块,创建这些模块对象build-module
构建模块after-compile
完成构建seal
封装构建结果emit
把各个chunk输出到结果文件after-emit
完成输出
a). 生成Compliation对象
Compliation两个作用,一是负责整个打包过程,包含了每个构建环节及输出环节所对应的方法。二是该对象内部存放着所有module,chunk,生成的asset以及用来生成最后打包文件的template信息。
b)编译和构建主流程
先找到入口js文件,开始构建模块
- 调用各loader处理模块
- 解析经loader处理后的源文件生成抽象语法树AST
- 遍历AST,递归处理依赖的module,重复上述编译过程
4. 打包输出
所有模块build完成之后,webpack会监听seal事件调用各插件对构建后进行封装,逐次对每个module和chunk进行整理,生成编译后的源码,合并,拆分,生成hash