webpack构建的详细流程探底(3)

webpack函数中主要做了以下两个操作,

  • 实例化 Compiler 类。该类继承自 Tapable 类,Tapable 是一个基于发布订阅的插件架构。webpack 便是基于Tapable的发布订阅模式实现的整个流程。Tapable 中通过 plugins 注册插件名,以及对应的回调函数,通过 apply,applyPlugins,applyPluginsWater,applyPluginsAsync等函数以不同的方式调用注册在某一插件下的回调。
  • 通过WebpackOptionsApply 处理webpack compiler对象,通过 compiler.apply的方式调用了一些必备插件,在这些插件中,注册了一些 plugins,在后面的编译过程中,通过调用一些插件的方式,去处理一些流程。

第三步:调用compiler的run的过程(Compiler.js)

run()调用

run函数中主要触发了before-run事件,在before-run事件的回调函数中触发了run事件,run事件中调用了readRecord函数读取文件,并调用compile()函数进行编译。

compile()调用

compile函数中定义了编译的相关流程,主要有以下流程:

  • 创建编译参数
  • 触发 before-compile 事件,
  • 触发 compile 事件,开始编译
  • 创建 compilation对象,负责整个编译过程中具体细节的对象
  • 触发 make 事件,开始创建模块和分析其依赖
  • 根据入口配置的类型,决定是调用哪个plugin中的 make 事件的回调。如单入口的 entry,调用的是SingleEntryPlugin.js下 make 事件注册的回调函数,其他多入口同理。
  • 调用 compilation 对象的 addEntry 函数,创建模块以及依赖。
  • make 事件的回调函数中,通过seal 封装构建的结果
  • run 方法中定义的 onCompiled回调函数被调用,完成emit过程,将结果写入至目标文件

compile函数的定义

compile(callback) {
 // 创建编译参数,包括模块工厂和编译依赖参数数组
 const params = this.newCompilationParams();
 // 触发before-compile 事件,开始整个编译过程
 this.applyPluginsAsync("before-compile", params, err => {
 if(err) return callback(err);
 // 触发compile事件
 this.applyPlugins("compile", params);
 // 构建compilation对象,compilation对象负责具体的编译细节
 const compilation = this.newCompilation(params);
 // 触发make事件,对应的监听make事件的回调函数在不同的EntryPlugin中注册,比如singleEntryPlugin
 this.applyPluginsParallel("make", compilation, err => {
 if(err) return callback(err);
 compilation.finish();
 compilation.seal(err => {
 if(err) return callback(err);
 this.applyPluginsAsync("after-compile", compilation, err => {
 if(err) return callback(err);
 return callback(null, compilation);
 });
 });
 });
 });
}

【问题】make 事件触发后,有哪些插件中注册了make事件并得到了运行的机会呢?