這是我參與8月更文挑戰的第5天,活動詳情查看:8月更文挑戰html
對於 webpack
來講, loader
和 plugin
能夠算是需求程度最爲普遍的配置項了。可是呢,單單止步於配置可能還不夠。若是咱們本身有時候想要 diy
一個需求,可是 webpack
又沒有相關的 loader
和 plugin
。那這個時候咱們可能就得開始造點輪子來供給本身使用了。node
所以,在今天的文章當中,將帶領你們手寫一個簡易的 loader
和 plugin
,並學會如何在項目中運用本身所編寫的 loader
和 plugin
。webpack
一塊兒來學習吧~📢web
以前的文章中咱們講到了關於 loader
的一些配置。那若是把那些引用的 loader
改成咱們寫的 loader
,該怎麼處理呢?npm
如今,咱們來了解一下,如何手寫一個簡易的 loader
,並運用到咱們的項目當中。設計模式
首先用一張圖,來看咱們的項目結構。以下圖所示:bash
其中 loaders
文件夾下放置咱們想要寫的 loader
,同時裏面的 replaceLoader.js
文件放置咱們即將要寫的 loader
的代碼邏輯。以後,index.js
文件是咱們的入口文件,放置咱們的業務邏輯。 webpack.config.js
文件放置關於 webpack
的相關配置,而 dist
文件夾內的內容,放置的是咱們經過 webpack
打包後,生成的打包文件。markdown
如今,咱們先來編寫入口文件 index.js
的代碼。具體代碼以下:app
console.log('hello monday');
複製代碼
入口文件的內容很簡單,咱們想要達到的目的就是輸出 hello monday
這個語句。如今,咱們來編寫 loader
的內容,已達到對入口文件 index.js
的內容進行修改。 replaceLoader.js
文件的代碼具體以下:異步
module.exports = function(source) {
const result = source.replace('monday', 'mondaylab');
this.callback(null, result);
}
複製代碼
以上的代碼意思爲,將入口文件 index.js
文件中的 monday
替換爲 mondaylab
。這樣寫彷佛沒啥問題,可是你們有沒有想過,咱們有時候傳的屬性可能會很詭異,不必定每次都能像這樣以字符串的形式來替換。
因此,咱們引用 webpack
官方推薦的 loadertils
這個工具,來解決這個問題。
第一步: 安裝 loader-utils
插件。具體命令以下:
npm install loader-utils --save-dev
複製代碼
第二步: 改造 loader
文件。接下來,咱們對 replaceLoader.js
文件進行改造升級,具體代碼以下:
const loaderUtils = require('loader-utils');
//用function的緣由在於爲了業務層能夠調用this
//source爲引入文件的源代碼
module.exports = function(source) {
//getOptions會自動地幫咱們分析this.query,而後把參數的全部內容放在options裏面去
const options = loaderUtils.getOptions(this);
const result = source.replace('monday', options.name);
this.callback(null, result);
}
複製代碼
你們能夠看到,經過使用 loaderUtils
插件,間接地,調用 getOptions
方法,來自動的幫咱們分析 this.query
,從而取到咱們想要的內容。
值得注意的是,咱們還須要再瞭解一下 this.callback
的內容。
通常狀況下,若是咱們接收到了源代碼 source
,那麼如今咱們只能對源代碼作處理。可是呢,有的時候,咱們想要使用一些 sourceMap
,或者對源代碼分析好了以後,咱們不只想要返回源代碼,還要把 sourceMap
也帶回去。
由於咱們 return
的時候只能 return
一個參數,其他的一些額外的內容就帶不出去了。這個時候呢,咱們就須要 this.callback
來幫咱們把 sourceMap
給帶出去。所以,通常用 this.callback
來返回內容。
如今,咱們在 webpack.config.js
中,來引入咱們上面的 loader
。具體配置以下:
const path = require('path');
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
module: {
rules: [{
test: /\.js/,
use: [
{
loader: path.resolve(__dirname, './loaders/replaceLoader.js'),
//上面的options.name中的name
options: {
name: 'mondaylab'
}
}
]
}]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
}
}
複製代碼
經過以上方式,咱們寫了一個簡易的 loader
,這個 loader
實現了將 monday
替換爲 mondaylab
的功能。而且供咱們在 webpack
中使用本身書寫的 loader
。
好了如今,若是咱們想要給 loader
作一些異步操做,該怎麼實現呢?
在咱們所寫的 loader
當中,加入異步操做,那麼咱們須要調用官方提供給咱們的 this.async()
這個 API
來實現。如今,咱們來改造一下 replaceLoader.js
文件的代碼。具體代碼以下:
const loaderUtils = require('loader-utils');
module.exports = function(source) {
const options = loaderUtils.getOptions(this);
//調用this.async()這個API,來給異步代碼使用
const callback = this.async();
setTimeout(() => {
const result = source.replace('monday', options.name);
callback(null, result);
}, 1000);
}
複製代碼
經過這種方式,咱們就能夠在 loader
中編寫異步代碼,來達到咱們想要的效果。
有一個很小的注意點就是,當咱們在配置 webpack.config.js
文件中, loader
的路徑時,每回都要 path.resolve
去尋找路徑文件。文件少的時候還好,但若是遇到多文件的時候呢?豈不是會很麻煩。
因此,咱們引用 resolveLoader
來簡化它。如今咱們在 webpack.config.js
文件中進行改造。具體配置以下:
const path = require('path');
module.exports = {
// 先到node_modules中去找,找不到則去./loaders目錄下去找
resolveLoader: {
modules: ['node_modules', './loaders']
},
module: {
rules: [{
test: /\.js/,
use: [
{
loader: 'replaceLoader'
}
]
}]
}
}
複製代碼
經過配置 resolveLoader
,來對文件文件目錄進行查找,從而簡化了路徑內容。
在講解 plugin
以前,咱們先來了解 loader
和 plugin
的區別。
當咱們在源代碼裏面,去引入一個新的 js
文件,或者是一個其餘格式的文件時,這個時候咱們能夠借用 loader
,來幫咱們處理咱們引用的 loader
文件。 loader
的做用就在於,幫助咱們處理引用的模塊。
而 plugin
呢,是當咱們在作打包的時候,在某些具體時刻上,好比說,當咱們打包結束以後,咱們要生成一個 html
文件,這個時候,咱們就可使用一個 htmlWebpackPlugin
的插件。使用它以後,他就會在打包結束以後,幫咱們生成對應的 html
文件。
再好比,咱們要在打包以前,把 dist
目錄進行清空,這個時候咱們就可使用 cleanWebpackPlugin
來幫助咱們作這件事情。
因此, plugin
插件,在何時生效呢?
它在咱們打包過程當中的某些時刻裏,就是插件生效的場景。
plugin
的編寫相對於 loader
來講,會難一點點。可是呢,若是有看過 webpack
源碼的小夥伴們可能會知道, webpack
的一些底層原理都是依據 plugin
來進行編寫的。因此,咱們仍是有必要來學習一下 plugin
的編寫。
下面就帶領你們來編寫一個簡易的 plugin
~
對於 webpack
的 plugin
來講,它是是基於發佈者訂閱的設計模式,也能夠說是基於事件驅動來實現的。在這個事件驅動裏,代碼之間的執行,是經過事件來進行驅動的。
接下來,咱們就來寫一個簡易的 plugin
。
首先用一張圖,來看咱們的項目結構。以下圖所示:
其中 plugins
文件夾下放置咱們想要寫的 plugin
,同時裏面的 copyright-webpack-plugin.js
文件放置咱們即將要寫的 plugin
的代碼邏輯。以後,index.js
文件是咱們的入口文件,放置咱們的業務邏輯。 webpack.config.js
文件放置關於 webpack
的相關配置,而 dist
文件夾內的內容,放置的是咱們經過 webpack
打包後,生成的打包文件。
如今,咱們先來編寫入口文件 index.js
的代碼。具體代碼以下:
console.log('hello monday');
複製代碼
如今,咱們來編寫 plugin
的內容, copyright-webpack-plugin.js
文件的代碼具體以下:
class CopyrightWebpackPlugin {
//編寫一個構造器
constructor(options) {
console.log(options)
}
apply(compiler) {
//遇到同步時刻
compiler.hooks.compile.tap('CopyrightWebpackPlugin',() => {
console.log('compiler');
});
//遇到異步時刻
//當要把代碼放到dist目錄以前,要走下面這個函數
//Compilation存放打包的全部內容,Compilation.assets放置生成的內容
compiler.hooks.emit.tapAsync('CopyrightWebpackPlugin', (Compilation, cb) => {
debugger;
// 往代碼中增長一個文件,copyright.txt
Compilation.assets['copyright.txt'] = {
source: function() {
return 'copyright by monday';
},
size: function() {
return 19;
}
};
cb();
})
}
}
module.exports = CopyrightWebpackPlugin;
複製代碼
上面的這個插件中想要實現的功能就是,獲取版權信息。
如今,咱們在 webpack.config.js
中,來引入咱們上面的 plugin
。具體配置以下:
const path = require('path');
const CopyrightWebpackPlugin = require('./plugins/copyright-webpack-plugin');
module.exports = {
mode: 'development',
entry: {
main: './src/index.js'
},
plugins: [
new CopyrightWebpackPlugin({
name: 'monday'
})
],
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
}
}
複製代碼
經過上述代碼,咱們能夠了解到,在(2)中,咱們首先須要定義一個類,以後呢,在類中寫一個構造器和一個 apply()
方法來調用。而後呢,你們看到(3),經過 require
的方式,來進行 new 實例 ,實例化一個插件,從而在項目中使用這個插件。
最終,咱們項目進行打包時,就會生成一個 dist
目錄,而且在目錄下增長一個 copyright.txt
文件,而且文件中的內容就是 copyright by monday
。
在上面的文章中,講解了關於loader和plugin的基本編寫思路,以及如何在項目中對他們進行運用,相信你們對這一塊內容有了基礎的認識。
到這裏,loader和plugin的編寫講解就結束啦!但願對你們有幫助~
如文章有誤或有不理解的地方,歡迎小夥伴們評論區留言哦💬
本系列文章代碼已上傳至公衆號,後臺回覆關鍵詞 webpack
便可獲取~
webpack入門核心知識👉萬字總結webpack的超入門核心知識
webpack入門進階知識👉萬字總結webpack入門進階知識
webpack實戰案例配置👉萬字總結webpack實戰案例配置
關注公衆號星期一研究室,第一時間關注優質文章,更多精選專欄待你解鎖~
若是這篇文章對你有用,記得留個腳印jio再走哦~
以上就是本文的所有內容!咱們下期見!👋👋👋