天天看點

webpack自定義loader和plugin寫在前面的話自定義loader自定義plugin

寫在前面的話

首先我想說,絕大多數國中級前端别說手寫這玩意了,連webpack打包都不需要接觸到,哪怕是進階,外包型公司或者大型自研項目理論上也接觸不到。就算接觸到了,現有的優化建構方案和第三方插件和包非常多,webpack的生态其實做的很好了,但是吧,你隻要在履歷裡不管是真搞過還是吹了牛寫上了對webpack的研究,那很有可能,面試官會問你又沒有自己寫過loader和plugin啊。那沒事咱不慌,問就是寫過,寫給他看就是了

自定義loader

官方文檔

https://webpack.docschina.org/contribute/writing-a-loader/

方法

首先官方文檔告訴我們,要自定義loader,在webpack.config.js裡通過絕對路徑引入自定義loader。

以file-loader舉例 源碼中除了開頭的綁原型鍊處理相容性問題。核心内容就是一個帶content參數的函數。所有編譯的内容其實都是字元串。将處理的字元串交給下一個函數。就是字元串的編譯

在config中建立一個loaders目錄,在目錄中建立一個你的loader檔案

基本文法

其實覺大多數的loader的基本文法都是如此,就是核心是個函數

function loader(source){
	const res =''
	return `module.exports=${res}`
}
module.exports=loader
           

自定義file loader

// 自定義Loader

module.exports = function(source) {

  // do something
  let result = source.replace(/\#/img, ' ')
  // do something

  // console.log('txt-loader result', result)
  return `module.exports = ${JSON.stringify(result)}`
}

           

用法

加上自定義loader 注意loader的鍊式調用,下一個接收的子產品是什麼,是以要注意是用modules抛出還是用ES6的文法環境,最好做個判斷,否則會出錯。

記得放在自己的包中,不要寫在node-modules包了

難點

說實話,造輪子實際上需要有較強的源碼能力。是以不管未來造啥輪子,第一步,看文檔看文檔看文檔。

閱讀源碼的邏輯是要把插件或者架構的核心看懂。比如vue的template編譯,那是非常複雜的字元串判斷。

手搓loader,難的不是寫法和思路,而是字元串的編譯解析。如果你懂甚至很精通編譯原理,那這個面試問題就成了你的出場,是你給面試官表演的時候了,其實vue-loader也是難在編譯原理。是以想想,是不是大學沒學好?

自定義plugin

上官網

https://webpack.docschina.org/contribute/writing-a-plugin/

這是官網給的步驟

webpack自定義loader和plugin寫在前面的話自定義loader自定義plugin

簡單翻譯下步驟

第一步,有個命名的function或者class

第二步 定義apply方法定義在原型鍊上 如果是面向對象 直接放在類的内部就是了

第三步 指定事件的hook,指向本身,tap事件

第四步 操作 webpack 内部執行個體特定資料。

第五步 處理回調

自定義一個clean 清除目錄方法

clean有缺陷,每次clean後dist檔案根節點的檔案清理不幹淨,比如在dist根目錄的自己建立的檔案清理不幹淨。webpack v5中實作删除dist目錄的寫法:缺陷是publicPath外面的檔案無法删除。

clean-webpack-plugin源碼

https://unpkg.com/browse/[email protected]/dist/clean-webpack-plugin.js

方法

config檔案夾下plugins檔案并建立自己的pluginjs檔案

導入

plugins: [

    new MyCleankPlugin()
  ],
           

核心極簡代碼

const del = require("del")
const path = require("path")

// 自定義定義插件
class MyCleankPlugin {
  // apply是webpack plugin的入口方法
  apply(compiler) {
    // 觸發插件運作
    compiler.hooks.emit.tap('qf-clean-plugin', () => {
      // 使用del這個庫執行删除操作
      try {
        const deleted = del.sync(['*'], {
          cwd: path.resolve(__dirname, '../../dist'),
          dot: true,
          ignore: []
        })
      } catch (error) {
        throw error
      }
    })
  }
}
module.exports = MyCleankPlugin

           

分析

用了del node的第三方包 引入path子產品 核心就是個class類,用del庫同步删除,調用apply方法,核心就是class 裡面的apply接收編譯器的方法compiler 裡面有webpack編譯器内置的方法,同時接收一個事件tap,這個事件觸發自己。在觸發時進行業務操作,抛出class。在plugins裡new一下執行個體化就行了