Webpack babel-loader

2023-05-19 17:48 更新
This README is for babel-loader v8 + Babel v7 Check the 7.x branch for docs with Babel v6

NPM Status  codecov

此 package 允許你使用 Babel 和 webpack 轉(zhuǎn)譯 JavaScript 文件。

注意:請?jiān)?Babel Issues tracker 上報(bào)告輸出時遇到的問題。

安裝

webpack 4.x | babel-loader 8.x | babel 7.x
npm install -D babel-loader @babel/core @babel/preset-env webpack

用法

在 webpack 配置對象中,需要將 babel-loader 添加到 module 列表中,就像下面這樣:

module: {
  rules: [
    {
      test: /\.m?js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env']
        }
      }
    }
  ]
}

選項(xiàng)

你可以使用 options 屬性,來向 loader 傳遞 options 選項(xiàng):

module: {
  rules: [
    {
      test: /\.m?js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'],
          plugins: ['@babel/plugin-proposal-object-rest-spread']
        }
      }
    }
  ]
}

此 loader 也支持下面這些 loader 特有的選項(xiàng):

  • cacheDirectory:默認(rèn)值為 false。當(dāng)有設(shè)置時,指定的目錄將用來緩存 loader 的執(zhí)行結(jié)果。之后的 webpack 構(gòu)建,將會嘗試讀取緩存,來避免在每次執(zhí)行時,可能產(chǎn)生的、高性能消耗的 Babel 重新編譯過程(recompilation process)。如果設(shè)置了一個空值 ?(loader: 'babel-loader?cacheDirectory') ?或者 ?true (loader: 'babel-loader?cacheDirectory=true')?,loader 將使用默認(rèn)的緩存目錄 ?node_modules/.cache/babel-loader?,如果在任何根目錄下都沒有找到 ?node_modules? 目錄,將會降級回退到操作系統(tǒng)默認(rèn)的臨時文件目錄。
  • cacheIdentifier:默認(rèn)是由 @babel/core 版本號,babel-loader 版本號,.babelrc 文件內(nèi)容(存在的情況下),環(huán)境變量 BABEL_ENV 的值(沒有時降級到 NODE_ENV)組成的一個字符串??梢栽O(shè)置為一個自定義的值,在 identifier 改變后,來強(qiáng)制緩存失效。
  • cacheCompression:默認(rèn)值為 true。當(dāng)設(shè)置此值時,會使用 Gzip 壓縮每個 Babel transform 輸出。如果你想要退出緩存壓縮,將它設(shè)置為 false -- 如果你的項(xiàng)目中有數(shù)千個文件需要壓縮轉(zhuǎn)譯,那么設(shè)置此選項(xiàng)可能會從中收益。
  • customize: 默認(rèn)值為 ?null?。導(dǎo)出 custom 回調(diào)函數(shù)的模塊路徑,例如傳入 ?.custom()? 的 callback 函數(shù)。由于你必須創(chuàng)建一個新文件才能使用它,建議改為使用 ?.custom? 來創(chuàng)建一個包裝 loader。只有在你_必須_繼續(xù)直接使用 babel-loader 但又想自定義的情況下,才使用這項(xiàng)配置。

疑難解答

babel-loader 很慢!

確保轉(zhuǎn)譯盡可能少的文件。你可能使用 /\.m?js$/ 來匹配,這樣也許會去轉(zhuǎn)譯 node_modules 目錄或者其他不需要的源代碼。

要排除 node_modules,參考文檔中的 loaders 配置的 exclude 選項(xiàng)。

你也可以通過使用 cacheDirectory 選項(xiàng),將 babel-loader 提速至少兩倍。這會將轉(zhuǎn)譯的結(jié)果緩存到文件系統(tǒng)中。

Babel 在每個文件都插入了輔助代碼,使代碼體積過大!

Babel 對一些公共方法使用了非常小的輔助代碼,比如 _extend。默認(rèn)情況下會被添加到每一個需要它的文件中。

你可以引入 Babel runtime 作為一個獨(dú)立模塊,來避免重復(fù)引入。

下面的配置禁用了 Babel 自動對每個文件的 runtime 注入,而是引入 @babel/plugin-transform-runtime 并且使所有輔助代碼從這里引用。

更多信息請查看 文檔。

注意:你必須執(zhí)行 npm install -D @babel/plugin-transform-runtime 來把它包含到你的項(xiàng)目中,然后使用 npm install @babel/runtime 把 @babel/runtime 安裝為一個依賴。

rules: [
  // 'transform-runtime' 插件告訴 Babel
  // 要引用 runtime 來代替注入。
  {
    test: /\.m?js$/,
    exclude: /(node_modules|bower_components)/,
    use: {
      loader: 'babel-loader',
      options: {
        presets: ['@babel/preset-env'],
        plugins: ['@babel/plugin-transform-runtime']
      }
    }
  }
]

注意:transform-runtime 和自定義 polyfills (例如 Promise library)

由于 ?@babel/plugin-transform-runtime? 包含了一個 polyfill,含有自定義的 ?regenerator-runtime? 和 ?core-js?, 下面使用 webpack.ProvidePlugin 來配置 shimming 的常用方法將沒有作用:

// ...
        new webpack.ProvidePlugin({
            'Promise': 'bluebird'
        }),
// ...

下面這樣的寫法也沒有作用:

require('@babel/runtime/core-js/promise').default = require('bluebird');

var promise = new Promise;

它其實(shí)會生成下面這樣 (使用了 runtime 后):

'use strict';

var _Promise = require('@babel/runtime/core-js/promise')['default'];

require('@babel/runtime/core-js/promise')['default'] = require('bluebird');

var promise = new _Promise();

前面的 Promise library 在被覆蓋前已經(jīng)被引用和使用了。

一種可行的辦法是,在你的應(yīng)用程序中加入一個“引導(dǎo)(bootstrap)”步驟,在應(yīng)用程序開始前先覆蓋默認(rèn)的全局變量。

// bootstrap.js

require('@babel/runtime/core-js/promise').default = require('bluebird');

// ...

require('./app');

babel 的 Node.js API 已經(jīng)被移到 babel-core 中。

如果你收到這個信息,這說明你有一個已經(jīng)安裝的 babel npm package,并且在 webpack 配置中使用 loader 簡寫方式(在 webpack 2.x 版本中將不再支持這種方式):

  {
    test: /\.m?js$/,
    loader: 'babel',
  }

webpack 將嘗試讀取 babel package 而不是 babel-loader。

想要修復(fù)這個問題,你需要卸載 babel npm package,因?yàn)樗?Babel v6 中已經(jīng)被廢除。(安裝 @babel/cli 或者 @babel/core 來替代它) 在另一種場景中,如果你的依賴于 babel 而無法刪除它,可以在 webpack 配置中使用完整的 loader 名稱來解決:

  {
    test: /\.m?js$/,
    loader: 'babel-loader',
  }

排除不應(yīng)參與轉(zhuǎn)碼的庫

core-js 和 webpack/buildin 如果被 Babel 轉(zhuǎn)碼會發(fā)生錯誤。

你需要在 babel-loader 中排除它們:

{
  "loader": "babel-loader",
  "options": {
    "exclude": [
      // \\ for Windows, \/ for Mac OS and Linux
      /node_modules[\\\/]core-js/,
      /node_modules[\\\/]webpack[\\\/]buildin/,
    ],
    "presets": [
      "@babel/preset-env"
    ]
  }
}

根據(jù) webpack 部署目標(biāo)(target)的自定義配置

Webpack 支持打包成多種 部署目標(biāo) 。例如,當(dāng)需要為不同的部署目標(biāo)(例如 web 和 node)指定不同的 Babel 配置時, babel-loader 通過 Babel 的caller API 提供了 target屬性。

例如,根據(jù) webpack 的部署目標(biāo)改變傳給@babel/preset-env的 targets選項(xiàng)

// babel.config.js

module.exports = api => {
  return {
    plugins: [
      "@babel/plugin-proposal-nullish-coalescing-operator",
      "@babel/plugin-proposal-optional-chaining"
    ],
    presets: [
      [
        "@babel/preset-env",
        {
          useBuiltIns: "entry",
          // caller.target 等于 webpack 配置的 target 選項(xiàng)
          targets: api.caller(caller => caller && caller.target === "node")
            ? { node: "current" }
            : { chrome: "58", ie: "11" }
        }
      ]
    ]
  }
}

自定義 loader

babel-loader 提供了一個 loader-builder 工具函數(shù), 允許用戶為 Babel 處理過的每個文件添加自定義處理選項(xiàng)

.custom 接收一個 callback 函數(shù), 它將被調(diào)用,并傳入 loader 中的 babel 實(shí)例, 因此,此工具函數(shù)才能夠完全確保它使用與 loader 的 @babel/core 相同的實(shí)例。

如果你想自定義,但實(shí)際上某個文件又不想調(diào)用 .custom, 可以向 customize 選項(xiàng)傳入一個字符串, 此字符串指向一個導(dǎo)出 custom 回調(diào)函數(shù)的文件。

示例

// 從 "./my-custom-loader.js" 中導(dǎo)出,或者任何你想要的文件中導(dǎo)出。
module.exports = require("babel-loader").custom(babel => {
  function myPlugin() {
    return {
      visitor: {},
    };
  }

  return {
    // 傳給 loader 的選項(xiàng)。
    customOptions({ opt1, opt2, ...loader }) {
      return {
        // 獲取 loader 可能會有的自定義選項(xiàng)
        custom: { opt1, opt2 },

        // 傳入"移除了兩個自定義選項(xiàng)"后的選項(xiàng)
        loader,
      };
    },

    // 提供 Babel 的 'PartialConfig' 對象
    config(cfg) {
      if (cfg.hasFilesystemConfig()) {
        // 使用正常的配置
        return cfg.options;
      }

      return {
        ...cfg.options,
        plugins: [
          ...(cfg.options.plugins || []),

          // 在選項(xiàng)中包含自定義 plugin
          myPlugin,
        ],
      };
    },

    result(result) {
      return {
        ...result,
        code: result.code + "\n// 自定義loader生成",
      };
    },
  };
});
// 然后,在你的 webpack config 文件中
module.exports = {
  // ..
  module: {
    rules: [{
      // ...
      loader: path.join(__dirname, 'my-custom-loader.js'),
      // ...
    }]
  }
};

customOptions(options: Object): { custom: Object, loader: Object }

指定的 loader 的選項(xiàng), 從 babel-loader 選項(xiàng)中分離出自定義選項(xiàng)。

config(cfg: PartialConfig): Object

指定的 Babel 的 PartialConfig 對象, 返回應(yīng)該被傳遞給 babel.transform 的 option 對象。

result(result: Result): Result

指定的 Babel 結(jié)果對象,允許 loaders 對它進(jìn)行額外的調(diào)整。

License

MIT


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號