開始之前咆霜,先介紹一下loader瓶颠,下面是webpack中文網(wǎng)
對loader
的描述
所謂 loader 只是一個導出為函數(shù)的 JavaScript 模塊涩笤。loader runner 會調(diào)用這個函數(shù)匣吊,然后把上一個 loader 產(chǎn)生的結果或者資源文件(resource file)傳入進去。函數(shù)的
this
上下文將由 webpack 填充桌肴,并且 loader runner 具有一些有用方法皇筛,可以使 loader 改變?yōu)楫惒秸{(diào)用方式,或者獲取 query 參數(shù)坠七。
loader的參數(shù)以及返回值(同樣摘抄自webpack中文網(wǎng)
)
第一個 loader 的傳入?yún)?shù)只有一個:資源文件(resource file)的內(nèi)容水醋。compiler 需要得到最后一個 loader 產(chǎn)生的處理結果旗笔。這個處理結果應該是 String 或者 Buffer(被轉換為一個 string) ,代表了模塊的 JavaScript 源碼拄踪。另外還可以傳遞一個可選的 SourceMap 結果(格式為 JSON 對象)蝇恶。
loader在webpack中執(zhí)行的時機
本圖片源于網(wǎng)絡
loader的分類
loader
分為同步loader
和異步loader
丝格。loader
本質(zhì)是一個函數(shù)
盛杰。所以這兩種loader
的區(qū)別右钾,可以理解為只是返回值不同(只是為了方便理解的類比)
摊滔。實際操作并不是
簡單的兩種返回值澎剥。
同步loader
同步loader
比較簡單励堡,無論是 return
還是 調(diào)用this.callback
都可以同步地返回轉換后的 content 內(nèi)容艇炎。
- 使用
return
這種比較直觀耸成,就一個普通函數(shù)叛拷,執(zhí)行完成返回一個值舌厨。例如:
function loader(source) {
// do anything
return source;
}
- 使用
this.callback
this.callback
的函數(shù)參數(shù)類型是
// 后兩個參數(shù)是非必傳的
this.callback(
err: Error | null,
content: string | Buffer,
sourceMap?: SourceMap,
meta?: any
);
這種比return
方式更靈活,可以返回多個值忿薇。例如:
function loader(source) {
// do anything
this.callback(null, source, map, meta);
}
注意: 函數(shù)中調(diào)用callback
后裙椭,return
的返回值將被忽略。
異步loader
異步loader
只有一種處理方式署浩。對于異步 loader揉燃,使用 this.async
來獲取 callback
函數(shù)。這里的callback
函數(shù)筋栋,和同步loader
里面的參數(shù)是一樣的炊汤。
function loader (source) {
console.log('--- loader begin ----');
console.log(source);
console.log('--- loader end ----\n');
const callback = this.async();
// do anything
callback(null, source);
}
module.exports = loader;
注意幾種特殊情況:
- 函數(shù)中調(diào)用
this.async
后,return
的返回值將被忽略弊攘。 - 函數(shù)中調(diào)用
this.async
后抢腐,再調(diào)用this.callback
,則會將當前loader
當做同步loader
來處理襟交。 - 函數(shù)中調(diào)用
this.async
后迈倍,再調(diào)用this.callback
且立即調(diào)用this.async返回的callback
。程序會報錯捣域。
至此啼染,我們就能開始著手寫一個簡單的loader
了。下面便開始焕梅,著手寫幾個loader
banner-loader
這個loader
的功能是給每一個文件頭部迹鹅,添加一行段注釋,標明作者丘侠。例如:
/**
** @author laibao101
** @time 2019-06-04 19:57:20
**/
// source code
功能分析:這個loader
,并沒有任何的異步操作徒欣,所以我們使用同步loader
即可。注釋方面蜗字,暫且先寫死打肝,通過參數(shù)配置的脂新,后續(xù)再做。
function loader (source) {
const time = new Date().toLocaleString()
return `
/**
** @author laibao101
** @time ${time}
**/
${source}
`
}
使用模板字符串粗梭,將注釋代碼寫進去争便,返回即可。這樣一個簡單的loader
就完成了断医。
異步的banner-loader
這個loader
是為了寫一個異步loader
而寫的滞乙。功能是從一個文件中讀取模板,給文件添加banner
// banner-loader
const path = require('path');
const fs = require('fs');
const baseUrl = process.cwd();
const configTextPath = "bannerConfig.txt";
// 拼接完整的配置文件路徑
const fullConfigPath = path.resolve(baseUrl, configTextPath);
// 根據(jù)模板中的占位符鉴嗤,來獲取數(shù)據(jù)
const configItemMap = {
author: "laibao101",
time: new Date().toLocaleString()
};
// 匹配占位符
const reg = /{(\w+)}/gi;
function loader (source) {
const callback = this.async();
fs.readFile(fullConfigPath, (err, data) => {
if (err) {
// 如果讀取文件失敗斩启,返回錯誤
callback(err);
}
// 獲取文件內(nèi)容
const template = data.toString();
// 根據(jù)模板,修改占位符數(shù)據(jù)醉锅,完成banner
const banner = template.replace(reg, (match, key) => {
return configItemMap[key] || key;
});
// 拼接返回值
const ret = `
${banner}
${source}
`
callback(null, ret);
});
}
module.exports = loader;
// bannerConfig.txt
/**
** @author {author}
** @time {time}
**/
可配置參數(shù)的同步banner-loader
前面寫到的banner-loader
兔簇,參數(shù)都是loader
內(nèi)部定的。如果需要從webpack.config.js
中獲取參數(shù)硬耍,則可以使用webpack
提供的this.query
參數(shù)來獲取loader配置中的options
參數(shù)垄琐。這在loader
中使用的很頻繁。
例如:
babel-loader
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
}
url-loader
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
}
}
]
}
]
}
}
所以经柴,我們將上面的banner-loader狸窘,修改一下,將參數(shù)改為從loader配置中獲取
// banner-loader
function loader (source) {
const time = new Date().toLocaleTimeString();
const { author = '' } = this.query || {}
return `
/**
** @author ${author}
** @time ${time}
**/
${source}
`
}
module.exports = loader;
// webpack.config.js
{
...
options: {
author: "laibao101"
}
}
這樣坯认,我們就可以實現(xiàn)參數(shù)從配置文件中獲取的loader了翻擒。
完整代碼
下一篇
介紹 raw-loader
、pitch-loader
牛哺。并各自編寫一個demo