持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第3天,点击查看活动详情
Webpack 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。本文主要写了自定义Plugin的实现过程。
Webpack 系列专栏地址 进入
本文demo地址查看
自定义 Plugin(插件)
开发自定义 Plugin
插件之前,先回想一下 Plugin
是怎么使用的。
new htmlWebpackPlugin({
template: './public/index.html',
filename: 'index.html',
chunks: ['index'],
}),
分析代码不难得知,Plugin
本身应该是一个 类
,参数通过类的构造函数传递。
打包流程
执行 npx webapck
命令后的打包流程大概是是下面这样:
- 合并webpack配置
- 启动构建任务
- 执行配置项
loader
plugin
...
那么插件是如何注册进去的?又是如何区分打包顺序/执行时机的?(例如CleanWebpackPlugin
是打包前执行清理目录,而htmlWebpackPlugin
是资源目录输出到dist目录之前执行),这些问题都将在下面解决。
插件基本结构
插件开发的要点:
- 插件是个类
- 必须内置一个
apply
函数,其中apply
的compiler
参数是实例化的webpack对象,其中包含了配置等信息 - compiler 钩子,是webpack打包流程的生命周期文档
- 同步钩子用
tap
注册,异步钩子用tapAsync
注册
新建 myPlugins/my-webpack-plugin.js,根据上面的要点可以搭建出来一个插件的基本结构
class MyWebpackPlugin {
constructor(options) {
console.log('options----', options)
}
apply(compiler) {
console.log('compiler----', compiler)
}
}
module.exports = MyWebpackPlugin
钩子
相关的钩子www.webpackjs.com/api/compile…
访问钩子的格式:
compiler.hooks.someHook.tap(...)
emit
钩子的执行时机是生成资源到 output 目录之前,也就是可加工bundle文件的最后一步
给 emit
钩子注册一个事件:
class MyWebpackPlugin {
constructor(options) {
console.log('options----', options)
}
apply(compiler) {
console.log('compiler----', compiler)
compiler.hooks.emit.tapAsync('myWebpackPluginEmit', (compilation, cb) => {
console.log('compilation---------', compilation.assets)
cb()
})
}
}
module.exports = MyWebpackPlugin
- 事件名可以为任意值,最好有语义,此处为
myWebpackPluginEmit
- 事件主体的函数有一个参数
compilation
,以及一个cb
回调函数参数(异步的钩子才需要)。 - 事件主体执行完,必须执行一次
cb
回调函数(异步的钩子才需要)。 compilation
是在当前钩子中 原材料被加工后的样子
执行打包命令,可以看到 compilation.assets
的结构如下:
在 emit
钩子事件中,给bundle文件添加进去一个资源文件 1.txt
compiler.hooks.emit.tapAsync('myWebpackPluginEmit', (compilation, cb) => {
// 添加 1.txt 文件
const content = '我是在钩子中添加的文件'
compilation.assets['1.txt'] = {
source() {
return content
},
size() {
return content.length
},
}
console.log('compilation---------', compilation.assets)
cb()
})
再次执行打包命令,查看bundle文件,多出了一个 1.txt 文件。