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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM