weboack的插件功能相对于loader来说能实现更强大的功能。
我们常见的copy-webpack-plugin、html-webpack-plugin等的插件都是在webpack执行中的某个生命周期中进行字符串操作或者文件操作。
插件实际上就是一个class对象它具有apply属性可以被webpack compiler调用。
主要的还是了解compiler对象相关的生命周期以及tap
, tapAsync
和 tapPromise
方法,然后根据业务需求在相应的生命周期中执行相应的操作。
class MyPlugin {
// webpack 插件是一个具有 apply 属性的 JavaScript 对象。
// apply 属性会被 webpack compiler 调用,并且 compiler 对象可在整个编译生命周期访问(其中还有各种hook提供调用)。
constructor(obj) {
console.log(obj) // 传进来的参数
}
apply(compiler) {
// 'shouldEmit', // 此时返回 true/false
// 'done', // 编译(compilation)完成
// 'additionalPass',
// 'beforeRun', // compiler.run() 执行之前,添加一个钩子
// 'run', // 开始读取 records 之前,钩入(hook into) compiler
// 'emit', // 生成资源到 output 目录之前
// 'assetEmitted',
// 'afterEmit', // 生成资源到 output 目录之后
// 'thisCompilation', // 触发 compilation 事件之前执行(查看下面的 compilation)
// 'compilation', // 编译(compilation)创建之后,执行插件
// 'normalModuleFactory', // NormalModuleFactory 创建之后,执行插件
// 'contextModuleFactory', // ContextModuleFactory 创建之后,执行插件
// 'beforeCompile', // 编译(compilation)参数创建之后,执行插件
// 'compile', // 一个新的编译(compilation)创建之后,钩入(hook into) compiler
// 'make',
// 'afterCompile',
// 'watchRun', // 监听模式下,一个新的编译(compilation)触发之后,执行一个插件,但是是在实际编译开始之前
// 'failed', // 编译(compilation)失败
// 'invalid', // 监听模式下,编译无效时
// 'watchClose', // 监听模式停止
// 'environment', // environment 准备好之后,执行插件
// 'afterEnvironment', // environment 安装完成之后,执行插件
// 'afterPlugins', // 设置完初始插件之后,执行插件。
// 'afterResolvers', // resolver 安装完成之后,执行插件
// 'entryOption', // 在 entry 配置项处理过之后,执行插件
console.log('插件被调用了。apply的钩子:', Object.keys(compiler.hooks))
compiler.hooks.run.tap('MyPlugin', params => {
console.log('以同步方式触及 compile 钩子。')
})
compiler.hooks.run.tapAsync('MyPlugin', (compiler, callback) => {
console.log('以异步方式触及 run 钩子。')
callback()
})
compiler.hooks.run.tapPromise('MyPlugin', compiler => {
return new Promise(resolve => setTimeout(resolve, 1000)).then(() => {
console.log('以具有延迟的异步方式触及 run 钩子')
})
})
}
}
module.exports = MyPlugin