できない.dev

Babel の .babelrc が読み込まれず設定が反映されない

.babelrc は package.json が見つかった時点で探索が止まるファイル相対設定のため、別パッケージのファイルには適用されない。
プロジェクト全体に効かせたいときは babel.config.json をルートに置く。

公開: 更新:

症状できない
npx babel packages/app/src/index.js
const greet = name => `hello ${name}`;
console.log(greet("babel"));

2026-09-13 に node:20(Node.js 20.20.2 / npm 10.8.2) で実際に打って取った出力。検証環境の詳細

要約

.babelrc を置いたのにプリセットやプラグインが効かないのは、.babelrc が「ファイル相対設定」で、探索が package.json のあるディレクトリで止まるためだ。
公式ドキュメントは「.babelrc files only apply to files within their own package」と明記している。
つまりモノレポのルートに置いた .babelrc は、packages/* の中のファイルには届かない。

プロジェクト全体に効かせたい設定は、ルートの babel.config.json に書く。

// babel.config.json(リポジトリのルート)
{
  "presets": ["@babel/preset-env"]
}

実行例

ルートに .babelrc を置いたまま packages/app/src/index.js を変換すると、アロー関数もテンプレートリテラルもそのまま出力され、BABEL_SHOW_CONFIG_FOR の表示にも programmatic options from @babel/cli しか並ばず .babelrc は読み込まれていなかった。
同じファイルを babel.config.json に改名しただけで、"use strict" 付きの function と concat 呼び出しに変換されている。

$ npx babel packages/app/src/index.js
const greet = name => `hello ${name}`;
console.log(greet("babel"));
$ BABEL_SHOW_CONFIG_FOR=packages/app/src/index.js npx babel packages/app/src/index.js
Babel configs on "/tmp/tmp.pSPWEgbDDM/packages/app/src/index.js" (ascending priority):
programmatic options from @babel/cli
{
  "sourceFileName": "packages/app/src/index.js",
  "caller": {
    "name": "@babel/cli",
    "supportsStaticESM": false,
    "supportsDynamicImport": false,
    "supportsExportNamespaceFrom": false
  },
  "filename": "packages/app/src/index.js"
}
-----End Babel configs-----
const greet = name => `hello ${name}`;
console.log(greet("babel"));
$ mv .babelrc babel.config.json
$ npx babel packages/app/src/index.js
"use strict";
 
var greet = function greet(name) {
  return "hello ".concat(name);
};
console.log(greet("babel"));

— 2026-09-13 時点の出力

検証環境Node.js 20.20.2 / npm 10.8.2 / Python 3.11.2 / 2026-09-13 検証(ほか 1 件)
検証日
実行環境
node:20 Debian GNU/Linux 12 (bookworm)
バージョン
  • Node.js 20.20.2
  • npm 10.8.2
  • Python 3.11.2
  • Git 2.39.5

この記事の「実行例」は、上記の環境で実際にコマンドを実行して得られた出力をそのまま掲載しています。 再現手順はリポジトリの検証スクリプトとして管理し、定期的に再実行して出力を更新しています。

解決策

1. プロジェクト全体の設定は babel.config.json にする

babel.config.json(または babel.config.js)はプロジェクト全体の設定で、パッケージ境界を越えて適用される。node_modules の中のファイルを変換したい場合も、この形式が必要だ。

mv .babelrc babel.config.json

2. サブパッケージの .babelrc を明示的に許可する

モノレポで、パッケージごとに .babelrc を持たせたいときは、ルートの babel.config.json で babelrcRoots を指定する。

// babel.config.json
{
  "babelrcRoots": [".", "packages/*"]
}

これを書かない限り、Babel の root 以外のパッケージにある .babelrc は無視される。

3. サブディレクトリから実行するなら rootMode を上向きにする

packages/app の中で Babel を動かすと、その場所が root と見なされてルートの babel.config.json が見つからない。rootMode を upward にすると、上位ディレクトリを遡って設定を探す。

rootMode は Babel を呼び出す側に渡すオプションで、.babelrc や babel.config.json の中には書けない。
設定ファイルに書くと ConfigError: .rootMode is only allowed in root programmatic options で止まる。
CLI なら引数で、webpack なら babel-loader のオプションで指定する。

# packages/app の中で実行する
npx babel --root-mode upward src -d lib
// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        loader: "babel-loader",
        options: { rootMode: "upward" },
      },
    ],
  },
};

upward-optional にすると、見つからなかった場合に現在のディレクトリを root として扱う。

4. 実際に適用された設定を表示して確かめる

推測で直す前に、対象ファイルへ最終的に適用された設定を出力させる。

BABEL_SHOW_CONFIG_FOR=src/index.js npx babel src/index.js

読み込まれた設定ファイルのパスと、マージ後のプリセット・プラグインが表示される。
期待した .babelrc がここに出てこなければ、探索範囲の問題だと確定できる。

よくある原因

  1. モノレポのルートに .babelrc を置いている: packages/app/src/index.js を変換するとき、Babel は packages/app/package.json を見つけた時点で探索をやめる。
    ルートの .babelrc はそもそも読まれない。
  2. node_modules の中を変換しようとしている: 依存パッケージには自身の package.json があるので、こちらの .babelrc は適用されない。
    Babel 6 で起きていた「.babelrc が依存パッケージにまで効いてしまう」問題を防ぐための仕様変更である。
  3. 実行時の作業ディレクトリがルートではない: babel.config.json は Babel の「root」(既定では cwd)から探される。
    サブディレクトリで npm run build を叩くと、ルートの設定が見つからない。
  4. 設定ファイルが複数ある: babel.config.json と .babelrc の両方があると、どちらが効いているのか読み違えやすい。

この手順で直った?