webpack 提供了一个如何开发 webpack 插件的介绍,你能够直接访问这里查看,这里提供一个扩展 HtmlWebpackPlugin 的开发实例。javascript
前面咱们介绍过 HtmlWebpackPlugin, 这个插件容许将 webpack 动态打包的输出注入到页面中,可是,有的时候咱们须要在这个页面中注入一些自定义的样式表或者脚本,HtmlWebpackPlugin 并不支持这个特性。有人向插件做者提了建议,这里是讨论的内容,结果是插件提供了几个事件来支持本身来实现这个特性。咱们经过一个实例来演示如何使用这些事件来扩展 webpack。html
咱们但愿可以自动插入一个脚本的 script 在 webpack 生成的 script 以前,以便提早加载咱们自定义的数据。最后生成的 HTML 相似这样的效果。java
<script type="text/javascript" src="./configuration/config.js"></script> <script type="text/javascript" src="style.bundle.js"></script> <script type="text/javascript" src="app.bundle.js"></script>
第一行是咱们指望注入的脚本,其它两行是 webpack 导出的脚本。webpack
做为一个 webpack 的插件,使用方式是这样的。git
plugins: [ new MyPlugin({ paths: ["./configuration/config.js"] }), new HtmlwebpackPlugin({ title: 'Hello Angular2!', template: './src/index.html', inject: true }) ],
全部的插件定义在 plugins 中,插件组成的一个数组,每一个元素是一个插件的对象实例,具体传递什么参数,是你本身定义的。github
从使用方式中能够看出,其实咱们须要一个 JavsScript 的类函数,也就是说,写 webpack 插件就是定义一个这样的函数,这个函数须要接收参数。web
webpack 还要求这个对象提供一个名为 apply 的函数,这个函数定义在插件的原型上,webpack 会调用插件实例的这个方法,在调用的时候还会传递一个参数,以便咱们访问 webpack 的上下文信息。npm
官方提供的实例函数以下,最后一行是使用 CommonJs 风格导出这个插件。数组
function HelloWorldPlugin(options) { // Setup the plugin instance with options... } HelloWorldPlugin.prototype.apply = function(compiler) { compiler.plugin('done', function() { console.log('Hello World!'); }); }; module.exports = HelloWorldPlugin;
在咱们的需求中,咱们但愿传递一个名为 paths 的路径参数,其中的每一个路径须要生成一个 script 元素,插入到 webpack 导出的 script 以前。app
new MyPlugin({ paths: ["./configuration/config.js"] }),
在咱们的插件中,须要保存这个参数,以便在 apply 函数中使用。
function MyPlugin(options) { // Configure your plugin with options... this.options = options; }
直接保存到当前的对象实例中,在配合 new 的时候,this 就是刚刚建立的插件对象实例了。
在 webpack 调用插件对象的 apply 方式的时候,咱们首先应该获取咱们保存的参数,使用 this 访问当前对象,获取刚刚保存的参数。
MyPlugin.prototype.apply = function(compiler) { // ... var paths = this.options.paths; };
在咱们的 apply 方法内,须要调用 compiler 的 plugin 函数。这个函数注册到 webpack 各个处理阶段上,能够支持的参数有:
咱们这里使用了 compilation 编译任务。
MyPlugin.prototype.apply = function(compiler) { var paths = this.options.paths; compiler.plugin('compilation', function(compilation, options) {
}); };
webpack 会给咱们提供的回调函数提供参数,咱们能够注册编译阶段的事件了。html-webpack-plugin 提供了一系列事件。
Async:
html-webpack-plugin-before-html-generation
html-webpack-plugin-before-html-processing
html-webpack-plugin-alter-asset-tags
html-webpack-plugin-after-html-processing
html-webpack-plugin-after-emit
Sync:
html-webpack-plugin-alter-chunks
咱们能够注册到它处理 HTML 以前,使用 html-webpack-plugin-before-html-processing 事件。
MyPlugin.prototype.apply = function(compiler) { var paths = this.options.paths; compiler.plugin('compilation', function(compilation, options) { compilation.plugin('html-webpack-plugin-before-html-processing', function(htmlPluginData, callback) {
......
}); }); };
在这个回调函数中,咱们能够获得 html-webpack-plugin 提供的上下文对象,好比,它准备生成 script 所对应的 javascript 文件路径就保存在 htmlPluginData.assets.js 数组中,它会根据这个数组中的路径,依次生成 script 元素,而后插入到 Html 网页中。
咱们须要的就是就咱们的路径插入到这个数组的前面。
MyPlugin.prototype.apply = function(compiler) { var paths = this.options.paths; compiler.plugin('compilation', function(compilation, options) { compilation.plugin('html-webpack-plugin-before-html-processing', function(htmlPluginData, callback) { for (var i = paths.length - 1; i >= 0; i--) { htmlPluginData.assets.js.unshift(paths[i]); } callback(null, htmlPluginData); }); }); };
完整的插件代码以下所示。
function MyPlugin(options) { this.options = options; } MyPlugin.prototype.apply = function(compiler) { var paths = this.options.paths; compiler.plugin('compilation', function(compilation, options) { compilation.plugin('html-webpack-plugin-before-html-processing', function(htmlPluginData, callback) { for (var i = paths.length - 1; i >= 0; i--) { htmlPluginData.assets.js.unshift(paths[i]); } callback(null, htmlPluginData); }); }); }; module.exports = MyPlugin;
最后一行是导出咱们的插件。
经过 webpack 的插件机制,咱们能够自由地扩展 webpack ,实现咱们须要的特性。