zoukankan      html  css  js  c++  java
  • 扩展 HtmlwebpackPlugin 插入自定义的脚本

    webpack 提供了一个如何开发 webpack 插件的介绍,你可以直接访问这里查看,这里提供一个扩展 HtmlWebpackPlugin 的开发实例。

    前面我们介绍过 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

  • 相关阅读:
    LeetCode
    LeetCode
    LeetCode
    LeetCode
    LeetCode
    LeetCode
    LeetCode
    LeetCode
    LeetCode
    LeetCode
  • 原文地址:https://www.cnblogs.com/haogj/p/5649670.html
Copyright © 2011-2022 走看看