Skip to content

[Bug]: Referenced cross-module binding dropped under strictExecutionOrder + sideEffects: false (regression in 1.1.3) #9961

Description

@gkurt

Reproduction link or steps

Minimal reproduction: https://github.com/KurtGokhan/rolldown-checkglobals-repro

git clone https://github.com/KurtGokhan/rolldown-checkglobals-repro
cd rolldown-checkglobals-repro
npm install
npm run build

grep -c 'checkGlobals()'        dist/assets/*.js   # => 1  (call kept)
grep -c 'function checkGlobals'  dist/assets/*.js   # => 0  (definition gone)

npm run preview   # blank page; console: "ReferenceError: checkGlobals is not defined"

The bug surfaces in the wild via msw: its core/index.mjs calls checkGlobals() at module top level, while its package.json declares "sideEffects": false.

// node_modules/msw/lib/core/index.mjs
import { checkGlobals } from './utils/internal/checkGlobals.mjs';
// ...
checkGlobals();           // top-level side effect
export { http, HttpResponse, /* ... */ };

Relevant config (vite.config.js):

export default defineConfig({
  build: {
    minify: false,
    rolldownOptions: { output: { strictExecutionOrder: true } },
  },
});

Trigger conditions (all required):

  • output.strictExecutionOrder: true — without it, both the call and the definition are removed together (no dangling reference)
  • the dependency declares "sideEffects": false
  • that dependency calls an imported cross-module function at its module top level
  • other exports of the dependency are used, so its module is retained

What is expected?

A referenced binding must be retained whenever the reference (the checkGlobals() call) is retained, regardless of "sideEffects": false. Either keep both the call and the definition, or remove both — never keep the call while dropping the definition.

This is what rolldown 1.0.3 (vite 8.0.16) does: the definition is present and the app works.

What is actually happening?

rolldown keeps the top-level checkGlobals() call but tree-shakes the checkGlobals function definition out of every chunk, leaving a free identifier → ReferenceError: checkGlobals is not defined at module-eval time → blank app.

This is a regression between rolldown 1.0.3 and 1.1.3:

vite rolldown result
8.1.0 1.1.3 ❌ definition dropped, ReferenceError
8.0.16 1.0.3 ✅ definition retained, works

System Info

  System:
    OS: macOS 26.5.1
    CPU: (12) arm64 Apple M3 Pro
    Memory: 845.58 MB / 36.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 24.18.0
    npm: 11.16.0
    pnpm: 10.28.1
    bun: 1.3.13
    Deno: 2.8.3+
  Browsers:
    Chrome: 149.0.7827.156
    Firefox Developer Edition: 151.0
    Safari: 26.5
  npmPackages:
    rolldown: 1.1.3 (transitive, via vite 8.1.0)
    vite: 8.1.0
    msw: 2.14.6

Any additional comments?

msw declaring "sideEffects": false while running checkGlobals() at import time is arguably inaccurate on msw's side, but a bundler must still not drop a referenced binding — so this looks like a rolldown correctness bug in scope-hoisting / side-effect handling. The concerning part is that the same mechanism could silently drop other referenced cross-module bindings that don't happen to throw loudly at load.

Originally hit while bumping vite 8.0.x8.1.0 in a real app, where it produced a fully blank page (ReferenceError: checkGlobals is not defined).

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Fields

Priority

None yet

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions