扩展 HtmlwebpackPlugin 插入自定义的脚本
2016-07-08 16:36
736 查看
webpack 提供了一个如何开发 webpack 插件的介绍,你可以直接访问这里查看,这里提供一个扩展 HtmlWebpackPlugin 的开发实例。
前面我们介绍过 HtmlWebpackPlugin, 这个插件允许将 webpack 动态打包的输出注入到页面中,但是,有的时候我们需要在这个页面中注入一些自定义的样式表或者脚本,HtmlWebpackPlugin 并不支持这个特性。有人向插件作者提了建议,这里是讨论的内容,结果是插件提供了几个事件来支持自己来实现这个特性。我们通过一个实例来演示如何使用这些事件来扩展 webpack。
第一行是我们期望注入的脚本,其它两行是 webpack 导出的脚本。
所有的插件定义在 plugins 中,插件组成的一个数组,每个元素是一个插件的对象实例,具体传递什么参数,是你自己定义的。
从使用方式中可以看出,其实我们需要一个 JavsScript 的类函数,也就是说,写 webpack 插件就是定义一个这样的函数,这个函数需要接收参数。
webpack 还要求这个对象提供一个名为 apply 的函数,这个函数定义在插件的原型上,webpack 会调用插件实例的这个方法,在调用的时候还会传递一个参数,以便我们访问 webpack 的上下文信息。
官方提供的实例函数如下,最后一行是使用 CommonJs 风格导出这个插件。
在我们的插件中,需要保存这个参数,以便在 apply 函数中使用。
直接保存到当前的对象实例中,在配合 new 的时候,this 就是刚刚创建的插件对象实例了。
在我们的 apply 方法内,需要调用 compiler 的 plugin 函数。这个函数注册到 webpack 各个处理阶段上,可以支持的参数有:
我们这里使用了 compilation 编译任务。
webpack 会给我们提供的回调函数提供参数,我们可以注册编译阶段的事件了。html-webpack-plugin 提供了一系列事件。
Async:
Sync:
我们可以注册到它处理 HTML 之前,使用 html-webpack-plugin-before-html-processing 事件。
在这个回调函数中,我们可以得到 html-webpack-plugin 提供的上下文对象,比如,它准备生成 script 所对应的 javascript 文件路径就保存在 htmlPluginData.assets.js 数组中,它会根据这个数组中的路径,依次生成 script 元素,然后插入到 Html 网页中。
我们需要的就是就我们的路径插入到这个数组的前面。
完整的插件代码如下所示。
最后一行是导出我们的插件。
如何写一个webpack插件(一)
webpack使用优化(基本篇) #2
html-res-webpack-plugin
前面我们介绍过 HtmlWebpackPlugin, 这个插件允许将 webpack 动态打包的输出注入到页面中,但是,有的时候我们需要在这个页面中注入一些自定义的样式表或者脚本,HtmlWebpackPlugin 并不支持这个特性。有人向插件作者提了建议,这里是讨论的内容,结果是插件提供了几个事件来支持自己来实现这个特性。我们通过一个实例来演示如何使用这些事件来扩展 webpack。
需求
我们希望能够自动插入一个脚本的 script 在 webpack 生成的 script 之前,以便提前加载我们自定义的数据。最后生成的 HTML 类似这样的效果。<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 的插件,使用方式是这样的。plugins: [ new MyPlugin({ paths: ["./configuration/config.js"] }), new HtmlwebpackPlugin({ title: 'Hello Angular2!', template: './src/index.html', inject: true }) ],
所有的插件定义在 plugins 中,插件组成的一个数组,每个元素是一个插件的对象实例,具体传递什么参数,是你自己定义的。
从使用方式中可以看出,其实我们需要一个 JavsScript 的类函数,也就是说,写 webpack 插件就是定义一个这样的函数,这个函数需要接收参数。
webpack 还要求这个对象提供一个名为 apply 的函数,这个函数定义在插件的原型上,webpack 会调用插件实例的这个方法,在调用的时候还会传递一个参数,以便我们访问 webpack 的上下文信息。
官方提供的实例函数如下,最后一行是使用 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 之前。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 ,实现我们需要的特性。See Also:
HOW TO WRITE A PLUGIN如何写一个webpack插件(一)
webpack使用优化(基本篇) #2
html-res-webpack-plugin