JS每日一題:Webpack如何實現一個Loader?

20190329期

如何實現一個Loader?node

咱們在上幾節有講過loader,今天咱們來深刻了解它們,最暴力的方式莫過於動手實現它們webpack

好了,回到正題, 先來回顧一下loadergit

loader定義: 用於對模塊的源代碼進行轉換。loader 可使你在 import 或"加載"模塊時預處理文件

簡單使用github

module.exports = {
  //...
  module: {
    rules: [
      {
        test: /\.js$/,
        use: [
          {
            // loader 是導出爲一個a函數的 node 模塊。該函數在 loader 轉換資源的時候調用
            // 給定的函數將調用 loader API,並經過 this 上下文訪問
            loader: path.resolve('loader.js'),
            options: {/* ... */}
          }
        ]
      }
    ]
  }
};

回顧了loader的定義及簡單使用後,咱們再來分析一下實現loader的思路web

  • 單一職責,一個loader只作一件事
  • 鏈式組合,鏈中的每一個 loader 會將轉換應用在已處理過的資源上
  • 模塊化,是導出爲一個函數的 node 模塊
  • 參數合併,loader 能夠經過 options 對象配置

基於上面分析的幾點,咱們開始動手api

// 這個就是一個最簡單loader,
// 若是咱們的loader有依賴其它模塊,也得以module的寫法將在在頂部引入
import fs from 'fs';
export default function(source){
    return source
}

咱們發現上面直接使用了return,是由於是同步類的loader且返回的內容惟一,若是你但願你的loader支持鏈式調用,將結果返給下一個loader繼續使用,這時候就須要用webpack提供的api緩存

這裏咱們簡單看一下this.callback的定義,一個能夠同步或者異步調用的能夠返回多個結果的函數。預期的參數是less

this.callback(
  err: Error | null,
  content: string | Buffer,
  sourceMap?: SourceMap,
  meta?: any
)
// loader-utils 它提供了不少有用的工具
// 最經常使用的一個就是獲取傳入 loader 的 options
import { getOptions } from 'loader-utils';
export default function(source, other) {
  const options = getOptions(this)    
  // do whatever you want
  // ...
  this.callback(null, source, other)
}

手寫一個loader對沒有研究過的聽上去好像有點難,事實上, 掌握上面所介紹的內容及思想,就能夠開始寫一個簡單的 Loader 了, 咱們再來用簡單的代碼綏一下loader究竟是什麼?異步

// 首先loader它是一個node模塊,這很好理解
export const lessToCss = function(source, other) {
    // source 就是你即將要轉換的文件源
    // TODO
    // 將轉換好的文件源流轉至一個管道
    this.callback(null, source, other)
}
讓你的loader更好用

loader api中有幾個好用的傢伙這裏就順便帶一下async

  • this.cacheable() 從提升執行效率上,如何處理利用緩存是極其重要的, webpack 中this.cacheable就能夠輕鬆將loader緩存了
  • this.async() 當一個loader無依賴時,咱們應該異步的去返回結果
案例分析

下方貼上less-loader的源碼,代碼很簡潔,結合上方咱們所分析的,也很容易理解

import processResult from './processResult';
const render = pify(less.render.bind(less));

function lessLoader(source) {
  const loaderContext = this;
  const options = getOptions(loaderContext);
  const done = loaderContext.async();
  const isSync = typeof done !== 'function';

  if (isSync) {
    throw new Error(
      'Synchronous compilation is not supported anymore. See https://github.com/webpack-contrib/less-loader/issues/84'
    );
  }
  processResult(loaderContext, render(source, options));
}

總結

  • loader是一個node模塊
  • 編寫loader時要遵循單一原則,每一個loader只作一種"轉義"工做
  • webpack爲咱們提供了豐富的loader api
  • webpack爲咱們還提供了工具函數集——loader-utils

關於JS每日一題

JS每日一題能夠當作是一個語音答題社區
天天利用碎片時間採用60秒內的語音形式來完成當天的考題
羣主在第二天0點推送當天的參考答案

  • 注 毫不僅限於完成當天任務,更可能是查漏補缺,學習羣內其它同窗優秀的答題思路

點擊加入答題

相關文章
相關標籤/搜索