手寫Loader和Plugin

loader
一、loader 是什么舶担,有什么用
是 webpack 用于在編譯過程中解析各類文件格式,并輸出彬呻;
本質(zhì)上就是一個 node 模塊衣陶,通過寫一個函數(shù)來完成自動化的過程;
由此我們就可以在開發(fā)模式下闸氮,通過解析各類前端無法解析的文件格式剪况,然后將其解析后返回為對象或字符串供前端開發(fā)時使用,在 webpack 的編譯過程中自動會將我們前端項目中引用的文件格式對應(yīng)到指定 loader 解析后輸出蒲跨。
二译断、怎么寫一個自定義 loader
接下來我將寫一個非常簡單的 loader 來解析 txt 文件,它將滿足以下功能
讀取 txt 文件內(nèi)容并輸出為一個對象或悲,對象內(nèi)包括文件內(nèi)容與文件名
讀取 webpack loader 選項孙咪,將內(nèi)容中的 [name] 替換為我們選項 name 的值

   // webpack.config.js
      module.exports = {
        //...
        module: {
          rules: [
            {
              test: /\.txt$/,
              use: {
                loader: path.resolve(__dirname, './txt-loader.js'),
                options: {
                  name: 'YOLO'
                }
              }
            }
          ]
        }
      }
    // txt-loader.js
   var utils = require('loader-utils')

   module.exports = function (source) {
   const options = utils.getOptions(this)

   source = source.replace(/\[name\]/g, options.name)
     return `export default ${ JSON.stringify({
       content: source,
       filename: this.resourcePath
     }) }`
   }

    // 測試在項目中 import 的 txt 文件
    test loader output from [name]
// 前端引用
import test from '@/public/test.txt'
// 在瀏覽器中 log 出結(jié)果,因為 txt 中保存時自動換行了隆箩,所以大家可以看到存在一個換行符
{
 content: "test loader output from YOLO?"
 filename: "/Users/yanglu/Desktop/Programers/test-loader/src/public/test.txt"
}

Plugin
一该贾、Plugin 是什么,有什么用
是 webpack 用于在編譯過程中利用鉤子進(jìn)行各種自定義輸出的函數(shù)捌臊;
本質(zhì)上就是一個 node 模塊杨蛋,通過寫一個類來使用編譯暴漏出來的鉤子實現(xiàn)編譯過程的可控;
由此我們就可以在開發(fā)模式下理澎,可以通過監(jiān)聽編譯過程的各個鉤子事件來完成如釋出模版逞力,對 js、css糠爬、html 進(jìn)行壓縮寇荧、去重等各類操作,結(jié)束后釋出對應(yīng)文件等等你可以想到的任何操作
二执隧、先說點細(xì)節(jié)揩抡,再說怎么寫一個自定義 plugin
webpack 的插件簡單來說就是在函數(shù)中通過調(diào)用 webpack 執(zhí)行的鉤子來完成自動化的過程,在函數(shù)中我們通過監(jiān)聽 compiler 鉤子镀琉,并在回調(diào)中執(zhí)行我們需要做的事情峦嗤,最后調(diào)用回調(diào)中的第二個參數(shù) callback 使 webpack 繼續(xù)構(gòu)建,否則將在此處停止編譯屋摔,整個過程都是在 webpack 的整個編譯過程中利用其暴漏出的鉤子進(jìn)行的

以下是我寫的一個簡短的例子烁设,它完成了這樣的功能:

仿照 htmlWebpackPlugin 進(jìn)行模版輸出,實例化插件時傳入模版地址钓试,釋出文件名装黑,需解析參數(shù)變量即可副瀑;
解析過程中會解析 {{ key }} 中的 param,將 {{ key }} => 實例化對象中 params[key]

  // webpack 配置
      var EmitTemplatePlugin = require('./emit-template-plugin')
      plugins: [
        new EmitTemplate({
          template: './src/template/template.html',
          filename: path.resolve(__dirname, './index-emit-template.html'),
          params: {
            title: '測試啊',
            name: 'YOLO'
          }
        })
      ]
      // emit-template-plugin.js
      const fs = require('fs')

      function EmitTemplate (options) {
        this.templateDir = options.template
        this.targetDir = options.filename
        this.params = options.params
      }

      EmitTemplate.prototype.apply = function (compiler) {
        var self = this
        compiler.plugin('emit', function (compilation, callback) {
          fs.readFile(self.templateDir, (err, data) => {
            if (err) throw err
            // 匹配參數(shù)替換 html 模版中變量
            var reg = new RegExp(`{{\\s*(${Object.keys(self.params).join('|')})\\s*}}`, 'g')
            var html = data.toString().replace(reg, function (str, key, index) {
              return self.params[key]
            })

            fs.writeFile(self.targetDir, html, function () {
              console.log('模版寫入成功')
              callback()
            })
          })
        })
      }

      module.exports = EmitTemplate
      // 模版 template.html
 <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="utf-8">
          <title>{{ title }}</title>
        </head>
        <body>
          <div class="">
            {{ name }}
          </div>
        </body>
      </html>
      // 解析后的釋出文件 index-emit-template.html
      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="utf-8">
          <title>測試啊</title>
        </head>
        <body>
          <div class="">
            YOLO
          </div>
        </body>
      </html>

上面的寫法是 webpack2 或 webpack3 調(diào)用鉤子的方法恋谭,在 4 中已變?yōu)?/p>

    compilation.hooks.compile.tap([compiler hooks event], (compilation, callback) => {

    })
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末糠睡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子疚颊,更是在濱河造成了極大的恐慌铜幽,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,509評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件串稀,死亡現(xiàn)場離奇詭異除抛,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)母截,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,806評論 3 394
  • 文/潘曉璐 我一進(jìn)店門到忽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人清寇,你說我怎么就攤上這事喘漏。” “怎么了华烟?”我有些...
    開封第一講書人閱讀 163,875評論 0 354
  • 文/不壞的土叔 我叫張陵翩迈,是天一觀的道長。 經(jīng)常有香客問我盔夜,道長负饲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,441評論 1 293
  • 正文 為了忘掉前任喂链,我火速辦了婚禮返十,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘椭微。我一直安慰自己洞坑,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,488評論 6 392
  • 文/花漫 我一把揭開白布蝇率。 她就那樣靜靜地躺著迟杂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪本慕。 梳的紋絲不亂的頭發(fā)上排拷,一...
    開封第一講書人閱讀 51,365評論 1 302
  • 那天,我揣著相機(jī)與錄音间狂,去河邊找鬼攻泼。 笑死火架,一個胖子當(dāng)著我的面吹牛鉴象,可吹牛的內(nèi)容都是我干的忙菠。 我是一名探鬼主播,決...
    沈念sama閱讀 40,190評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼纺弊,長吁一口氣:“原來是場噩夢啊……” “哼牛欢!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起淆游,我...
    開封第一講書人閱讀 39,062評論 0 276
  • 序言:老撾萬榮一對情侶失蹤傍睹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后犹菱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拾稳,經(jīng)...
    沈念sama閱讀 45,500評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,706評論 3 335
  • 正文 我和宋清朗相戀三年腊脱,在試婚紗的時候發(fā)現(xiàn)自己被綠了访得。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,834評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡陕凹,死狀恐怖悍抑,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情杜耙,我是刑警寧澤搜骡,帶...
    沈念sama閱讀 35,559評論 5 345
  • 正文 年R本政府宣布佑女,位于F島的核電站,受9級特大地震影響团驱,放射性物質(zhì)發(fā)生泄漏簸呈。R本人自食惡果不足惜店茶,卻給世界環(huán)境...
    茶點故事閱讀 41,167評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望贩幻。 院中可真熱鬧,春花似錦丛楚、人聲如沸族壳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,779評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至拢操,卻和暖如春锦亦,著一層夾襖步出監(jiān)牢的瞬間令境,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,912評論 1 269
  • 我被黑心中介騙來泰國打工舔庶, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人惕橙。 一個月前我還...
    沈念sama閱讀 47,958評論 2 370
  • 正文 我出身青樓瞧甩,卻偏偏與公主長得像弥鹦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子惶凝,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,779評論 2 354

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