Skip to content

Circular runtime helper import between entry chunk and code-split CJS chunk causes "e is not a function" at load (rc.17, regression from rc.15) #9224

@Stanzilla

Description

@Stanzilla

Reproduction link or steps

I don't have a minimal REPL yet (the trigger is a real-world dependency graph), but the behavior is fully deterministic and I can produce one if needed. The key shape is:

  • App entry imports a CommonJS module @faceit/protos-commonjs (a generated protobuf package), which require()s google-protobuf.

  • google-protobuf is its own large CommonJS module (Closure-compiler output).

  • Rolldown chunks google-protobuf separately from the entry, lifts the __commonJSMin runtime helper into the entry chunk, and re-imports it from google-protobuf — creating a cycle:

    • google-protobuf-*.js:
      import { n as e } from "./index-*.js";
      var t = e((e => { /* google-protobuf factory */ }));
    • index-*.js:
      import { t as require_google_protobuf } from "./google-protobuf-*.js";
      
      __commonJSMin = (e, t) => () => (t || (e((t={exports:{}}).exports, t), e = null), t.exports);
      
      export { __commonJSMin as n, require_timestamp_pb as t };

When the browser runs the cycle, google-protobuf executes first; at that point n (the live binding to __commonJSMin) is still uninitialized, so the top-level var t = e(…) calls undefined as a function.

What is expected?

The __commonJSMin/__commonJS runtime helper either gets inlined into the chunk that needs it (the way rolldown 1.0.0-rc.15 did), or some other arrangement that does not produce a circular ESM import between an entry chunk and a code-split CJS chunk. No runtime error.

What is actually happening?

Production build of two of our apps (Vite 8.0.10, rolldown 1.0.0-rc.17) crashes immediately on load with a blank page and:

google-protobuf-DvwQlcDQ.js:1 Uncaught TypeError: e is not a function
    at google-protobuf-DvwQlcDQ.js:1:462

Because var t = e(…) runs at top level of the google-protobuf chunk before index has had a chance to assign __commonJSMin, e is undefined.

Comparison with rolldown 1.0.0-rc.15 (Vite 8.0.8 — works)

Same source, same vite config, just a different bundled rolldown. The chunk is self-contained, no cross-chunk runtime import:

var e=Object.create,  ,
    s=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),
     ,
    d=s((e=>{ var t = typeof O… /* google-protobuf factory */ }));

No cycle, no error.

Why this is probably interesting to you

This looks like the same class of regression as #8989 (“TypeError: __exportAll is not a function” via cyclic chunk import), which was reported against rc.13 and supposedly addressed in rc.16 by #9057 (“prevent circular runtime helper imports during facade elimination”). The fix does not cover this case — we still hit it on rc.17.

Two of our apps (a customer-facing React/Vite SPA each) are blocked on the Vite 8.0.9 → 8.0.10 patch upgrade because of this. Dev mode is fine — only production builds are affected, since dev doesn't extract the runtime helper.

System Info

System:
  OS: macOS 26.4 (Darwin 25.4.0, arm64)
  CPU: Apple Silicon (M3 Pro)
Binaries:
  Node: 24.15.0
  pnpm: 10.33.2
npmPackages:
  vite: 8.0.10
  rolldown: 1.0.0-rc.17 (transitive, bundled in vite)
  google-protobuf: 3.21.4
  @vitejs/plugin-react: latest

(Both Vite 8.0.9 and 8.0.10, both shipping rolldown 1.0.0-rc.17, reproduce. Vite 8.0.8 / rolldown 1.0.0-rc.15 does not reproduce.)

Any additional comments?

Happy to put together a minimal repro if helpful — let me know if the description above is enough to get started or if you'd like me to reduce it.

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Priority

None yet

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions