webpack 4 源码主流程分析(三):编译前的准备
Compiler 简述
webpack/lib/Compiler.js
该文件是webpack
的核心,Compiler
类定义了整个构建的流程;new Compiler
执行constructor
,首先扩展了Tapable
,在constructor
里定义了一堆钩子done,beforeRun,run,emit
等等;- 然后注册了
this._pluginCompat.tap("Compiler")
,这个用来兼容之前的老版webpack
的plugin
的钩子,触发时机在tapable/lib/Tapable.js
里调用plugin
的时候; - 该
Compiler
类下的的run
即为整个打包的主流程函数;
封装 FS
继续执行 webpack.js
,执行:
1 | new NodeEnvironmentPlugin({ |
该类主要对文件系统做了一些封装,包括输入,输出,缓存,监听
等等,这些扩展后的方法全部挂载在 compiler
对象下。
执行 plugins
项目配置的 plugins
然后对自己 config
文件里的 plugins
进行了注册:
1 | if (options.plugins && Array.isArray(options.plugins)) { |
在这里,会把 compiler
实例传进去供 plugin
使用,compiler
包含整个构建流程的全部钩子,通过它可以把控整个 webpack
构建周期。其中 compiler
的部分钩子会传入 compilation
对象参数,该对象又包含资源构建的很多钩子。
掌握流程里各对象(如 compiler
,compilation
)的事件钩子触发的时机,就是掌握如何写一个插件的关键。如何写一个 webpack 插件?
接着触发了 compiler
的 hooks
: environment,afterEnvironment
,然后执行:
1 | compiler.options = new WebpackOptionsApply().process(options, compiler); |
项目默认的 plugins
该 WebpackOptionsApply
类的 process
除了把配置里的一些属性添加到 compiler
对象下,更主要的是根据 options
的配置不同,注册激活一些默认自带的插件和 resolverFactory.hooks
,大部分插件的作用是往 compiler.hooks:compilation,thisCompilation
里注册一些事件(此时该钩子已经获取到 normalModuleFactory
等参数),如:
1 | new JavascriptModulesPlugin().apply(compiler); //给normalModuleFactory的js模块提供Parser、JavascriptGenerator对象 ,并给seal阶段的template提供renderManifest数组(包含render方法) |
1 | new EntryOptionPlugin().apply(compiler); |
插件处理完毕后,触发 compiler.hooks
: afterPlugins
。
注册 resolverFactory.hooks
1 | compiler.resolverFactory.hooks.resolveOptions.for('normal').tap('WebpackOptionsApply', (resolveOptions) => { |
然后注册 compiler.resolverFactory.hooks
: resolveOptions for (normal/context/loader)
,目的是为 Factory.createResolver
提供默认的参数对象(含有相关的 resolve
项目配置项)。
注册完成后,触发 compiler.hooks
: afterResolvers
,到此 compiler
初始化完毕。
回到 cli.js
回到cli.js
,处理配置项 progress
和 infoVerbosity
,然后判断 options
里是否有 watch
,有则走 compiler.watch
,无则走 compiler.run
,这里我们走compiler.run
,进入 webpack
核心构建流程!
本章小结
- 实例化了
Compiler
,它扩展于Tapable
,是webapck
的核心; - 封装了输入输出等方法
FS
,然后执行了plugins
(compiler
作为参数),包括项目配置的和项目默认; - 注册
resolverFactory.hooks
用于Factory.createResolver
方法提供参数对象; - 最后根据配置是否有
watch
来决定程序走向。