在 Webpack 插件开发中,apply 方法是一个关键部分。它是 Webpack 插件的入口点,Webpack 会在初始化时调用每个插件的 apply 方法,并传入一个 compiler 对象。compiler 对象是 Webpack 的核心实例,它包含了 Webpack 的完整配置、构建流程以及各种生命周期钩子(Hooks)。
compiler 对象的作用
compiler 对象是 Webpack 的核心实例,负责整个构建过程的调度和管理。通过 compiler,你可以访问 Webpack 的配置、注册钩子、监听构建事件,并在适当的时机执行自定义逻辑。
compiler 的主要属性和方法
1. compiler.options
- 这是 Webpack 的完整配置对象,包含了你在
webpack.config.js中定义的所有配置项。 - 你可以通过
compiler.options访问或修改 Webpack 的配置。
javascript
复制
apply(compiler) {
console.log(compiler.options); // 输出 Webpack 配置
}
2. compiler.hooks
compiler.hooks是 Webpack 提供的生命周期钩子集合。通过它,你可以在构建过程的不同阶段插入自定义逻辑。- 每个钩子都是一个
Tapable实例,支持通过.tap方法注册回调函数。
常用钩子:
entryOption: 在 Webpack 处理入口配置时触发。beforeRun: 在 Webpack 开始执行构建之前触发。run: 在 Webpack 开始构建时触发。compile: 在 Webpack 开始编译之前触发。emit: 在生成资源并输出到目录之前触发。done: 在构建完成后触发。
示例:
javascript
复制
apply(compiler) {
compiler.hooks.beforeRun.tap('MyPlugin', () => {
console.log('Webpack is about to start building...');
});
compiler.hooks.done.tap('MyPlugin', (stats) => {
console.log('Build completed!');
});
}
3. compiler.inputFileSystem 和 compiler.outputFileSystem
- 这两个属性是 Webpack 使用的文件系统实例,分别用于读取输入文件和写入输出文件。
- 默认情况下,Webpack 使用 Node.js 的
fs模块,但你也可以替换为自定义的文件系统(比如内存文件系统)。
示例:
javascript
复制
apply(compiler) {
const inputFileSystem = compiler.inputFileSystem;
const outputFileSystem = compiler.outputFileSystem;
// 读取文件
inputFileSystem.readFile('path/to/file', (err, data) => {
if (err) throw err;
console.log(data.toString());
});
// 写入文件
outputFileSystem.writeFile('path/to/output', 'Hello World', (err) => {
if (err) throw err;
console.log('File written!');
});
}
4. compiler.context
- 这是 Webpack 的上下文路径,通常是项目的根目录。
- 你可以通过
compiler.context获取项目的根目录路径。
示例:
javascript
复制
apply(compiler) {
console.log('Project root:', compiler.context);
}
5. compiler.webpack
- 这是 Webpack 的 API 对象,包含了 Webpack 的核心功能和方法。
- 你可以通过它访问 Webpack 的内部模块或工具函数。
示例:
javascript
复制
apply(compiler) {
const { sources } = compiler.webpack;
console.log(sources); // 输出 Webpack 的 sources 模块
}
6. compiler.run 和 compiler.watch
compiler.run用于启动一次构建。compiler.watch用于启动监听模式,当文件变化时自动重新构建。
示例:
javascript
复制
apply(compiler) {
// 手动启动构建
compiler.run((err, stats) => {
if (err) throw err;
console.log('Build completed!');
});
// 启动监听模式
compiler.watch({}, (err, stats) => {
if (err) throw err;
console.log('Rebuild completed!');
});
}
compiler 的生命周期钩子(Hooks)
Webpack 的构建过程分为多个阶段,每个阶段都有对应的钩子。以下是一些常用的钩子及其触发时机:
| 钩子名称 | 触发时机 |
|---|---|
entryOption | 在处理入口配置时触发。 |
beforeRun | 在 Webpack 开始执行构建之前触发。 |
run | 在 Webpack 开始构建时触发。 |
compile | 在 Webpack 开始编译之前触发。 |
thisCompilation | 在创建新的 compilation 对象时触发。 |
compilation | 在 compilation 对象创建完成后触发。 |
emit | 在生成资源并输出到目录之前触发。 |
afterEmit | 在资源输出到目录之后触发。 |
done | 在构建完成后触发。 |
failed | 在构建失败时触发。 |
示例:监听 emit 钩子
emit 钩子是一个常用的钩子,它在 Webpack 生成资源并输出到目录之前触发。你可以在这个阶段修改输出内容。
javascript
复制
class EmitPlugin {
apply(compiler) {
compiler.hooks.emit.tap('EmitPlugin', (compilation) => {
// 遍历所有生成的文件
for (const file of Object.keys(compilation.assets)) {
console.log(`Generated file: ${file}`);
}
// 添加一个自定义文件
compilation.assets['custom-file.txt'] = {
source: () => 'This is a custom file!',
size: () => 21,
};
});
}
}
module.exports = EmitPlugin;
总结
compiler是 Webpack 的核心实例,包含了 Webpack 的配置、构建流程和生命周期钩子。- 通过
compiler.hooks,你可以在构建过程的不同阶段插入自定义逻辑。 compiler还提供了文件系统、上下文路径等实用工具,方便你扩展 Webpack 的功能。