Reproduction link or steps
Repo (starting point, see "partial repro" note below):
https://github.com/thedoublejay/rolldown-chunk-split-cjs-repro
Open in Stackblitz:
https://stackblitz.com/github/thedoublejay/rolldown-chunk-split-cjs-repro
git clone https://github.com/thedoublejay/rolldown-chunk-split-cjs-repro
cd rolldown-chunk-split-cjs-repro
npm install
npm run build # vite 8.0.13, rolldown 1.0.1
npm run preview # browse http://localhost:4173
The repo sets up the same conditions where a real-world Vite 8.0.13 build broke:
- 3 ×
React.lazy(() => import(...)) boundaries, all importing the same lodash/<sub> CJS submodules (forces rolldown to extract them to a shared vendor chunk)
- ESM libs (
@mui/material, @tanstack/react-query, clsx, @emotion/react) mixed with the CJS modules in the shared chunk, matching the real failing chunk's shape
tss-react/mui withStyles in a lazy component (matches the legacy component that surfaced the bug)
vite.config.js mirrors the failing config's distinctive flags: react({ jsxImportSource: "@emotion/react" }) + rolldown.moduleTypes: { ".js": "jsx" }
Important — partial repro
This standalone repo does not yet trigger the broken emission on its own — rolldown emits a consistent interop shape here. The same Vite/rolldown versions + the same lodash subpaths + the same lazy boundary structure DO reproduce in a larger codebase (~5000 modules / ~1200-source vendor chunks). The trigger appears to depend on graph shape we couldn't isolate down to a small case.
I'm filing this rather than waiting because the production-side evidence below is concrete (minified output + bisect-narrowed regression range), and a maintainer hint at the chunking heuristic that changed between rolldown 1.0.0-rc.18 and 1.0.0 / 1.0.1 would let me push the repo over the edge. Happy to invest more time on shrinking the case.
What is expected?
When rolldown splits a CJS module into a separate output chunk, the import-site code and the export-side emission should agree on the interop shape:
- Either both sides treat the export as a
__commonJSMin(...) lazy-wrapper function, or
- both sides treat the export as a static namespace value.
This is what rolldown 1.0.0-rc.18 (shipped in Vite 8.0.11) does, and what the same source produces correctly there.
What is actually happening?
In rolldown 1.0.0 / 1.0.1, when a CJS module ends up in a separate output chunk (not the main bundle), the importer and exporter disagree:
- The import-site emits
a(c()) — i.e. calls c as a __commonJSMin() lazy-wrapper, then passes the result to _interopRequireDefault.
- The export-side emits the resolved module namespace directly as the export, not wrapped in a callable getter.
Result: TypeError: <minified> is not a function thrown synchronously at top-level of the lazy chunk (before any of its export bindings evaluate), which surfaces as a React.lazy rejection caught by the nearest ErrorBoundary.
Real-world emitted code (anonymized)
// Importing chunk (lazy)
import { Vt as t, fi as n, p as r, q as i, vi as a } from "./main.js";
import { n as s } from "./shared-A.chunk.js";
import { T as c } from "./shared-B.chunk.js"; // ← shared CJS+ESM vendor chunk
var l = a(n()), // ← works: n() returns the __commonJSMin wrapper from main
u = a(i()), // ← works: i() returns the __commonJSMin wrapper from main
d = a(c()) // ← throws: c is not callable, exporter emitted a value
Browser console
TypeError: c is not a function
at app.<hash>.chunk.js:1:272
Caused by: React ErrorBoundary TypeError: c is not a function
at Lazy (<anonymous>)
at Suspense (<anonymous>)
Reproducible with both [email protected] and [email protected], both @vitejs/[email protected] and @vitejs/[email protected], so neither of those is the variable.
System Info
System:
OS: macOS 26.5
CPU: arm64 Apple Silicon
Binaries:
Node: 24.14.1
npm: 11.11.0
Yarn: 4.13.0
npmPackages (broken configuration):
vite: 8.0.13
rolldown: 1.0.1 (transitive via vite)
@vitejs/plugin-react: 6.0.2
react / react-dom: 19.2.x
Any additional comments?
Bisect: which Vite/rolldown versions are affected?
| Vite version |
Bundled rolldown |
Status |
| 8.0.1 |
1.0.0-rc.10 |
✅ works |
| 8.0.11 |
1.0.0-rc.18 (Apr 29, 2026 — last RC) |
✅ works |
| 8.0.12 |
1.0.0 (May 7, 2026 — first stable) |
⚠️ likely affected (same rolldown family) — not directly retested |
| 8.0.13 |
1.0.1 (May 13, 2026) |
❌ reproduces |
Bisect was carried out against the real-world failing app: same source, same install, only the Vite/rolldown version changed.
Workaround in use
Pin Vite to exact 8.0.11.
Related
- #9407 — distinct bug, same rolldown 1.0.1 family:
require("react") left as runtime __require even when react is inlined elsewhere in the same build. Different surface (SSR + dangling __require) but same theme of CJS-interop emission inconsistency across the bundle graph.
- #7449 — incorrect execution order with CJS + advancedChunks (different mechanism, but also CJS chunking-related).
Triage hint
If a maintainer can hint at what specifically changed in chunk emission between rolldown 1.0.0-rc.18 and 1.0.0 / 1.0.1 for shared CJS modules — particularly when a vendor chunk mixes ESM and __commonJSMin-wrapped CJS modules — I should be able to take the linked repo over the edge into a clean standalone repro.
Reproduction link or steps
Repo (starting point, see "partial repro" note below):
https://github.com/thedoublejay/rolldown-chunk-split-cjs-repro
Open in Stackblitz:
https://stackblitz.com/github/thedoublejay/rolldown-chunk-split-cjs-repro
The repo sets up the same conditions where a real-world Vite 8.0.13 build broke:
React.lazy(() => import(...))boundaries, all importing the samelodash/<sub>CJS submodules (forces rolldown to extract them to a shared vendor chunk)@mui/material,@tanstack/react-query,clsx,@emotion/react) mixed with the CJS modules in the shared chunk, matching the real failing chunk's shapetss-react/muiwithStylesin a lazy component (matches the legacy component that surfaced the bug)vite.config.jsmirrors the failing config's distinctive flags:react({ jsxImportSource: "@emotion/react" })+rolldown.moduleTypes: { ".js": "jsx" }Important — partial repro
This standalone repo does not yet trigger the broken emission on its own — rolldown emits a consistent interop shape here. The same Vite/rolldown versions + the same lodash subpaths + the same lazy boundary structure DO reproduce in a larger codebase (~5000 modules / ~1200-source vendor chunks). The trigger appears to depend on graph shape we couldn't isolate down to a small case.
I'm filing this rather than waiting because the production-side evidence below is concrete (minified output + bisect-narrowed regression range), and a maintainer hint at the chunking heuristic that changed between rolldown
1.0.0-rc.18and1.0.0/1.0.1would let me push the repo over the edge. Happy to invest more time on shrinking the case.What is expected?
When rolldown splits a CJS module into a separate output chunk, the import-site code and the export-side emission should agree on the interop shape:
__commonJSMin(...)lazy-wrapper function, orThis is what rolldown
1.0.0-rc.18(shipped in Vite8.0.11) does, and what the same source produces correctly there.What is actually happening?
In rolldown
1.0.0/1.0.1, when a CJS module ends up in a separate output chunk (not the main bundle), the importer and exporter disagree:a(c())— i.e. callscas a__commonJSMin()lazy-wrapper, then passes the result to_interopRequireDefault.Result:
TypeError: <minified> is not a functionthrown synchronously at top-level of the lazy chunk (before any of itsexportbindings evaluate), which surfaces as aReact.lazyrejection caught by the nearestErrorBoundary.Real-world emitted code (anonymized)
Browser console
Reproducible with both
[email protected]and[email protected], both@vitejs/[email protected]and@vitejs/[email protected], so neither of those is the variable.System Info
Any additional comments?
Bisect: which Vite/rolldown versions are affected?
1.0.0-rc.101.0.0-rc.18(Apr 29, 2026 — last RC)1.0.0(May 7, 2026 — first stable)1.0.1(May 13, 2026)Bisect was carried out against the real-world failing app: same source, same install, only the Vite/rolldown version changed.
Workaround in use
Pin Vite to exact
8.0.11.Related
require("react")left as runtime__requireeven when react is inlined elsewhere in the same build. Different surface (SSR + dangling__require) but same theme of CJS-interop emission inconsistency across the bundle graph.Triage hint
If a maintainer can hint at what specifically changed in chunk emission between rolldown
1.0.0-rc.18and1.0.0/1.0.1for shared CJS modules — particularly when a vendor chunk mixes ESM and__commonJSMin-wrapped CJS modules — I should be able to take the linked repo over the edge into a clean standalone repro.