Skip to content

Support Babel 8 alongside Babel 7 - #720

Draft
wagenet wants to merge 1 commit into
embroider-build:mainfrom
wagenet:wagenet/babel-8-support
Draft

Support Babel 8 alongside Babel 7#720
wagenet wants to merge 1 commit into
embroider-build:mainfrom
wagenet:wagenet/babel-8-support

Conversation

@wagenet

@wagenet wagenet commented Aug 12, 2026

Copy link
Copy Markdown

This PR was written by Claude (an AI agent), run by @wagenet. The code and the numbers below are the agent's work, not @wagenet's. Please review it as you would any unfamiliar contributor's patch.

Makes ember-auto-import install and run under either @babel/core 7 or 8. I didn't find an existing Babel 8 issue in this repo.

The bug that breaks silently

Babel 8 parses import() into a dedicated ImportExpression node instead of a CallExpression with an Import callee. Both of our plugins keyed off the old shape: analyzer-plugin.ts checked callee.type === 'Import', and babel-plugin.ts had an Import visitor.

Under Babel 8 neither fires, and nothing throws. The analyzer stops seeing dynamic imports, so those deps never enter a bundle, and import() is never rewritten to emberAutoImportDynamic. You'd find out at runtime.

Both plugins now handle both shapes. Babel 7.22+ can emit the Babel 8 AST via the createImportExpressions parser option, so the regression test runs on our normal Babel 7 CI. It fails without the fix.

Config Babel 8 rejects

In cleanBabelConfig():

Was Now Why
plugin-proposal-class-properties plugin-transform-class-properties 7.18.6 is the last proposal release there will ever be, and its @babel/core: ^7.0.0-0 peer is an install failure against core 8
plugin-proposal-private-methods plugin-transform-private-methods Same
decorators { legacy: true } { version: 'legacy' } Babel 8 dropped the shorthand and errors without an explicit version. 7.17+ accepts version: 'legacy'
{ loose: false } omitted Already the default, and deprecated in Babel 8 in favor of assumptions

Ranges

Babel deps widened to ^7.x || ^8.0.0. Babel 8's plugins declare api.assertVersion("^7.0.0-0 || ^8.0.0"), so a mixed install (core 7 with plugins 8, which is what pnpm produces here) works.

babel-loader goes to ^8.0.6 || ^10.1.1; 8 and 9 both cap @babel/core at ^7. Two side effects worth a look: a fresh install now resolves babel-loader 10 even for Babel 7 users, and its engines (^18.20.0 || ^20.10.0 || >=22.0.0) are narrower than this package's declared 12.* || 14.* || >= 16. That engines field looked stale enough that I left it alone.

broccoli-babel-transpiler: ^8.0.0 is new in devDependencies. The unit tests imported it without declaring it and were getting 7.8.1 by hoisting, which calls babel.transform() with no callback, which Babel 8 rejects. 8.0.2 needs new and { babel: options }, hence the test churn.

TypeScript

Babel 8 ships its own types and renamed things (TransformOptions to InputOptions, PluginObj to PluginObject), so tsc fails outright under it. ts/babel-compat.ts derives the options type from a signature present in both. cleanBabelConfig's plugin list is now PluginItem[], which meant flattening single-element [plugin] entries to bare strings.

Test results

Under @babel/core 8.0.1, preset-env 8.0.2, babel-loader 10.1.1 (forced with pnpm.overrides): 157/157 node unit tests pass. That's the signal that matters, since js/tests drives both plugins and the analyzer through real @babel/core. The new unit_babel8 CI job runs exactly this.

Babel 7 is unregressed: 157/157 unit tests, plus the release-babel, release-dynamic-import, release-static-import, release-import-sync, and indirect-analyzer-skew scenarios.

The full scenario suite can't run under Babel 8 yet, and the blocker isn't here. It dies in ember-cli-babel 8.3.1, which still passes four removed options: { legacy: true } to proposal-decorators, { legacy: true } to transform-class-static-block (which has no such option), regenerator/useESModules to transform-runtime, and moduleId/getModuleId. I patched the first three in node_modules to get further; the build then failed on getModuleId inside a nested qunit-dom/node_modules/ember-cli-babel a local patch can't reach.

Left alone

analyzer.ts has if (this.pack.babelMajorVersion !== 7) throw on the slow analyzer path. That's the ember-cli-babel major, not @babel/core's, so it already throws for anyone on ember-cli-babel 8 who reaches that path. Unrelated to Babel 8, but someone should look at it.

babel-plugin-syntax-dynamic-import is a Babel 6 plugin pushing a dynamicImport parser plugin name. Babel 8 ignores it rather than erroring, so it's harmless.

🤖 Generated with Claude Code

Babel 8 parses `import()` into an ImportExpression node instead of a
CallExpression with an `Import` callee, so both of our babel plugins
silently stopped seeing dynamic imports. They now handle both shapes,
with a regression test that uses Babel 7's `createImportExpressions`
parser option to produce the Babel 8 AST.

In cleanBabelConfig, swap the proposal-* class-features plugins for the
maintained transform-* equivalents (no Babel 8 release of the proposal
packages exists), pass decorators `version: 'legacy'` instead of the
`legacy` shorthand Babel 8 dropped, and stop passing `loose: false`,
which is both the default and deprecated in Babel 8.

Widen the babel dependency ranges to `^7.x || ^8.0.0` and babel-loader
to include ^10.1.1, the first release whose @babel/core peer admits 8.

Add ts/babel-compat.ts because Babel 8 ships its own types under
different names, which otherwise breaks tsc.

The full scenario suite can't run under Babel 8 until ember-cli-babel
supports it, so the new unit_babel8 CI job covers the part we own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant