Skip to content

Add agadoo tree-shake regression check#21366

Merged
NullVoxPopuli merged 1 commit intoemberjs:nvp/configure-side-effectsfrom
NullVoxPopuli-ai-agent:claude/shrink-hello-world-config-only
May 3, 2026
Merged

Add agadoo tree-shake regression check#21366
NullVoxPopuli merged 1 commit intoemberjs:nvp/configure-side-effectsfrom
NullVoxPopuli-ai-agent:claude/shrink-hello-world-config-only

Conversation

@NullVoxPopuli-ai-agent
Copy link
Copy Markdown
Contributor

Stacks on top of #21365.

sideEffects: false is a contract that's invisible to reviewers — any module-level mutation (set*Manager(...), Foo.reopenClass(...), _backburner = new Backburner(...)) silently rots the contract. Bundlers will drop these side effects when the symbol they ride along with isn't imported.

This adds a pnpm test:tree-shake script that bundles each currently-pure entry point with rollup as if a consumer imported it for side effects only, and asserts nothing survives. Regression in any known-pure entry fails CI with an actionable message.

What's checked

23 entries that are fully tree-shakeable today:

@ember/-internals/browser-environment    @glimmer/destroyable
@ember/-internals/error-handling          @glimmer/encoder
@ember/-internals/owner                   @glimmer/env
@ember/-internals/utility-types           @glimmer/global-context
@ember/deprecated-features                @glimmer/owner
@ember/destroyable                        @glimmer/util
@ember/owner                              @glimmer/vm
@ember/reactive                           @glimmer/wire-format
@ember/template-compilation               @simple-dom/document
@ember/test                               backburner.js
@ember/version                            dag-map
                                          route-recognizer

The 43 currently-impure entries (@ember/-internals/glimmer, @ember/runloop, @glimmer/runtime, etc.) are omitted because they have known top-level side effects (manager registrations, validator state, backburner instance, etc.) that sideEffects: false is promising bundlers can drop in practice anyway.

Files

  • bin/check-tree-shake.mjs — runs agadoo.check() on each known-pure entry, reports failures
  • package.json — adds agadoo devDep and pnpm test:tree-shake script
  • patches/agadoo.patch — bumps agadoo's bundled acorn from ecmaVersion: 11 (ES2020) to 'latest' so it doesn't choke on private class fields / other ES2022+ syntax that appears in dist/

Caveat

Agadoo bundles by absolute path with no nodeResolve plugin, so it doesn't actually read ember-source/package.json's sideEffects: false. That's a feature here, not a bug: it's measuring "is this file inherently pure?" not "does it tree-shake when consumed as a package." The contract sideEffects: false is making is "no module gains a new top-level side effect that bundlers can't observe through their conservative heuristics," and agadoo enforces exactly that.

Verification

Verified the failure mode by adding globalThis.__OOPS__ = {} at the top level of @ember/destroyable/index.ts. The check correctly fails:

✗ @ember/destroyable — has top-level side effects

1 entry regressed:
  - @ember/destroyable

These packages were previously fully tree-shakeable. Either:
  1. Remove the new top-level side effect (preferred), or
  2. If the side effect is intentional, remove the entry from
     KNOWN_PURE_ENTRIES in bin/check-tree-shake.mjs and update
     ember-source's package.json sideEffects field accordingly.

Test plan

  • pnpm test:tree-shake — 23 entries verified pure
  • Verified failure mode by adding a deliberate side effect, then reverting

🤖 Generated with Claude Code

@NullVoxPopuli-ai-agent NullVoxPopuli-ai-agent force-pushed the claude/shrink-hello-world-config-only branch 3 times, most recently from cdfeb88 to 4de95e9 Compare May 3, 2026 15:36
`sideEffects: false` declares a contract that's invisible to
reviewers: any module-level mutation (`set*Manager(...)`,
`Foo.reopenClass(...)`, `_backburner = new Backburner(...)`)
silently rots the contract. Bundlers will drop these side effects
when the symbol they ride along with isn't imported.

Adds a `pnpm test:tree-shake` script that bundles each pure-today
entry point with rollup as if a consumer imported it for side
effects only, and asserts nothing survives. Regression in any
known-pure entry fails CI with an actionable message.

Today the list is 23 entries — `@glimmer/util`, `@glimmer/destroyable`,
`@ember/owner`, `@ember/version`, etc. The 43 currently-impure entries
(@ember/-internals/glimmer, @ember/runloop, @glimmer/runtime, …) are
omitted because they have known top-level side effects that
sideEffects: false promises bundlers can drop in practice anyway.

Patch: agadoo's bundled acorn pins ecmaVersion 11 (ES2020), which
chokes on private class fields and other ES2022+ syntax that appears
in dist. The patch bumps it to `'latest'`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@NullVoxPopuli-ai-agent NullVoxPopuli-ai-agent force-pushed the claude/shrink-hello-world-config-only branch from 4de95e9 to e8bb3bb Compare May 3, 2026 15:41
@NullVoxPopuli NullVoxPopuli merged commit ade41e1 into emberjs:nvp/configure-side-effects May 3, 2026
77 checks passed
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.

2 participants