loader的原理探究

前言

loader幾乎是webpack配置必備,但是我們用它的時(shí)候有沒有想過它的原理到底是怎么回事呢喊式?今天就讓我們來探究一下它的原理吧。

loader的作用

在探究原理之前萧朝,我們先來回顧一下常用的loader與及相關(guān)的作用岔留。

如處理css文件的
style-loader, css-loader, sass-loader

module:{
  rules: [
    {
        test: /\.css$/,
        use: ['style-loader', 'css-loader', 'sass-loader']
      }
  ]
}

loade執(zhí)行順序是從右往左執(zhí)行的。至于為什么是從右到左執(zhí)行而不是從左到右检柬?因?yàn)閣ebpack選擇了compose這樣的函數(shù)式編程方式献联,而從左到右則是pipe式編程。

所以上面例子的執(zhí)行順序是遇到.scss的文件就先經(jīng)過sass-loader 處理再到 css-loader 再到style-loader何址,我們可以猜測到寫的scss文件經(jīng)過處理得到css字符串里逆,再給css-loader序列化處理,最后給style-loader處理創(chuàng)建style標(biāo)簽插入到html

所以我們可以從這些現(xiàn)象就可以猜出來loader其實(shí)就像一個(gè)函數(shù)用爪,有參數(shù)輸入原押,經(jīng)過處理,然后將處理好的結(jié)果輸出偎血。

可以打開webpack官網(wǎng)loader部分https://webpack.js.org/api/loaders/诸衔,這里詳細(xì)指出了如何寫一個(gè)loader。

如寫一個(gè) sync-loader.js

module.exports = function(content, map, meta) {
  return someSyncOperation(content);
};

最后導(dǎo)出一個(gè)函數(shù)颇玷,這個(gè)函數(shù)有幾個(gè)參數(shù)笨农,其中主要用到的就是content這個(gè)參數(shù),它表示讀取到的對應(yīng)的文件的源碼內(nèi)容亚隙,類型可以是string 也可以是buffer磁餐。我們就可以在這個(gè)方法里面對這些源碼進(jìn)行操作了。

laoder實(shí)戰(zhàn)

弄清楚原理之后阿弃,我們自己手寫3個(gè)loader,創(chuàng)建src/myLoaders目錄
創(chuàng)建 my-sass-loader.js羞延、 my-css-loader.js渣淳、 my-style-loader.js,


image.png

再配置好webpack.config.js如下

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
    mode: 'development',
    entry: {
        index: './src/index.js'
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'
    },
    resolveLoader: {
        modules: ['node_modules', './src/myLoaders'],
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            },
            {
                test: /\.scss$/,
                use: ['my-style-loader', 'my-css-loader', 'my-sass-loader']
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin(), // 輸出html模板
        new CleanWebpackPlugin(), // 清除dist目錄
    ]
}

注意配置中配置了resolveLoader來自定義loader的存放目錄的

 resolveLoader: {
        modules: ['node_modules', './src/myLoaders'],
    }

和scss 的loader配置改為了我們自己寫的loader

{
    test: /\.scss$/,
    use: ['my-style-loader', 'my-css-loader', 'my-sass-loader']
}

配置好之后伴箩,分別寫這三個(gè)loader要做的事情入愧,
首先是my-sass-loader, 利用sass的api對scss文件內(nèi)容進(jìn)行編譯

const sass = require('sass')
module.exports = function(content) {
    const result = sass.renderSync({
        data: content
    })
    return result.css
}

其次是my-css-loader, 對編譯后的文件進(jìn)行序列化

module.exports = function(content) {
    return JSON.stringify(content)
}

最后是my-style-loader, 對css字符串進(jìn)行創(chuàng)建style標(biāo)簽并插入到head中

module.exports = function(content) {
    return `
    const style = document.createElement('style');
    style.setAttribute('id', 'my-style-loader');
    style.innerHTML = ${content};
    document.head.appendChild(style);
    `
}

為了查看效果,我額外加了一句 style.setAttribute('id', 'my-style-loader');

index.scss代碼:

body {
    background: red;
    div {
        background: blue;
        color: #fff;
    }
}

寫完了嗤谚,npm run dev


image.png

打開dist/index.html查看效果


image.png

ok, 沒問題棺蛛,自己實(shí)現(xiàn)了三個(gè)loader。有人問為什么要三個(gè)巩步?一個(gè)不行嗎旁赊?其實(shí)一個(gè)也可以的,但是這樣子的寫法不符合函數(shù)式編程的規(guī)范椅野,不符合官方提倡的寫法终畅。官方要求一個(gè)loader只做一件事籍胯。這樣子函數(shù)會(huì)更加純粹,純粹的函數(shù)對于可維護(hù)性离福、可擴(kuò)展性杖狼、可重構(gòu)性大大有利,這才是體現(xiàn)一個(gè)程序員的內(nèi)涵的地方妖爷。否則你養(yǎng)成了經(jīng)常寫一坨偶合代碼的習(xí)慣將會(huì)影響日后的成長蝶涩。

如果要獲取參數(shù)怎么辦?

在loader函數(shù)內(nèi)通過this.query獲刃跏丁绿聘;而且因?yàn)橐褂胻his ,所以笋除,導(dǎo)出的函數(shù)必須是module.exports = function(){}, 不能是箭頭函數(shù)斜友。

 console.log(this.query)

如果要返回多個(gè)結(jié)果怎么辦?

可以用 this.callback

this.callback(
  err: Error | null,
  content: string | Buffer,
  sourceMap?: SourceMap,
  meta?: any
);

如果要返回異步結(jié)果呢垃它?

以上都是同步執(zhí)行返回loader的處理的結(jié)果鲜屏,同理,業(yè)務(wù)中可能會(huì)有異步處理的結(jié)果国拇,就用this.async洛史,如下

module.exports = function(content) {
  const callback = this.async();
  setTimeout(() => {
    callback(content)
  }, 1000) 
}

總結(jié)

  • loader就是一個(gè)必須有返回值(String | Buffer)的函數(shù)
  • loader函數(shù)對源文件進(jìn)行增刪改處理,將處理好的結(jié)果返回給webpack酱吝。
  • loader不能是箭頭函數(shù)也殖,因?yàn)閮?nèi)部可以采用this
  • loader支持同步異步、返回結(jié)果
  • loader的參數(shù)通過this.query獲取
  • resolveLoaders可以配置存放loader的路徑

以上是我看法务热,如有不對請留言討論忆嗜,謝謝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末崎岂,一起剝皮案震驚了整個(gè)濱河市捆毫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌冲甘,老刑警劉巖绩卤,帶你破解...
    沈念sama閱讀 212,222評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異江醇,居然都是意外死亡濒憋,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,455評論 3 385
  • 文/潘曉璐 我一進(jìn)店門陶夜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來凛驮,“玉大人,你說我怎么就攤上這事律适》茫” “怎么了遏插?”我有些...
    開封第一講書人閱讀 157,720評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長纠修。 經(jīng)常有香客問我胳嘲,道長,這世上最難降的妖魔是什么扣草? 我笑而不...
    開封第一講書人閱讀 56,568評論 1 284
  • 正文 為了忘掉前任了牛,我火速辦了婚禮,結(jié)果婚禮上辰妙,老公的妹妹穿的比我還像新娘鹰祸。我一直安慰自己,他們只是感情好密浑,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,696評論 6 386
  • 文/花漫 我一把揭開白布蛙婴。 她就那樣靜靜地躺著,像睡著了一般尔破。 火紅的嫁衣襯著肌膚如雪街图。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,879評論 1 290
  • 那天懒构,我揣著相機(jī)與錄音餐济,去河邊找鬼。 笑死胆剧,一個(gè)胖子當(dāng)著我的面吹牛絮姆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播秩霍,決...
    沈念sama閱讀 39,028評論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼篙悯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了铃绒?” 一聲冷哼從身側(cè)響起辕近,我...
    開封第一講書人閱讀 37,773評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎匿垄,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體归粉,經(jīng)...
    沈念sama閱讀 44,220評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡椿疗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,550評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了糠悼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片届榄。...
    茶點(diǎn)故事閱讀 38,697評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖倔喂,靈堂內(nèi)的尸體忽然破棺而出铝条,到底是詐尸還是另有隱情靖苇,我是刑警寧澤,帶...
    沈念sama閱讀 34,360評論 4 332
  • 正文 年R本政府宣布班缰,位于F島的核電站贤壁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏埠忘。R本人自食惡果不足惜脾拆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,002評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望莹妒。 院中可真熱鬧名船,春花似錦、人聲如沸旨怠。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鉴腻。三九已至迷扇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間拘哨,已是汗流浹背谋梭。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留倦青,地道東北人瓮床。 一個(gè)月前我還...
    沈念sama閱讀 46,433評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像产镐,于是被迫代替她去往敵國和親隘庄。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,587評論 2 350

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