寫在前面的話
首先我想說,絕大多數國中級前端别說手寫這玩意了,連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/
這是官網給的步驟
簡單翻譯下步驟
第一步,有個命名的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一下執行個體化就行了