Extend HtmlwebpackPlugin to insert custom scripts

webpack  provides an introduction on how to develop webpack plug-ins, you can visit here directly to view , here is a   development example of extending HtmlWebpackPlugin .

Earlier we introduced  HtmlWebpackPlugin , this plugin allows to inject the output of webpack dynamic packaging into the page, but sometimes we need to inject some custom style sheets or scripts into this page, HtmlWebpackPlugin  does not support this feature. A suggestion was made to the plugin author, and here is the discussion , it turns out that the plugin provides several events to support itself to implement this feature. We walk through an example to demonstrate how to use these events to extend webpack.

need

We want to be able to automatically insert a script's script before the script generated by webpack in order to load our custom data ahead of time. The resulting HTML looks like this.

    <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>

 

The first line is the script we expect to inject, and the other two lines are the scripts exported by webpack.

Getting started with plugins

As a webpack plugin, this is how it is used.

copy code
plugins: [
    new MyPlugin({
        paths: ["./configuration/config.js"]
    }),
    new HtmlwebpackPlugin({
        title: 'Hello Angular2!',
        template: './src/index.html',
        inject: true
    })
],
copy code

 

All plug-ins are defined in plugins, an array of plug-ins, each element is an object instance of a plug-in, and the specific parameters to be passed are defined by you.

As can be seen from the usage, we actually need a class function of JavsScript, that is to say, writing a webpack plugin is to define such a function, which needs to receive parameters.

webpack also requires this object to provide a function called apply, which is defined on the plugin's prototype, webpack will call this method of the plugin instance, and pass a parameter when calling, so that we can access webpack's context information.

The officially provided instance functions are as follows, and the last line is to export the plugin using the  CommonJs  style.

copy code
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;
copy code

 

 

pass parameters

In our requirements, we want to pass a path parameter named paths, where each path needs to generate a script element, inserted before the script exported by webpack.

new MyPlugin({
        paths: ["./configuration/config.js"]
    }),

 

 In our plugin, this parameter needs to be saved for use in the apply function.

function MyPlugin(options) {
    // Configure your plugin with options... 
this.options = options;
}

 

Save it directly to the current object instance. When new is used, this is the just created plug-in object instance.

accomplish

When webpack calls the apply method of the plugin object, we should first get the parameters we saved, use this to access the current object, and get the parameters just saved.

MyPlugin.prototype.apply = function(compiler) {
    // ...
    var paths = this.options.paths;
    

};

 

 

在我们的 apply 方法内,需要调用 compiler 的 plugin 函数。这个函数注册到 webpack 各个处理阶段上,可以支持的参数有:

<iframe id="iframe_0.730754913120701" style="border-style: none; width: 212px; height: 475px;" src="data:text/html;charset=utf8,%3Cstyle%3Ebody%7Bmargin:0;padding:0%7D%3C/style%3E%3Cimg%20id=%22img%22%20src=%22https://cloud.githubusercontent.com/assets/3348398/13768093/f46acd18-eaac-11e5-8895-a20a48e0972c.png?_=5649670%22%20style=%22border:none;max-width:1045px%22%3E%3Cscript%3Ewindow.onload%20=%20function%20()%20%7Bvar%20img%20=%20document.getElementById('img');%20window.parent.postMessage(%7BiframeId:'iframe_0.730754913120701',width:img.width,height:img.height%7D,%20'http://www.cnblogs.com');%7D%3C/script%3E" frameborder="0" scrolling="no"></iframe>

我们这里使用了 compilation 编译任务。

copy code
MyPlugin.prototype.apply = function(compiler) {
    var paths = this.options.paths;
    compiler.plugin('compilation', function(compilation, options) {


    });
};
copy code

 

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 事件。

copy code
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) {

         ......
        });
    });
};
copy code

 

在这个回调函数中,我们可以得到 html-webpack-plugin 提供的上下文对象,比如,它准备生成 script 所对应的 javascript 文件路径就保存在 htmlPluginData.assets.js 数组中,它会根据这个数组中的路径,依次生成 script 元素,然后插入到 Html 网页中。

我们需要的就是就我们的路径插入到这个数组的前面。

copy code
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);
        });
    });
};
copy code

 

完整的插件代码如下所示。

copy code
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;
copy code

 

The last line is to export our plugin.

Discuss

Through the plugin mechanism of webpack, we can freely extend webpack to achieve the features we need.

See Also:

HOW TO WRITE A PLUGIN

How to write a webpack plugin (1)

Optimization of webpack usage (basic) #2

html-res-webpack-plugin

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326611317&siteId=291194637