网站首页 > 技术文章 正文
大家好,我是喜欢写 hello world 的前端西瓜哥。这次我们开发一个自己的 webpack 插件。
插件使用的 webpack 版本为 4.46.0。
webpack 插件有什么用?
webpack plugins 是 webpack 非常重要的一环,用于增强 webpack 的功能。
插件会在 webpack 构建时的生命周期钩子上做一些处理。比如,最常用的 HtmlWebpackPlugin 是在打包文件构建好之后,该插件会额外生成一个 HTML,并将将打包文件通过引用的方式加入到 HTML 文件里。
下面正式开始开发一款名为 HelloWorldPlugin 的插件,作用是打包时额外生成一个 hello.js 文件。
plugin 的结构
首先插件需要有一个 apply 方法。webpack 构建时,会执行这个 apply 方法,并将 webpack 的 compiler 对象传入进去。
通过这个对象,我们可以访问 webpack 的生命周期钩子,改动一些构造过程中产生的对象,影响最终构建结果。
理论上插件是个有 apply 方法的对象即可,但最好还是写成类的形式。
我们看下 webpack 常见的配置写法:
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// ...
new HtmlWebpackPlugin({
template: 'index.html',
}),
// ...
}
可以看到,类的写法可以更方便地传入配置项,以及被复用(这里的 new HtmlWebpackPlugin 其实可以被使用多次,构造多个 HTML)。
我们的 HelloWorldPlugin 类的基本框架为:
class HelloWorldPlugin {
options;
constructor(options) {
this.options = options;
}
apply(compiler) {
console.log('hello');
}
}
module.exports = HelloWorldPlugin;
然后将该插件加入到 webpack 配置中:
const HelloWorldPlugin = require('./HelloWorldPlugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'app.js',
},
plugins: [
// 插件在这里
new HelloWorldPlugin(),
],
}
此时如果执行 webpack 构建,你会在控制台中看到 hello 被打印出来。
此外构造函数也会将传入的配置对象保存起来,当然这里我还没传任何东西。
使用 webpack 的生命周期钩子
下面我们让 HelloWorldPlugin 去通过钩子去额外生成一个文件。
先看 plugin 代码实现:
const { RawSource } = require('webpack-sources');
const pluginName = 'hello-world-plugin';
class HelloWorldPlugin {
options;
constructor(options) {
this.options = options;
}
apply(compiler) {
// 生成一个文件
compiler.hooks.emit.tap(pluginName, (compilation) => {
compilation.assets['hello.js'] = new RawSource('console.log(\'Hello world!\')');
})
}
}
module.exports = HelloWorldPlugin;
apply 方法中,通过 compiler.hooks 可以拿到所有的钩子。
我们要用到是 emit hook。emit hook 的触发时机是 webpack 打包好资源,准备将资源生成到构建目录之前,此时正是我们往里面塞一个文件的好时机。
我们需要执行这个 emit hook 的 tap 方法来注册事件响应函数,这里需要传入当前插件名和一个回调函数。传入插件名,我也不清楚是要干嘛,大概是做一个标记,方便 debug。回调函数则会拿到一个 compilation 对象,这个对象下的 assets 其实就是即将生成的文件。我们可以直接修改这个对象,补上一个 hello.js 文件。
这里需要用到 webpack 官方提供的 webpack-sources 库,这个库专门用来生成符合 assets 格式的对象。
const { RawSource } = require('webpack-sources');
compilation.assets['hello.js'] = new RawSource('console.log(\'Hello world!\')');
如果你使用 webpack5,该库其实已经内置到 webpack 中,通过 require('webpack').sources 即可获取到。
使用 webpack 构建后,你会发现 dist 目录下,除了有一个 app.js 文件,还有一个内容为 console.log('Hello world!') 的 hello.js 文件。
使用插件配置
这里我们没有用到插件传入的配置,我们对 HelloWorldPlugin 做个加强,用到配置。
插件改为:
const { RawSource } = require('webpack-sources');
const pluginName = 'hello-world-plugin'
class HelloWorldPlugin {
options;
constructor(options) {
this.options = options;
}
apply(compiler) {
const { filename, content} = this.options;
compiler.hooks.emit.tap(pluginName, (compilation) => {
compilation.assets[filename] = new RawSource(content);
})
}
}
module.exports = HelloWorldPlugin;
配置改为:
plugins: [
new HelloWorldPlugin({
filename: 'a.js',
content: 'b',
}),
]
于是你额外拿到了一个内容为 b 的 a.js 文件。
结尾
总结一下,开发一个 Plugin 的几个要点:
- 确定 webpack 版本,使用对应的 API。否则插件可能用了更高版本的 webpack 语法且没有兼容而无法工作,比如 webpack4 中, CopyWebpackPlugin 的版本不能高于 6。
- 插件需要通过类的方式保存好传入的配置项,并提供一个 apply 方法。
- 插件本质是利用 webpack 构建时的各种生命周期钩子,在其中对数据做一些改动,最终导致构建的资源发生变化。
- webpack 官方文档写得很垃圾
我是啥都写写的前端西瓜哥,欢迎关注我。
猜你喜欢
- 2024-09-26 2020年了,再不会webpack敲得代码就不香了(近万字实战)
- 2024-09-26 Webpack高频面试题(附答案)(webpack与gulp面试题)
- 2024-09-26 webpack-dev-server 版本问题(webpack dev server before)
- 2024-09-26 webpack4、5+基础入门(webpack实战 入门进阶与调优)
- 2024-09-26 webpack插件篇之html-webpack-plugin
- 2024-09-26 手把手教你在Webpack写一个Loader
- 2024-09-26 webpack学习(webpack教学)
- 2024-09-26 Webpack构建速度优化(webpack提高构建速度)
- 2024-09-26 Webpack - 手把手教你写一个 loader / plugin
- 2024-09-26 是切图仔还是工程师就看会不会它(webpack-1)
- 1514℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 573℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 513℃MySQL service启动脚本浅析(r12笔记第59天)
- 486℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 486℃启用MySQL查询缓存(mysql8.0查询缓存)
- 469℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 449℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 447℃MySQL server PID file could not be found!失败
- 最近发表
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (83)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- checkout-b (67)
- c语言min函数头文件 (68)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)