插件plugin
插件是 webpack 除了loader以外的另一个核心功能。而通过对Webpack源码的观察,我们发现Webpack自身也是构建于各类插件之上。
插件目的在于解决上一篇文章所介绍的loader 无法实现的事。通过上篇文章的介绍,我们知道了loader的主要作用是对各类的文件的解析、预处理。但如果仅有这些对于我们的日常开发是远远不够的,这也是插件所补充的部分。
如何使用插件
我们日常开发中如果需要使用Webpack插件,就需要在webpack.config.js中进行配置,比如:
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
filename: 'my-first-webpack.bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /.(js|jsx)$/,
use: 'babel-loader',
},
],
},
plugins: [
new HtmlWebpackPlugin({ template: './src/index.html' }),
],
};
上面的例子中首先通过require加载通过npm安装的插件,接着在module.exports中的plugins中传入我们所需要的插件的实例,这里通过new来创建一个插件的实例并进行加载。这里的例子是一个解析html的插件,插件需要传入一个参数是需要处理的html的相对路径,然后插件内部对该html进行解析,构建。该插件将为你生成一个 HTML5 文件, 在 body 中使用 script 标签引入你所有 webpack 生成的 bundle。HtmlWebpackPlugin简化了 HTML 文件的创建,以便为你的 webpack 包提供服务。这对于那些文件名中包含哈希值,并且哈希值会随着每次编译而改变的 webpack 包特别有用。
一个插件是如何开发的
plugins是可以用自身原型方法apply来实例化的对象。apply只在安装插件被Webpack compiler执行一次。apply方法传入一个webpck compiler的引用,来访问编译器回调。一个简单的插件代码结构是这样:
class Plugin {
constructor(options) {}
apply(compiler) {
//...
}
}
module.exports = Plugin
这里以HtmlWebpackPlugin的代码为例:
apply(compiler){
compiler.hooks.make.tapAsync(
//...
)
}
这里的compiller.hooks.make()函数,这是一个异步并发 AsyncParallelBailHook 钩子,也就是在编译完成之前执行的钩子函数,compiler里有很多钩子函数是在webpack的compile编译过程的不同阶段进行操作的钩子,这样也就扩展了我们的webpack的功能。
插件的执行过程
首先介绍一下Compiler,Compiler 模块是 webpack 的核心引擎,它通过 CLI 或 Node API 传递的所有选项,创建出一个 compilation 实例。它扩展(extend)自 Tapable 类,以便于我们注册和调用插件。大多数面向用户的插件首先在 Compiler 上注册。
监听
Compiler支持可以监控文件系统的监听(watching)机制,并且在文件修改时重新编译。当处于监听模式(watch mode)时,compiler 会触发诸如watchRun,watchClose和invalid等额外的事件。通常用于开发环境中使用,也常常会在webpack-dev-server这些工具的底层之下调用,由此开发人员无须每次都使用手动方式重新编译。还可以通过 CLI 进入监听模式。
执行过程
- 在
Webpack开始读取插件配置的过程中会先执行new xxxPlugin(options)初始化一个xxxxPlugin插件来获得其实例。 - 在初始化
compiler对象后调用xxxxPlugin.apply(compiler)给插件实例传入compiler对象。 - 插件实例在获取到
compiler对象后,就可以通过compiler.plugin(事件名称, 回调函数)监听到Webpack广播出来的事件。然后根据不同的事件,进行不同的操作。并且可以通过compiler对象去操作Webpack。