できない.dev

Babel「Support for the experimental syntax 'jsx' isn't currently enabled」の原因と直し方

experimental syntax 'jsx' isn't currently enabled は、@babel/preset-react を presets に登録すれば直る。
インストールしただけで presets に足していないと同じエラーになる。

公開: 更新:

症状できない · exit 1
npx babel src/App.js
…
SyntaxError: /tmp/tmp.dWHFTMhqmh/src/App.js: Support for the experimental syntax 'jsx' isn't currently enabled (2:10):
  1 | export default function App() {
> 2 |   return <div className="app">hello</div>;
解決後できた · exit 0
npx babel src/App.js
…
  return /*#__PURE__*/React.createElement("div", {
    className: "app"
  }, "hello");
}

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

要約

Support for the experimental syntax 'jsx' isn't currently enabled は、Babel が <div /> のような JSX を JavaScript の構文として解釈できないときに出る。
Babel は既定では JSX を知らないので、構文プラグインを含む @babel/preset-react を明示的に読ませる必要がある。

npm i -D @babel/preset-react
// babel.config.json
{
  "presets": ["@babel/preset-env", "@babel/preset-react"]
}

実行例

実際に上記の手順を node:20 で動かすと、@babel/preset-env だけの設定では JSX を含むファイルが終了コード 1 の構文エラーで止まり、@babel/preset-react を presets に登録すると変換が通る。BABEL_SHOW_CONFIG_FOR を付けると、読み込まれた設定に両方のプリセットが並んでいることも確かめられる。

$ npx babel src/App.js
SyntaxError: /tmp/tmp.dWHFTMhqmh/src/App.js: Support for the experimental syntax 'jsx' isn't currently enabled (2:10):
 
  1 | export default function App() {
> 2 |   return <div className="app">hello</div>;
    |          ^
  3 | }
  4 |
 
Add @babel/preset-react (https://github.com/babel/babel/tree/main/packages/babel-preset-react) to the 'presets' section of your Babel config to enable transformation.
If you want to leave it as-is, add @babel/plugin-syntax-jsx (https://github.com/babel/babel/tree/main/packages/babel-plugin-syntax-jsx) to the 'plugins' section to enable parsing.
 
If you already added the plugin for this syntax to your config, it's possible that your config isn't being loaded.
You can re-run Babel with the BABEL_SHOW_CONFIG_FOR environment variable to show the loaded configuration:
	npx cross-env BABEL_SHOW_CONFIG_FOR=/tmp/tmp.dWHFTMhqmh/src/App.js <your build command>
See https://babeljs.io/docs/configuration#print-effective-configs for more info.
 
    at constructor (/tmp/tmp.dWHFTMhqmh/node_modules/@babel/parser/lib/index.js:369:19)
    at Parser.raise (/tmp/tmp.dWHFTMhqmh/node_modules/@babel/parser/lib/index.js:6622:19)
    at Parser.expectOnePlugin (/tmp/tmp.dWHFTMhqmh/node_modules/@babel/parser/lib/index.js:6656:18)
    at Parser.parseExprAtom (/tmp/tmp.dWHFTMhqmh/node_modules/@babel/parser/lib/index.js:11429:24)
    at Parser.parseExprSubscripts (/tmp/tmp.dWHFTMhqmh/node_modules/@babel/parser/lib/index.js:11107:23)
    at Parser.parseUpdate (/tmp/tmp.dWHFTMhqmh/node_modules/@babel/parser/lib/index.js:11092:21)
    at Parser.parseMaybeUnary (/tmp/tmp.dWHFTMhqmh/node_modules/@babel/parser/lib/index.js:11072:23)
    at Parser.parseMaybeUnaryOrPrivate (/tmp/tmp.dWHFTMhqmh/node_modules/@babel/parser/lib/index.js:10925:61)
    at Parser.parseExprOps (/tmp/tmp.dWHFTMhqmh/node_modules/@babel/parser/lib/index.js:10930:23)
    at Parser.parseMaybeConditional (/tmp/tmp.dWHFTMhqmh/node_modules/@babel/parser/lib/index.js:10907:23) {
  code: 'BABEL_PARSE_ERROR',
  reasonCode: 'MissingOneOfPlugins',
  loc: Position { line: 2, column: 9, index: 41 },
  pos: 41,
  syntaxPlugin: undefined,
  missingPlugin: [ 'jsx', 'flow', 'typescript' ]
}
$ echo $?
1
$ npm i -D @babel/preset-react --no-audit --no-fund
added 6 packages in 696ms
$ npx babel src/App.js
"use strict";
 
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = App;
function App() {
  return /*#__PURE__*/React.createElement("div", {
    className: "app"
  }, "hello");
}
$ echo $?
0
$ BABEL_SHOW_CONFIG_FOR=src/App.js npx babel src/App.js
Babel configs on "/tmp/tmp.dWHFTMhqmh/src/App.js" (ascending priority):
config /tmp/tmp.dWHFTMhqmh/babel.config.json
{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "node": "current"
        }
      }
    ],
    "@babel/preset-react"
  ]
}
 
programmatic options from @babel/cli
{
  "sourceFileName": "src/App.js",
  "caller": {
    "name": "@babel/cli",
    "supportsStaticESM": false,
    "supportsDynamicImport": false,
    "supportsExportNamespaceFrom": false
  },
  "filename": "src/App.js"
}
-----End Babel configs-----
"use strict";
 
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = App;
function App() {
  return /*#__PURE__*/React.createElement("div", {
    className: "app"
  }, "hello");
}

— 2026-10-04 時点の出力

検証環境Node.js 20.20.2 / npm 10.8.2 / Python 3.11.2 / 2026-10-04 検証(ほか 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. preset-react を入れて presets に登録する

presets の並びは後ろから前へ適用されるため、preset-env と併記する順序は上の例のままで問題ない。

// babel.config.json
{
  "presets": [
    ["@babel/preset-env", { "targets": { "node": "current" } }],
    "@babel/preset-react"
  ]
}

2. TypeScript の .tsx なら preset-typescript も足す

型注釈と JSX は別のプリセットが担当する。.tsx を扱うなら両方必要だ。

// babel.config.json
{
  "presets": [
    "@babel/preset-env",
    "@babel/preset-react",
    ["@babel/preset-typescript", { "isTSX": true, "allExtensions": true }]
  ]
}

3. 適用された設定を出力して確かめる

設定ファイルが読まれていない場合、プリセットを足しても状況は変わらない。
対象ファイルに実際に適用された設定を表示する。

BABEL_SHOW_CONFIG_FOR=src/App.jsx npx babel src/App.jsx

出力の presets に @babel/preset-react が出てこなければ、設定ファイルの置き場所か root 指定の問題だ。

4. runtime の既定値を踏まえて import を整理する

@babel/preset-react の runtime オプション(v7.9.0 で追加)の既定値は、Babel 7 では classic、Babel 8 では automatic である。automatic なら JSX の変換に必要な関数が自動で import されるため、各ファイルの先頭に React を読み込む記述は不要になる。
Babel 7 で runtime を指定していない場合や、古い設定を引き継いで classic を明示している場合は、React の import が無いと実行時に落ちる。

// babel.config.json
{
  "presets": [["@babel/preset-react", { "runtime": "automatic" }]]
}

よくある原因

  1. プリセットが未インストール: @babel/preset-react には syntax-jsx / transform-react-jsx / transform-react-display-name の 3 プラグインが含まれる。
    これが無いと構文解析の段階で落ちる。
  2. インストールしたが登録していない: package.json の devDependencies には入っているのに、presets 配列へ足していないケースが多い。
    エラーメッセージは「インストールされていない」ではなく「有効になっていない」と言っている。
  3. 設定ファイル自体が読まれていない: モノレポや node_modules のファイルを対象にすると .babelrc は届かない。
    詳しくは /babel/babelrc-not-applied/ を参照。
  4. ツールごとに設定が分かれている: Jest は babel-jest を通すので babel.config.json を読むが、webpack の babel-loader に options を直書きしていると設定が二重管理になり、片方だけ JSX を有効にしていることがある。

この手順で直った?