从零实现一个 Webpack Plugin
栏目: JavaScript · 发布时间: 5年前
内容简介:相比于 loaders,plugin 更加的灵活,因为它能够接触到 webpack 编译器和编译核心。这就使得 plugin 可以通过一些 hook 函数来拦截 webpack 的执行,甚至你可以运行一个子编译器和 loader 串联,像示例代码:以
Plugins expose the full potential of the webpack engine to third-party developers. ----------- Webpack
相比于 loaders,plugin 更加的灵活,因为它能够接触到 webpack 编译器和编译核心。这就使得 plugin 可以通过一些 hook 函数来拦截 webpack 的执行,甚至你可以运行一个子编译器和 loader 串联,像 MiniCssExtractPlugin
就是这么做的。
示例代码: link
webpack plugin 基本结构
以 html-webpack-plugin
为例,它的使用如下
plugins: [ new HtmlWebpackPlugin({ ... }), ], 复制代码
不难看出,webpack plugin 的基本形式一个构造函数 new function()
,同时为了能够获得 compiler,就需要 plugin 对外暴露一个接口(为 apply
函数)。所以,它的基本结构如下:
- 一个命名的 JavaScript 函数对象;
-
在其
prototype
上,定义一个apply
方法。
JavaScript 的实现这种形式的方法有很多,本文采用 class
来实现,具体如下
module.exports = class DemoPlugin { apply() { console.log('applying') } } 复制代码
配置开发环境
为了能够运行这个 plugin,我们需要创建一个环境
mkdir webpack-demo-plugin cd webpack-demo-plugin npm init 复制代码
webpack.plugin.js
const path = require("path"); const PATHS = { lib: path.join(__dirname, "index.js"), build: path.join(__dirname, "build"), }; module.exports = { entry: { lib: PATHS.lib, }, output: { path: PATHS.build, filename: "[name].js", }, }; 复制代码
index.js
console.log("hello world") 复制代码
同时向 package.json 中添加
"scripts": { "build:plugin": "webpack --config webpack.plugin.js --mode production", ... } 复制代码
实现 webpack demo
创建 plugins/demo-plugin.js 文件,内容为之前的 webpack plugin demo,并将其引入到 webpack.plugin.js 内。
webpack.plugin.js
const DemoPlugin = require("./plugins/demo-plugin.js"); module.exports = { ... // 引入 plugin plugins: [new DemoPlugin()], }; 复制代码
尝试运行下 npm run build:plugin
,终端上打印出
applying Hash: 98c8997160aa995a58a4 Version: webpack 4.12.0 Time: 93ms Built at: 2019-04-29 14:34:31 Asset Size Chunks Chunk Names lib.js 956 bytes 0 [emitted] lib [0] ./index.js 26 bytes {0} [built] 复制代码
惊奇的发现 applying,说明插件已经成功运行。
传递参数
在应用一个 plugin 时,有时需要根据传递 Options 来告诉 plugin 具体应该做什么。当 new DemoPlugin()
时候会触发 class DemoPlugin
的 constructor
所以
plugins/demo-plugin.js
module.exports = class DemoPlugin { constructor(options) { this.options = options } apply() { console.log('apply', this.options) } } 复制代码
同时,还需要修改 webpack.plugin.js 来传递对应参数
module.exports = { ... plugins: [new DemoPlugin({ name: 'demo' })], } 复制代码
运行 npm run build:plugin
,可以发现 apply { name: 'demo' }
。这里介绍一个常用插件schema-utils 能够用来校验 Options。
理解 webpack 的 compiler 和 compilation
在之前的 webpack plugin 基本结构中介绍, apply
函数能够用来访问 webpack 的核心。具体的做法是, apply
函数的参数为 compiler
plugins/demo-plugin.js
module.exports = class DemoPlugin { constructor(options) { this.options = options } apply(compiler) { console.log(compiler) } } 复制代码
再次运行 npm run build:plugin
,会发现终端上打印出了 compiler
的全部信息,其中 hooks
字段占了绝大部分。
对照着官方文档,你会发现每一个 hook 对应一个特定的阶段。 例如,emit 实践是在向输出目录发送资源之前执行。这样就可以通过监听 hook 来实现控制编译过程。
plugins/demo-plugin.js
module.exports = class DemoPlugin { constructor(options) { this.options = options } apply(compiler) { compiler.plugin('emit', (compilation, next) => { console.log(compilation) next() }) } } 复制代码
不要忘记调用 next,否则 webpack 将不会继续打包。
运行 npm run build:plugin
会显示出比以前更多的信息,因为编译对象包含webpack 遍历的整个依赖关系图。 你可以访问与此相关的所有内容,包括 entries, chunks, modules, assets等。
通过 Compilation 写入文件
可以通过 compilation
的 assets
对象来编写新的文件,或是修改已经创建的文件。为了更好地写入文件,我们引入一个 npm 包
npm install webpack-sources --save-dev 复制代码
plugins/demo-plugin.js
const { RawSource } = require("webpack-sources"); module.exports = class DemoPlugin { constructor(options) { this.options = options } apply(compiler) { const { name } = this.options; compiler.plugin('emit', (compilation, next) => { compilation.assets[name] = new RawSource("demo"); next() }) } } 复制代码
在终端运行 npm run build:plugin
Hash: 98c8997160aa995a58a4 Version: webpack 4.12.0 Time: 95ms Built at: 2019-04-29 16:08:52 Asset Size Chunks Chunk Names lib.js 956 bytes 0 [emitted] lib demo 4 bytes [emitted] [0] ./index.js 26 bytes {0} [built] 复制代码
在 Asset 那里一列内,出现了我们自定的 demo 文件。
更多的钩子函数,请见 the official compilation reference 。
管理 Warnings 和 Errors
做一个实验,如果你在 apply
函数内插入 throw new Error("Message")
,会发生什么,终端会打印出 Unhandled rejection Error: Message
。然后 webpack 中断执行。
为了不影响 webpack 的执行,要在编译期间向用户发出警告或错误消息,则应使用 compilation.warnings
和 compilation.errors
。
compilation.warnings.push("warning"); compilation.errors.push("error"); 复制代码
以上所述就是小编给大家介绍的《从零实现一个 Webpack Plugin》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- php如何实现session,自己实现session,laravel如何实现session
- AOP如何实现及实现原理
- webpack 实现 HMR 及其实现原理
- Docker实现原理之 - OverlayFS实现原理
- 为什么实现 .NET 的 ICollection 集合时需要实现 SyncRoot 属性?如何正确实现这个属性?
- 自己实现集合框架(十):顺序栈的实现
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。