在上一篇博客中分析了webpack打包以后的bundle文件,了解webpack是如何通过require
模拟commonjs标准加载模块的。下面探索webpack整体调用的流程,也就是如何通过shell输入webpack命令就可以实现整个编译、打包过程的。该系列博客的所有测试代码。
这篇博客只对整个流程及相关的事件流进行分析,不具体分析每个步骤中的具体实现。也就是,对于plugin和loader的具体分析请移步后面的博客。
整体调用流程
只有了解整体流程以后,才更容易找到你关心功能的源码。比如,如果你想知道plugin的工作原理,面对webpack的庞大源码,很难找到到底哪些js文件与plugin相关。于是我想先了解整体流程。
思路
捋顺流程的思路很简单,首先找到node_modules/.bin/webpack.cmd
查看webpack
命令干了什么:
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\webpack\bin\webpack.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\webpack\bin\webpack.js" %*
)
在安装node的情况下,会执行webpack/bin/wepack.js
,下面看看这个文件进行了哪些操作。
- 通过
[yargs](https://www.npmjs.com/package/yargs)
获得shell中的参数 - 把
webpack.config.js
中的参数和shell参数整合到options
对象上 - 调用
lib/webpack.js
开始编译和打包
依照这个思路继续查看lib/webpack.js
。不再一步一步仔细分析,下面直接展示分析后的结果。
流程
下图展示了webpack主要流程涉及的类及其调用关系。
lib/webpack.js
中返回一个compiler
对象,并调用了compiler.run()
lib/Compiler.js
中,run
方法触发了before-run
、run
两个事件,然后通过readRecords
读取文件,通过compile
进行打包,打包后触发before-compile
、compile
、make
等事件;compile
是主要流程,该方法中实例化了一个Compilation
类,并调用了其finish
及seal
方法,图中没有展开compile
方法具体代码lib/Compilation.js
中定义了finish
及seal
方法,还有一个重要方法addEntry
。这个方法通过调用其私有方法_addModuleChain
完成了两件事:根据模块的类型获取对应的模块工厂并创建模块;构建模块lib/Compiler.js
中没有显式调用addEntry
,而是触发make
事件,lib/DllEntryPlugin.js
为一个监听make
事件的插件,在回调函数中调用了addEntry
具体分析_addModuleChain
,其完成的第二件事构建模块又可以分为三部分:
- 调用
loader
处理模块之间的依赖 - 将
loader
处理后的文件通过[acorn](https://github.com/ternjs/acorn)
抽象成抽象语法树AST - 遍历AST,构建该模块的所有依赖
至此,我们知道了,plugin是通过事件监听的方式实现(DllEntryPlugin.js
就是一个插件);loader相关源码可以从_addModuleChain
为切入点看。
但是,我们多了几个疑惑:webpack到底有哪些事件(些plugin时候需要),这些事件流是如何控制的,每个事件都在什么阶段触发?
Tapable事件流
由第一部分分析可以知道,webpack整个流程是用事件进行控制的,也就是,不同的功能函数都封装到plugin中,plugin相当于listener,主打包流程中调用各种apply
方法(如:applyPluginsAsync
等)触发plugin
,apply
方法相当于emitter。该流程通过Tapable
类进行控制,上部分中 Compiler
和Compilation
两类都继承自Tapable
。那么,到底webpack中到底有哪些事件,不同的apply
方法具体行为有什么不一样呢?
webpack中的事件
webpack中的事件如下,这些事件出现的顺序固定,但不一定每次打包所有事件都触发:
类型 | 名字 | 事件名 |
---|---|---|
[C] | applyPluginsBailResult | entry-option |
[A] | applyPlugins | after-plugins |
[A] | applyPlugins | after-resolvers |
[A] | applyPlugins | environment |
[A] | applyPlugins | after-environment |
[D] | applyPluginsAsyncSeries | run |
[A] | applyPlugins | normal-module-factory |
[A] | applyPlugins | context-module-factory |
[A] | applyPlugins | compile |
[A] | applyPlugins | this-compilation |
[A] | applyPlugins | compilation |
[F] | applyPlu |