Repository navigation
feat!: replace the ember-cli addon with a Babel plugin - #83
Merged
RobbieTheWagner merged 8 commits intoSep 11, 2026
Merged
Conversation
BREAKING CHANGE: this is no longer an ember-cli addon. Installing it is no
longer enough — it must be added to your Babel config. See MIGRATION.md.
v1 worked by hooking `preprocessTree('test', ...)` and running a
`broccoli-persistent-filter` over the host's test tree. That hook does not exist
in the Embroider v2 addon format and never fires in a Vite-built app, so on a
modern Ember build v1 was already silently inert: installed, resolved, and
transforming nothing.
A Babel plugin runs in both pipelines — Vite via `babel.config.mjs`, classic
builds via the `babel.plugins` option in `ember-cli-build.js`. Dropping the
`ember-addon` keyword also means `@embroider/compat` no longer has to rewrite
this package on every build.
Removed with the broccoli pipeline: `broccoli-persistent-filter`, `recast`,
`minimatch`, `ember-cli-babel`, `ember-cli-htmlbars`, `ember-template-imports`,
the dummy app, testem, and the ember-specific lint tooling. The package now has
no runtime dependencies and a single `@babel/core` peer.
The rewrite also resolves `assert` through Babel's scope rather than tracking
the most recently seen `test()` call textually, closing two gaps v1 had: arrow
-function tests and `test.only` / `test.skip` / `test.todo` were silently
skipped, and a renamed `assert` parameter was fragile. It is correspondingly
stricter — an `assert` that is not a test callback's first parameter, such as one
passed to `hooks.beforeEach`, is no longer transformed.
Config moves from `config/environment.js` to plugin options, and `include` /
`exclude` change from minimatch globs to regular expressions. `annotation` and
`persist` are gone, both being broccoli concerns.
73 tests, CI over Node 20/22/24 and two @babel/core versions.
Follow-up to the Babel plugin migration, clearing references to machinery that no longer exists: - CONTRIBUTING.md described running a dummy application at localhost:4200 and scripts (`test:ember`, `test:ember-compatibility`) that were removed with the ember-cli scaffolding. Replaced with how the suite actually runs now, plus a pointer at the `transform` / `inTest` helpers. - .gitignore dropped entries for build output (`/dist/`, `/declarations/`), `/testem.log`, and broccoli-debug's `/DEBUG/`. None of those are produced any more. - package.json#directories pointed `doc` at a directory that never existed and `test` at `tests/`, which is now `test/`. - MIGRATION.md is now published in the tarball — it is the reason this major exists, and is worth having available from node_modules. Also picks up the pnpm 12 workspace policy file and the .prettierrc.json -> .prettierrc.mjs swap.
v2.0.0 shipped in August 2025 (ember 4.12+/node 20+, plus configurable include/exclude), so the Babel plugin change is the next major after that. MIGRATION.md and the README referred to it as v2 throughout. The Embroider "v2 addon format" reference is left alone — that v2 means the addon format, not this package's version.
aklkv
force-pushed
the
feat/babel-plugin
branch
from
September 10, 2026 22:35
d22874a to
041d6a4
Compare
`node --test test/` resolves the directory as a module on some Node versions and fails with "Cannot find module .../test". It works on Node 20 and 26 but breaks on 22 and 24, which is why CI went red on exactly those two jobs while passing locally. Shell-expanded explicit paths are accepted by every version. Verified against Node 20, 22, 24 and 26: 73 passing on each. A quoted glob would be the other option, but Node 20 has no glob support in the test runner, and the matrix includes it.
BREAKING CHANGE: Node 20 is no longer supported. Node 20 reached end-of-life on 2026-04-30 and no longer receives security patches. Since this release is already a major, it is the natural point to drop it rather than carrying an unsupported runtime into the next cycle. This also removes an awkward constraint: engines was `^20.13.0 || >= 22` purely because `describe` from node:test is only stable on 20.13+. With Node 20 gone that collapses to `>= 22`. CI matrix moves from 20/22/24 to 22/24/26 — the currently supported lines. Verified locally on all three.
The guide covered the Babel-config change but not the runtime bump, so an upgrader hitting an engines error would have had nothing to go on. Both breaking changes are now stated up front, with a short section on why Node 20 is gone.
With Node 20 dropped, the test runner's own glob support is available, so the scripts no longer need shell-expanded file lists. Two things this fixes: - `--watch` now picks up newly added test files. Shell expansion resolved once, at launch, so a new file was invisible until the command was restarted. - It no longer depends on the shell expanding `*`, which some shells do not. The glob is quoted so it reaches Node verbatim rather than being expanded first. It stays explicit rather than using a bare `node --test`, because Node's default patterns include `**/test/**/*.cjs` and would sweep up `test/helpers.cjs` — that reports 74 tests instead of 73, counting a file with no tests in it. Verified on Node 22, 24 and 26: 73 passing on each.
RobbieTheWagner
approved these changes
Sep 11, 2026
Merged
|
@aklkv I'm so happy to have this back in our tests - this made me entire week! THANK YOU!! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
The addon's entire mechanism is a classic ember-cli build hook:
That hook does not exist in the Embroider v2 addon format, and never fires in a Vite-built app. On a modern Ember build this addon is already silently inert — installed, resolved, rewritten by
@embroider/compaton every build, and transforming nothing. No error, no warning; assertions just quietly stop getting messages.I confirmed this in a large production monorepo before touching anything: in the Vite-built app, the built bundle contained zero injected messages across 146 eligible message-less assertions. The addon was doing nothing there, and had been for as long as that app has used Vite.
It still works in classically-built packages, which is why this hasn't been widely noticed.
There is no way to fix this while remaining an addon: v2 deliberately removed
preprocessTree/treeFor*because host-tree build hooks are broccoli-specific and defeat static analysis. An addon whose only purpose is transforming the consuming app's source has nowhere to stand in v2.The change
Reimplemented as a Babel plugin, which runs in both pipelines. Note this direction was attempted once before, on the
migrate-to-babel-pluginbranch back in 2017 — v2 and Vite have since turned it from a nice-to-have into the only way this keeps working.This lands as v3 — v2.0.0 already shipped in August 2025 (#79, ember 4.12+/node 20+). MIGRATION.md is written as v2 → v3.
Two breaking changes:
enginesfrom^20.13.0 || >= 22— a range that existed only becausedescribefromnode:testneeds 20.13+ — down to>= 22.Config moves from
config/environment.jsto plugin options, andinclude/excludebecome regular expressions rather than minimatch globs.annotationandpersistare gone — both were broccoli concerns.What this removes
The broccoli pipeline, the dummy app, testem, and the ember-specific lint tooling all go. Dropped dependencies:
broccoli-persistent-filter,recast,minimatch,ember-cli-babel,ember-cli-htmlbars,ember-template-imports.The package now has zero runtime dependencies and a single
@babel/corepeer.Dropping the
ember-addonkeyword also means@embroider/compatno longer rewrites this package on every consumer build.What this fixes beyond the port
v1 resolves
assertby tracking the most recently seentest()call textually and only matchingFunctionExpression. This resolves the actual Babel binding:test('x', function (assert) {…})test('x', async (assert) => {…})test('x', function (a) { a.ok(…) })test.only/test.skip/test.todoArrow-function tests are common in
.gjs/.gtssuites, so this is not a theoretical gap.It is correspondingly stricter: an
assertthat is not a test callback's first parameter — one passed tohooks.beforeEach, say — is no longer transformed. v1 would sometimes catch those by accident.Consumers upgrading should expect assertions that previously had no message to start reporting one. That is the fix working, but it does change CI output.
Verification
node --test), covering every supported assertion at both arities, already-messaged assertions, unsupported assertions, computed access, spread args, shadowed and unrelatedassertbindings, all five test-callback shapes, everytest.*variant, nested and inner-test scoping, multi-line assertions and embedded comments, every option including error cases, idempotency, and output-still-parses.@babel/core8.0.5 and 7.x — the plugin spans both majors with one CJS file and no shims.@babel/core7 job that keeps the lower bound of the peer range honest.It was also validated end-to-end in a real monorepo across both pipelines — 362 injected messages in the Vite app (previously 0) and 34–133 per classic engine, with 4,570 tests across nine consumers passing, zero failures.
Notes
require(), and classic build files are CJS, so a CJS entry works from both an ESMbabel.config.mjsand a CJSember-cli-build.js.MIGRATION.mdis included in the published tarball.