編寫一個Plugin

前面我們編寫了一個Loader ,這裏我們試下編寫一個簡單的plugin。

那麼Loader 與 Plugin,他們有什麼區別呢。

我們在源代碼中引入js 或其他格式文件時,我們可以通過Loader 去處理這些文件,也就是Loader 幫助我們處理模塊。而Plugin 是在我們打包的時候,在某些特定時刻上插件會被調用。比如說,當打包結束希望自動生成html 文件,這時可以使用htmlWebpackPlugin 插件;再比如,在打包之前,希望把dist 目錄清空,那我們可以使用cleanWebpackPlugin...

下面我們來編寫一個簡單的webpack plugin。

對於webpack 插件來說,他的核心機制事件驅動的模式或者說發佈訂閱設計模式。代碼的執行是通過事件來驅動的。

那我們也是新建一個項目 plugin ,然後npm init -y 來初始化。

然後我們在項目根目錄下新建目錄src, src 下新建文件index.js , 輸入一個console語句

console.log('hello')

然後,我們在項目中安裝webpack, webpack-cli

npm install webpack webpack-cli --save-dev

然後,我們配置一下webpack.config.js 如下。

const path = require('path')

module.exports = {
    mode: 'development',
    entry: {
        main: './src/index.js'
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'
    }
}

然後配置一下package.json 的script 如下。

  "scripts": {
    "build": "webpack"
  },

然後,先打包一下,看看是否配全了。

接下來,我們將做一件事,當打包結束的時候,在dist 目錄下生成一個版權文件,裏面保存版權信息。

那麼,我們在項目跟目錄下創建目錄 plugins,裏面新建一個文件copyright-webpack-plugin.js

然後,插件是一個 class (Loader 是一個函數,雖然本質上class 是函數的語法糖,但class 上還是有些不同的內部功能)。當調用插件的時候,會執行這個類的apply 方法,apply 方法會接收一個參數 compiler ,它是一個webpack 的實例。下面,我們把大致的格式寫好了。

class CopyrightWebpackPlugin {
    constructor () {

    }

    apply (compiler) {
        
    }
}

module.exports = CopyrightWebpackPlugin

然後,在webpack.config.js 中去把插件引入並配置上,如下。

const path = require('path')
const CopyRightWebpackPlugin = require('./plugins/copyright-webpack-plugin')

module.exports = {
    mode: 'development',
    entry: {
        main: './src/index.js'
    },
    plugins: [
        new CopyRightWebpackPlugin()
    ],
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'
    }
}

當然,如果想往插件中傳入參數,在使用new 調用插件的時候,傳入(通過對象)即可,在插件的constructor 中正常接收即可。

回到我們的問題,希望在打包結束時,在dist 下生成一個文件,那麼我們就要使用到插件中的appply 函數。apply 接收的compiler 是一個webpack 的實例,我們先翻翻官網 webpack documentation > API > compiler hooks 

我們可以找到emit 的hook (注意他是 AsyncSeriesHook 即異步的鉤子)

這就是我們要的鉤子,如下

class CopyrightWebpackPlugin {
    apply (compiler) {
        compiler.hooks.emit.tapAsync('CopyrightWebpackPlugin', (compilation, cb) => {
            console.log(123)
            cb()
        })
    }
}

module.exports = CopyrightWebpackPlugin

下面,我們要在打包結束時生成一個文件,在compilation 中存放了這次打包的所有內容,我們查看一下compilation.assets 如下。

class CopyrightWebpackPlugin {
    apply (compiler) {
        compiler.hooks.emit.tapAsync('CopyrightWebpackPlugin', (compilation, cb) => {
            console.log(compilation.assets)
            cb()
        })
    }
}

module.exports = CopyrightWebpackPlugin

下面,我們更改下代碼

class CopyrightWebpackPlugin {
    apply (compiler) {
        compiler.hooks.emit.tapAsync('CopyrightWebpackPlugin', (compilation, cb) => {
            compilation.assets['copyright.txt'] = {
                source: function () {
                    return 'copyright by y'
                },
                size: function () {
                    return 14
                }
            }
            cb()
        })
    }
}

module.exports = CopyrightWebpackPlugin

然後打包,就會發現,打包結束後多了一個我們要的文件。

上面emit hooks 是異步的,如果我們想用的hooks 是同步的話,應該向下面這樣使用。比如compile hook。如下。

class CopyrightWebpackPlugin {
    apply (compiler) {
        compiler.hooks.compile.tap('CopyrightWebpackPlugin', (compilation) => {
            console.log('compile')
        })
        
        compiler.hooks.emit.tapAsync('CopyrightWebpackPlugin', (compilation, cb) => {
            compilation.assets['copyright.txt'] = {
                source: function () {
                    return 'copyright by y'
                },
                size: function () {
                    return 14
                }
            }
            cb()
        })
    }
}

module.exports = CopyrightWebpackPlugin

如果我們想要debug 我們的插件的話,可以使用node 運行webpack ,如下。

先在package.json 中配置script 如下。(__inspect 表示node 運行時進入調試模式,__inspect_brk 表示在執行時在第一行打斷點)


  "scripts": {
    "debug": "node --inspect --inspect-brk node_modules/webpack/bin/webpack.js",
    "build": "webpack"
  },

然後我們運行命令 npm run debug ,即可看到

然後,我們可以打開chrome 瀏覽器。控制檯上會有這個綠色六邊形,點開。就會自動跳轉到調試的頁面。

Done.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章