自定义插件
- 根据项目的特殊需求,来自定义插件来满足项目定制
- 资源优化:自定义插件可以用于优化资源,例如压缩、混淆、合并或拆分文件,以减小文件大小,提高加载速度。
- 静态资源处理:静态资源需要处理,例如图片、字体等,你可以编写自定义插件来进行文件的复制、重命名、转换等操作
- 环境变量注入: 在不同的环境中(开发、生产等),你可能需要注入不同的环境变量或配置。自定义插件可以在构建过程中根据环境自动注入这些变量
- 自定义错误处理: 自定义插件可以帮助你在构建过程中捕获和处理错误,以便更好地定位问题并提供有用的错误信息
步骤:
- 1、Plugin: 开始打包,在某个时刻,帮助我们处理一些事情的机制
- 2、plugin要比loader稍微复杂⼀一些,在webpack的源码中,用plugin的机制 还是占有非常大的场景,可以说plugin是webpack的灵魂
- 3、plugin是一个类,里面包含一个apply函数,接受一个参数,compiler
- 4、可以在 compiler 对象实例上注册各种事件钩子函数,来影响 webpack 的所有构建流程,以便完成更多其他的构建任务
- 5、同步的钩子使用
tap, 如果是异步的事件钩子,那么可以使用tapPromise或者tapAsync来注册事件函数,tapPromise要求方法返回Promise以便处理异步,而tapAsync则是需要用callback来返回结果
编写插件步骤
1、暴露一个 js 函数
2、在函数的原型对象添加一个apply 方法,接受一个参数compiler
3、可以在 compiler 对象实例上注册各种事件钩子函数,来影响 webpack 的所有构建流程,以便完成更多其他的构建任务
在
apply方法中,你可以使用Webpack的钩子(hooks)来监听构建过程的特定事件。你可以在这些事件中执行你的插件逻辑。
class MyPlugin {
constructor(options) {
// 可以在这里接受一些插件的配置选项
this.options = options;
}
// 在这里编写插件逻辑
apply(compiler) {
//emit:表示生成output目录之前执行
//plugins类型
//同步 (同步没有回调callback)
compiler.hooks.compile.tap('MyPlugin', (compilation) => {
console.log('同步钩子')
})
//异步
//异步需要使用callback回调,来确保执行下一个异步事件
compiler.hooks.emit.tapAsync('MyPlugin', (compilation, callback) => {
// 处理自己所需要处理的事件
....
// 处理完成后的回调
callback()
})
}
}
module.exports = MyPlugin
compiler常见的事件名称
run
开始读取records前,一般用于插件开始启动的时候。用来处理在编译开始所需要执行一些事件。使用方法为:
javascript复制代码apply(compiler){
compiler.hooks.run.tag('插件名称',(compilation)=>{
console.log('编译开始');
})
}
watchRun
监听编译,当编译开始的时候会触发此方法,但是实际上此方法是在编译以前就执行了。使用方法:
javascript复制代码apply(compiler){
compiler.hooks.watchRun.tag('插件名称',(compilation)=>{
console.log('编译开始');
})
}
beforeRun
在compiler.run()方法前执行。
beforeCompile
在正式编译之前,执行此方法
compiler
在正式编译的时候,触发此方法。
afterCompiler
在编译执行完前触发此方法
emit
在编译完成后将资源生成到output配置的目录之前触发此方法。
afterEmit
在将编译后的资源生成到output配置的目录之后触发此方法。
done
编译完成后触发此方法
failed
编译失败后会触发此方法 以上为常用的钩子,如果想要看更多的事件名称,可以通过complier钩子查看
函数的注册
任何一个方法都需要通过一种注册方式,将方法绑定到我们需要用的地方。在webpack中对于plugins的事件注册。是通过三种方式来注册,分别是tap,tapAsync,tapPromise
tap
用来注册同步以及异步钩子。使用如下
apply(compiler){
compiler.hooks.watchRun.tag('插件名称',(compilation)=>{
console.log('编译开始');
})
}
tapAsync
注册异步的钩子,通过,回调函数告知异步方法执行完成,使用如下:
apply(compiler){
compiler.hooks.watchRun.tagAsync('插件名称',(compilation,callback)=>{
console.log('编译开始');
callback();
})
}
tapPromise
同tapAsync方法一样,注册异步的钩子,但是其通过返回一个Promise来告知执行完成。因此我们的方法有两种实现方式
- 返回Promise函数,通过
then来执行
apply(compiler){
compiler.hooks.watchRun.tapPromise('插件名称',(compilation)=>{
return new Promise(resolve=>{}).then(()=>{
console.log('异步编译开始');
})
})
}
- 通过
async来执行返回的数据
apply(compiler){
compiler.hooks.watchRun.tapPromise('插件名称',async (compilation)=>{
await new Promise(resolve=>{});
console.log('异步编译开始');
})
}
自定义插件例子
自定义错误处理
自定义错误处理插件可以处理Webpack构建过程中的各种类型的错误,从而提供更好的错误信息和可读性,以便更轻松地识别、定位和解决问题
-
通过配置选项
- 配置是否将错误日志记录到文件中
- 配置是否通过通知系统通知错误
-
将错误信息写入到错误文件中
-
使用
node-notifier库 在Node.js环境中发送操作系统通知 错误信息- 通常在开发过程中用于发送构建完成、错误、警告等通知
Webpack构建过程可能出现的问题:
- 语法错误
- 模块依赖错误
- 文件加载错误
- 代码拆分失败
- 环境变量配置错误
- 插件配置错误
const fs = require('fs');
const path = require('path');
const notifier = require('node-notifier');
class CustomErrorPlugin {
constructor(options) {
this.options = {
logToFile: false,
notifyOnErrors: true,
// ...其他配置选项
...options,
};
// 错误日志记录
this.errorLogFilePath = path.resolve(__dirname, 'error-log.txt');
}
apply(compiler) {
compiler.hooks.done.tap('CustomErrorPlugin', (stats) => {
const errors = stats.compilation.errors;
const warnings = stats.compilation.warnings;
if (errors.length > 0) {
this.handleErrors(errors);
}
if (warnings.length > 0) {
this.handleWarnings(warnings);
}
});
}
handleErrors(errors) {
console.log('\nCustom Error Plugin: Build failed with the following errors:\n');
errors.forEach((error, index) => {
console.log(`Error #${index + 1}:`);
console.log(error.message);
console.log('\n');
if (this.options.logToFile) {
this.logErrorToFile(error.message);
}
});
if (this.options.notifyOnErrors) {
this.notifyErrors();
}
}
handleWarnings(warnings) {
console.log('\nCustom Error Plugin: Build completed with the following warnings:\n');
warnings.forEach((warning, index) => {
console.log(`Warning #${index + 1}:`);
console.log(warning.message);
console.log('\n');
});
}
logErrorToFile(errorMessage) {
// 追加到文件中。如果文件不存在,则会创建一个新文件
fs.appendFileSync(this.errorLogFilePath, `${errorMessage}\n\n`);
}
notifyErrors() {
notifier.notify({
title: 'Build Failed',
message: 'There are errors in the build process.',
});
}
}
module.exports = CustomErrorPlugin;
- 错误日志记录: 如果配置了
logToFile为true,错误信息将会被记录到文件error-log.txt中。 - 错误通知: 如果配置了
notifyOnErrors为true,将会使用node-notifier库在操作系统通知中心发送错误通知。