跳到主要內容

組態檔案

組態檔案類型

Babel 有兩種並行的組態檔案格式,它們可以一起使用,或獨立使用。

歷史
版本變更
v7.21.0支援 .babelrc.ctsbabel.config.cts(實驗性)
v7.8.0支援 .babelrc.mjsbabel.config.mjs
v7.7.0支援 .babelrc.json.babelrc.cjsbabel.config.jsonbabel.config.cjs
  • 專案範圍設定
    • babel.config.* 檔案,副檔名為:.json.js.cjs.mjs.cts
  • 檔案相對設定
    • .babelrc.* 檔案,副檔名為:.json.js.cjs.mjs.cts
    • .babelrc 檔案,無副檔名。
    • package.json 檔案,有 "babel" 鍵。

專案範圍設定

Babel 7.x 的新功能,Babel 有個概念叫 "根目錄",預設為目前的作業目錄。對於專案範圍設定,Babel 會自動在這個根目錄搜尋 babel.config.json 檔案,或使用 支援的副檔名 的等效檔案。或者,使用者可以使用明確的 "configFile" 值來覆寫預設設定檔搜尋行為。

由於專案範圍設定檔與設定檔的實際位置分開,因此它們非常適合用於必須廣泛套用的設定,甚至允許外掛程式和預設值輕鬆套用於 node_modules 或符號連結套件中的檔案,這些檔案在 Babel 6.x 中通常很難設定。

這個專案範圍設定的主要缺點是,由於它依賴於作業目錄,因此如果作業目錄不是單一儲存庫的根目錄,在單一儲存庫中使用它可能會比較麻煩。請參閱 單一儲存庫 文件,了解如何在這種情況下使用設定檔的範例。

專案範圍的設定也可以透過將 「configFile」 設定為 false 來停用。

檔案相對應設定

Babel 會載入 .babelrc.json 檔案,或使用 支援的副檔名 的等效檔案,方法是從正在編譯的 「filename」 開始,向上搜尋目錄結構(受以下警告限制)。這很強大,因為它允許您為套件的子區塊建立獨立的設定。檔案相對應設定也會 合併 到專案範圍設定值之上,這使得它們可能對特定覆寫很有用,儘管這也可以透過 「overrides」 來完成。

在使用檔案相對應設定時,有幾個邊界狀況需要考量

  • 一旦找到包含 package.json 的目錄,搜尋就會停止,因此相對應設定只會套用在單一套件內。
  • 正在編譯的 「filename」 必須在 「babelrcRoots」 套件內,否則將完全略過搜尋。

這些警告表示

  • .babelrc.json 檔案套用於它們自己的套件內的檔案
  • 除非您使用 「babelrcRoots」 選擇加入,否則會忽略非 Babel「根目錄」套件中的 .babelrc.json 檔案。

請參閱 單一儲存庫 文件,以進一步討論如何設定具有許多套件的單一儲存庫。檔案相對應設定也可以透過將 「babelrc」 設定為 false 來停用。

6.x 與 7.x .babelrc 載入

來自 Babel 6.x 的使用者可能會遇到這兩個在 Babel 7.x 中新增的邊緣案例。這兩個限制新增的目的,是為了解決 Babel 6.x 中常見的陷阱

  • .babelrc 檔案意外套用至 node_modules 相依性
  • 當人們預期 .babelrc 檔案會像一般相依性一樣運作時,它無法套用至符號連結的 node_modules
  • 即使 node_modules 相依性.babelrc 檔案通常並未安裝,甚至可能在編譯檔案的 Babel 版本中無效,它仍會被偵測到

這些案例主要會對使用單一儲存庫結構的使用者造成問題,因為如果你有

.babelrc
packages/
mod1/
package.json
src/index.js
mod2/
package.json
src/index.js

現在會完全忽略設定檔,因為它跨越封裝邊界

一種替代方法是在每個使用 "extends" 的子封裝中建立一個 .babelrc,如下所示

.babelrc.json
{ "extends": "../../.babelrc" }

不幸的是,這種方法可能會有點重複,而且根據 Babel 的使用方式,可能需要設定 "babelrcRoots"

有鑑於此,將 .babelrc 重新命名為 專案範圍的「babel.config.json」 可能會比較理想。如同上述專案範圍區段所述,這可能需要明確設定 "configFile",因為如果工作目錄不正確,Babel 將找不到設定檔

支援的檔案副檔名

Babel 可以使用 Node.js 本機支援的任何檔案副檔名進行設定,如 設定檔類型 區段所述

  • babel.config.json.babelrc.json 會以 JSON5 解析,且應該包含符合 Babel 接受的 選項 格式的物件。它們自 v7.7.0 起獲得支援

    建議在任何情況下都使用此檔案類型:如果您有複雜的組態,在建置時會根據條件或以其他方式計算,則 JS 組態檔會很方便。不過,缺點是 JS 組態較難靜態分析,因此會對快取性、程式碼檢查、IDE 自動完成等產生負面影響。由於 babel.config.json.babelrc.json 是靜態 JSON 檔案,因此允許其他使用 Babel 的工具(例如打包器)安全快取 Babel 的結果,這可能會大幅提升建置效能。

  • babel.config.cjs.babelrc.cjs 允許您使用 module.exports 將組態定義為 CommonJS。它們自 v7.7.0 起受到支援。

  • babel.config.mjs.babelrc.mjs 使用原生 ECMAScript 模組。它們受到 Node.js 13.2+(或透過 --experimental-modules 旗標使用的較舊版本)支援。請記住,原生 ECMAScript 模組是非同步的(這就是為什麼 import() 始終傳回 Promise 的原因!):因此,在同步呼叫 Babel 時,.mjs 組態檔會擲回例外。它們自 v7.8.0 起受到支援。

  • 當您的 package.json 檔案包含 "type": "module" 選項時,babel.config.js.babelrc.js 的行為與 .mjs 等效項相同,否則它們與 .cjs 檔案完全相同。

  • babel.config.cts.babelrc.cts 允許您將組態定義為 Typescript + CommonJS。您必須安裝 @babel/preset-typescript,或使用 ts-node 執行 Babel。

    備註

    🚧 此功能為實驗性質。目前尚無法使用 babel.config.tsbabel.config.mts 檔案,需待 Node.js ESM 載入器 API 穩定後才能使用。

JavaScript 組態檔案可以匯出物件,或一個呼叫後會傳回產生組態的函式。回傳函式的組態會獲得一些特殊權限,因為它們可以存取 Babel 本身公開的 API。有關更多資訊,請參閱 組態函式 API

備註

基於相容性考量,.babelrc.babelrc.json 的別名。

單一儲存庫

單一儲存庫結構的儲存庫通常包含許多套件,這表示它們經常會遇到 檔案相關組態 和一般組態檔案載入中提到的注意事項。本節旨在協助使用者了解如何處理單一儲存庫組態。

對於單一儲存庫設定,要了解的核心概念是 Babel 將您的工作目錄視為其邏輯 「根目錄」,如果您想要在特定子套件中執行 Babel 工具,而不讓 Babel 套用至整個儲存庫,這就會造成問題。

另外,決定是否要使用 .babelrc.json 檔案或僅使用一個集中式的 babel.config.json 也很重要。 .babelrc.json 檔案不再是 Babel 6 中特定子資料夾設定的必要條件,因此在 Babel 7 中通常不需要使用,而是偏好 babel.config.json

根目錄 babel.config.json 檔案

任何 monorepo 結構的第一步應該是建立一個 babel.config.json 檔案在儲存庫根目錄。這會建立 Babel 儲存庫基本目錄的核心概念。即使您想使用 .babelrc.json 檔案設定每個獨立套件,但將其作為儲存庫層級選項的位置仍然很重要。

您通常可以將所有儲存庫設定都放在根目錄 babel.config.json 中。透過 "overrides",您可以輕鬆指定僅套用於儲存庫特定子資料夾的設定,這通常比在儲存庫中建立許多 .babelrc.json 檔案更容易遵循。

您可能會遇到的第一個問題是,預設情況下,Babel 預期從設定為其 "root" 的目錄載入 babel.config.json 檔案,這表示如果您建立一個 babel.config.json,但在個別套件中執行 Babel,例如

Shell
cd packages/some-package;
babel src -d dist

在該情況下 Babel 使用的 "root" 不是 monorepo 根目錄,而且它將無法找到 babel.config.json 檔案。

如果所有建置指令碼都相對於儲存庫根目錄執行,則應已運作,但如果從子套件內執行 Babel 編譯程序,則需要告訴 Babel 到哪裡尋找設定檔。有幾種方法可以做到這一點,但建議的方法是使用具有「upward」的「rootMode」選項,這將使 Babel 從工作目錄向上搜尋,尋找您的「babel.config.json」檔案,並將其位置用作「root」值。

測試您的設定檔是否已偵測到的其中一種有用的方法是在其中放置「console.log()」呼叫,如果它是「babel.config.json」JavaScript 檔案:日誌將在 Babel 首次載入時執行。

設定這個值的方式因專案而異,但以下是一些範例

CLI

Shell
babel --root-mode upward src -d lib

@babel/register

JavaScript
require("@babel/register")({
rootMode: "upward",
});

Webpack

webpack.config.js
module: {
rules: [
{
loader: "babel-loader",
options: {
rootMode: "upward",
},
},
];
}

Jest

Jest 通常安裝在單一儲存庫的根目錄,可能不需要設定,但如果每個套件都安裝,則不幸地設定可能會更複雜。

主要部分是建立一個自訂 jest 轉換器檔案,將「babel-jest」的預設行為包裝起來以設定選項,例如

wrapper.js
module.exports = require("babel-jest").default.createTransformer({
rootMode: "upward",
});

並將其儲存在某個地方,然後在 Jest 選項中使用該檔案取代「babel-jest」,透過「轉換選項」

jest.config.js
"transform": {
"^.+\\.jsx?$": "./path/to/wrapper.js"
},

因此,所有 JS 檔案都將使用啟用選項的「babel-jest」版本處理。

備註

使用 babel-jest < 27 時,您必須省略 .default 部分:require("babel-jest").createTransformer({ ...

其他

有許多工具,但核心是如果工作目錄尚未為單一儲存庫根目錄,則需要啟用 rootMode 選項。

子套件 .babelrc.json 檔案

類似於 babel.config.json 檔案需要在 「根目錄」 的方式,.babelrc.json 檔案預設必須在根目錄套件中。這表示,工作目錄影響 babel.config.json 載入的方式,也影響 .babelrc.json 載入的方式。

假設您已正確載入 babel.config.json 檔案,如上所述,Babel 將只會處理該根目錄套件(而非子套件)中的 .babelrc.json 檔案,因此例如

package.json
babel.config.js
packages/
mod/
package.json
.babelrc.json
index.js

編譯 packages/mod/index.js 檔案不會載入 packages/mod/.babelrc.json,因為此 .babelrc.json 在子套件中,而非根目錄套件中。

若要啟用處理該 .babelrc.json,您會想要在 babel.config.json 檔案中使用 「babelrcRoots」 選項,以執行

JavaScript
babelrcRoots: [
".",
"packages/*",
],

這樣一來,Babel 會將所有 packages/* 套件視為允許載入 .babelrc.json 檔案,以及原始儲存庫根目錄。

設定函式 API

JS 組態檔可以匯出一個函式,此函式將傳遞組態函式 API

JavaScript
module.exports = function(api) {
return {};
};

api 物件公開了 Babel 本身從其索引模組公開的所有內容,以及組態檔特定的 API

api.version

類型:字串

正在載入組態檔的 Babel 版本的版本字串。

api.cache

JS 組態很棒,因為它們可以即時運算組態,但缺點是它讓快取變得更困難。Babel 希望避免在每次編譯檔案時重新執行組態函式,因為這樣它還需要重新執行該組態中引用的任何外掛程式和預設函式。

為避免這種情況,Babel 希望組態函式的使用者告訴它如何在組態檔中管理快取。

  • api.cache.forever() - 永久快取已運算的組態,且不再呼叫函式。
  • api.cache.never() - 不要快取此組態,且每次都重新執行函式。
  • api.cache.using(() => process.env.NODE_ENV) - 基於 NODE_ENV 的值快取。任何時候 using 回呼傳回的值與預期的值不同,整體組態函式將再次被呼叫,且新的項目將被加入快取中。
  • api.cache.invalidate(() => process.env.NODE_ENV) - 基於 NODE_ENV 的值快取。任何時候 using 回呼傳回的值與預期的值不同,整體組態函式將再次被呼叫,且快取中的所有項目將被結果取代。
  • api.cache(true) - 與 api.cache.forever() 相同
  • api.cache(false) - 與 api.cache.never() 相同

由於實際的回呼結果用於檢查快取項目是否有效,因此建議

  • 回呼應小且無副作用。
  • 回呼應回傳範圍最小的值。例如,上述的 .using(() => process.env.NODE_ENV) 用法並非理想,因為它會根據偵測到的 NODE_ENV 值產生未知數量的快取項目。較安全的作法是 .using(() => process.env.NODE_ENV === "development"),因為快取項目只能是 truefalse

api.env(...)

由於 NODE_ENV 是切換行為的常見方式,因此 Babel 也包含專門用於此目的的 API 函式。此 API 用於快速檢查 Babel 已載入的 "envName",如果沒有設定其他優先環境,則會考量 NODE_ENV

它有幾種不同的形式

  • 如果 envName === "production",則 api.env("production") 會回傳 true
  • 如果 ["development", "test"].includes(envName),則 api.env(["development", "test"]) 會回傳 true
  • api.env() 會回傳目前的 envName 字串。
  • 如果 env 以 "test-" 開頭,則 api.env(envName => envName.startsWith("test-")) 會回傳 true
備註

此函式在內部使用上述提到的 api.cache,以確保 Babel 知道此組建依賴於特定的 envName。您不應將它與 api.cache.forever()api.cache.never() 一起使用。

api.caller(cb)

此 API 用於存取已傳遞給 Babel 的 caller 資料。由於許多 Babel 實例可能在同一個程序中執行,且具有不同的 caller 值,因此此 API 旨在自動設定 api.cache,就像 api.env() 所做的一樣。

caller 值可用作回呼函式的第一個參數。最適合用於

JavaScript
function isBabelRegister(caller) {
return !!(caller && caller.name === "@babel/register");
}

module.exports = function(api) {
const isRegister = api.caller(isBabelRegister);

return {
// ...
};
};

根據特定環境切換組態行為。

api.assertVersion(range)

雖然 api.version 通常很有用,但有時僅宣告您的版本就很棒。此 API 提供一個簡單的方法來執行此操作

JavaScript
module.exports = function(api) {
api.assertVersion("^7.2");

return {
// ...
};
};