Compiler

Webpack 的 Compiler 模块是 主引擎,它通过配置参数传递的所有选项,创建出一个 compilation 实例。

Webpack 使用它来实例化 compiler,然后调用 run 方法。下面是一个可以使用 Compiler 简单示例。

代码示例:

// 可以从 webpack package 中 import 导入
import { Compiler } from 'webpack';
// 创建一个新的 compiler 实例
const compiler = new Compiler();
// 填充所有必备的 options 选项
compiler.options = {
// ...
};
// 创建一个插件
class LogPlugin {
apply(compiler) {
compiler.plugin('should-emit', (compilation) => {
console.log('should I emit?');
return true;
});
}
}
// 将 compiler 应用到插件中
new LogPlugin().apply(compiler);
/* 添加其他支持插件 */
// 运行结束后执行回调
const callback = (err, stats) => {
console.log('Compiler 已经完成执行');
// 显示 stats
};
// compiler 的 run 调用,并传入 callback
compiler.run(callback);

Compiler 也是我们所说的 Tapable 实例。通过这种实现机制,我们可以理解为,它混合(mix)了 Tapable 类,来使实例也具备 注册调用插件 功能。大多数面向用户的插件,要首先在 Compiler 上注册。

Compiler 运行机制可以被提取为以下要点:

  • 通常有一个 Compiler 的主实例。可以创建子 compilers 来委托特定任务
  • 创建 compiler 的多数复杂度,在于为它填充所有相关的 options 选项
  • Webpack 通过 WebpackOptionsDefaulterWebpackOptionsApply,来专门为 Compiler 提供所需的所有 初始数据
  • Compiler 是一个执行最简功能,来保证生命周期运行的函数。它把所有的 加载(loading) / 打包(bundling) / 写入(writing) 工作委托给各种插件
  • new LogPlugin(args).apply(compiler) 将插件注册到 Compiler 生命周期中的任何特定钩子事件
  • Compiler 暴露 run 方法,它启动了 Webpack 所有编译工作。在执行完成后,会调用传递给它的 callback 函数。记录 statserrors 的所有末端工作,都在此回调函数中完成

多编译配置

MultiCompiler 模块允许 Webpack 在单个 compiler 中运行多个配置。如果 Webpack 的 Node.js API 中的 options 参数,是一个由 options 构成的数组,则 Webpack 会对其应用单个 compiler,并在所有 compiler 执行结束时,调用 callback 方法。

代码示例:

const Webpack = require('webpack');
const config1 = {
entry: './index1.js',
output: {
filename: 'bundle1.js',
},
};
const config2 = {
entry: './index2.js',
output: {
filename: 'bundle2.js',
},
};
webpack([config1, config2], (err, stats) => {
process.stdout.write(stats.toString() + '\n');
});

插件开发

开发插件首先要知道 compilercompilation 对象是做什么的。

Compiler 对象包含了当前运行 Webpack 的配置,包括 entryoutputloader 等配置,这个对象在启动 Webpack 时被实例化,而且是全局唯一的。Plugin 可以通过该对象获取到 Webpack 的配置信息进行处理。

如果看完这段话,你还是没理解 compiler 是做啥的,不要怕。运行 npm run build,把 compiler 的全部信息输出到控制台上 console.log(compiler)

Compiler对象实例

Compiler 源码精简版代码解析

生命周期钩子

列出 Compiler 暴露的所有事件钩子。

事件名称内容说明参数类型
entry-option--basicResult
after-plugins设置完一组初始化插件之后compilersync 同步
after-resolvers设置完 resolvers 之后compilersync 同步
environment--sync 同步
after-environment环境设置完成-sync 同步
before-runcompiler.run() 开始compilerasync 异步
run在读取记录之前compilerasync 异步
watch-run在开始编译之前,watch 之后compilerasync 异步
normal-module-factory创建出一个 NormalModuleFactory 之后normalModuleFactorysync 同步
context-module-factory创建出一个 ContextModuleFactory 之后contextModuleFactorysync 同步
before-compilecompilation 的参数已创建compilationParamsasync 异步
compile在创建新 compilation 之前compilationParamssync 同步
this-compilation在触发 compilation 事件之前compilationsync 同步
compilationcompilation 创建完成compilationsync 同步
make-compilationparallel 平行
after-compile-compilationasync 异步
should-emit此时可以返回 true/falsecompilationbailResult
need-additional-pass--bailResult
emit在生成资源并输出到目录之前compilationasync 异步
after-emit在生成资源并输出到目录之后compilationasync 异步
done完成编译statssync 同步
failed编译失败errorsync 同步
invalid在无效的 watch 编译之后fileNamechangeTimesync 同步
watch-close在停止 watch 编译之后-sync 同步

代码示例:

compiler.plugin('emit', function (compilation, callback) {
// 执行一些异步...
// 异步的 `emit` 事件处理函数的
setTimeout(function () {
console.log('异步运行完成...');
callback();
}, 1000);
});

参考资料