Plugins expose the full potential of the webpack engine to third-party developers. ----------- Webpackhtml
相比于 loaders,plugin 更加的灵活,由于它可以接触到 webpack 编译器和编译核心。这就使得 plugin 能够经过一些 hook 函数来拦截 webpack 的执行,甚至你能够运行一个子编译器和 loader 串联,像 MiniCssExtractPlugin
就是这么作的。webpack
示例代码:linkgit
以 html-webpack-plugin
为例,它的使用以下github
plugins: [
new HtmlWebpackPlugin({
...
}),
],
复制代码
不难看出,webpack plugin 的基本形式一个构造函数 new function()
,同时为了可以得到 compiler,就须要 plugin 对外暴露一个接口(为 apply
函数)。因此,它的基本结构以下:web
prototype
上,定义一个 apply
方法。JavaScript 的实现这种形式的方法有不少,本文采用 class
来实现,具体以下npm
module.exports = class DemoPlugin {
apply() {
console.log('applying')
}
}
复制代码
为了可以运行这个 plugin,咱们须要建立一个环境json
mkdir webpack-demo-plugin
cd webpack-demo-plugin
npm init
复制代码
webpack.plugin.jsapi
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.jsbash
console.log("hello world")
复制代码
同时向 package.json 中添加app
"scripts": {
"build:plugin": "webpack --config webpack.plugin.js --mode production",
...
}
复制代码
建立 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 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
的 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。
作一个实验,若是你在 apply
函数内插入 throw new Error("Message")
,会发生什么,终端会打印出 Unhandled rejection Error: Message
。而后 webpack 中断执行。
为了避免影响 webpack 的执行,要在编译期间向用户发出警告或错误消息,则应使用 compilation.warnings
和 compilation.errors
。
compilation.warnings.push("warning");
compilation.errors.push("error");
复制代码
当你着手开始设计插件时,必定要花时间研究同类型的现有插件。 逐个开发插件,以便你一次只验证一个插件。 遇到问题,能够查看 webpack 源码,它会加强你的 debug 直觉。
参考: