編寫一個webpack的loader(1)

開始之前咆霜,先介紹一下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執(zhí)行時機.png

loader的分類

loader分為同步loader異步loader丝格。loader本質(zhì)是一個函數(shù)盛杰。所以這兩種loader的區(qū)別右钾,可以理解為只是返回值不同(只是為了方便理解的類比)摊滔。實際操作并不是簡單的兩種返回值澎剥。

同步loader

同步loader比較簡單励堡,無論是 return 還是 調(diào)用this.callback 都可以同步地返回轉換后的 content 內(nèi)容艇炎。

  1. 使用return
    這種比較直觀耸成,就一個普通函數(shù)叛拷,執(zhí)行完成返回一個值舌厨。例如:
function loader(source) {
  // do anything
  return source;
}
  1. 使用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;

注意幾種特殊情況:

  1. 函數(shù)中調(diào)用this.async后,return的返回值將被忽略弊攘。
  2. 函數(shù)中調(diào)用this.async后抢腐,再調(diào)用this.callback,則會將當前loader當做同步loader來處理襟交。
  3. 函數(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-loaderpitch-loader牛哺。并各自編寫一個demo

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末韭寸,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子荆隘,更是在濱河造成了極大的恐慌,老刑警劉巖赴背,帶你破解...
    沈念sama閱讀 211,948評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件椰拒,死亡現(xiàn)場離奇詭異,居然都是意外死亡凰荚,警方通過查閱死者的電腦和手機燃观,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來便瑟,“玉大人缆毁,你說我怎么就攤上這事〉酵浚” “怎么了脊框?”我有些...
    開封第一講書人閱讀 157,490評論 0 348
  • 文/不壞的土叔 我叫張陵颁督,是天一觀的道長。 經(jīng)常有香客問我浇雹,道長沉御,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,521評論 1 284
  • 正文 為了忘掉前任昭灵,我火速辦了婚禮吠裆,結果婚禮上,老公的妹妹穿的比我還像新娘烂完。我一直安慰自己试疙,他們只是感情好,可當我...
    茶點故事閱讀 65,627評論 6 386
  • 文/花漫 我一把揭開白布抠蚣。 她就那樣靜靜地躺著祝旷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪柱徙。 梳的紋絲不亂的頭發(fā)上缓屠,一...
    開封第一講書人閱讀 49,842評論 1 290
  • 那天,我揣著相機與錄音护侮,去河邊找鬼敌完。 笑死,一個胖子當著我的面吹牛羊初,可吹牛的內(nèi)容都是我干的滨溉。 我是一名探鬼主播,決...
    沈念sama閱讀 38,997評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼长赞,長吁一口氣:“原來是場噩夢啊……” “哼晦攒!你這毒婦竟也來了?” 一聲冷哼從身側響起得哆,我...
    開封第一講書人閱讀 37,741評論 0 268
  • 序言:老撾萬榮一對情侶失蹤脯颜,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后贩据,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體栋操,經(jīng)...
    沈念sama閱讀 44,203評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,534評論 2 327
  • 正文 我和宋清朗相戀三年饱亮,在試婚紗的時候發(fā)現(xiàn)自己被綠了矾芙。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,673評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡近上,死狀恐怖剔宪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤葱绒,帶...
    沈念sama閱讀 34,339評論 4 330
  • 正文 年R本政府宣布感帅,位于F島的核電站,受9級特大地震影響哈街,放射性物質(zhì)發(fā)生泄漏留瞳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,955評論 3 313
  • 文/蒙蒙 一骚秦、第九天 我趴在偏房一處隱蔽的房頂上張望她倘。 院中可真熱鬧,春花似錦作箍、人聲如沸硬梁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽荧止。三九已至,卻和暖如春阶剑,著一層夾襖步出監(jiān)牢的瞬間跃巡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評論 1 266
  • 我被黑心中介騙來泰國打工牧愁, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留素邪,地道東北人。 一個月前我還...
    沈念sama閱讀 46,394評論 2 360
  • 正文 我出身青樓猪半,卻偏偏與公主長得像兔朦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子磨确,可洞房花燭夜當晚...
    茶點故事閱讀 43,562評論 2 349

推薦閱讀更多精彩內(nèi)容

  • 使用Webpack往往離不開loader的安裝配置沽甥,手寫一個loader其實非常簡單,類似手寫一個功能函數(shù)乏奥,下面我...
    Adoins閱讀 813評論 0 2
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5摆舟? 答:HTML5是最新的HTML標準。 注意:講述HT...
    kismetajun閱讀 27,449評論 1 45
  • 編寫 Loader Loader就像是一個翻譯員邓了,能把源文件經(jīng)過轉化后輸出新的結果盏檐,并且一個文件還可以鏈式的經(jīng)過多...
    oWSQo閱讀 7,583評論 0 8
  • 本文為阮一峰大神的《ECMAScript 6 入門》的個人版提純! babel babel負責將JS高級語法轉義驶悟,...
    Devildi已被占用閱讀 1,972評論 0 4
  • 文:小 boy(滬江網(wǎng)校Web前端工程師) 本文原創(chuàng),轉載請注明作者及出處 經(jīng)常逛 webpack 官網(wǎng)的同學應該...
    iKcamp閱讀 8,008評論 4 22