fix(oxc-runtime): route require() to CJS helper variant (#9263)#9526
Conversation
How to use the Graphite Merge QueueAdd the label graphite: merge-when-ready to this PR to add it to the merge queue. You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
✅ Deploy Preview for rolldown-rs canceled.
|
36ef49e to
8d4e742
Compare
Merging this PR will not alter performance
Comparing Footnotes
|
|
I'm not sure this is a good direction. I'm worred that this might cause the runtime code have dual package hazard. What will happen if the runtime code got both
From the PR description, I assume the anwser is that rolldown will ship both esm and cjs version code. I think we need to refer to other bundlers and see how does they deal with the situation. @sapphi-red cc |
1. Almost all helpers are pure stateless functionsI scanned all 116 ESM helpers. The overwhelming majority are pure functions like: function _defineProperty(e, r, t) { /* …pure… */ }
function _typeof(o) { /* …pure… */ }For those, "two copies in one bundle" just means two equivalent function objects — no helper is compared by identity, only called, so duplication is at worst a few wasted bytes. The exceptions worth naming explicitly:
Within a single user module, the helper and its transitive 2. The on-disk package already does exactly this dispatchLook at "./helpers/defineProperty": [
{
"node": "./src/helpers/defineProperty.js", // CJS variant
"import": "./src/helpers/esm/defineProperty.js", // ESM variant
"default": "./src/helpers/defineProperty.js"
},
"./src/helpers/defineProperty.js"
]So if 3. The CJS variant is interop-safe by constructionThe on-disk CJS helper ends with: module.exports = _defineProperty;
module.exports.__esModule = true;
module.exports["default"] = module.exports;So 4. Other bundlers in this niche behave the same way
5. The alternatives are worseThe other ways to fix #9263 are:
|
|
Another reason I don't prefer the way |
hyf0
left a comment
There was a problem hiding this comment.
Webpack + babel runtime has the same behavior as this PR. LGTM.
8d4e742 to
2842ec4
Compare
Merge activity
|
|
I have fixed the issues(refactor) that @shulaoda mentioned, so I merged. |
The on-disk `@oxc-project/runtime` package ships two variants of every helper: a CJS form at `src/helpers/<name>.js` that sets `module.exports = fn`, and an ESM form at `src/helpers/esm/<name>.js` that does `export default fn`. The plugin previously embedded only the ESM variant and reused it for every caller, which meant `require("@oxc-project/runtime/helpers/X")` returned the ESM namespace `{ default: fn }` rather than the function itself.
This PR embeds both variants and dispatches resolution by `ImportKind`: `require()` gets the CJS variant (callable directly), `import` / dynamic `import()` get the ESM variant. Relative imports between virtual helpers preserve the importer's directory so an ESM helper's `./typeof.js` stays in `esm/`. Fixes #9263, where `_defineProperty` resolved to the ESM namespace inside CJS-classified modules and threw `TypeError: _defineProperty is not a function` at init.
2842ec4 to
f06c2a0
Compare
|
I guess we can add |
… (rolldown#9526) The on-disk `@oxc-project/runtime` package ships two variants of every helper: a CJS form at `src/helpers/<name>.js` that sets `module.exports = fn`, and an ESM form at `src/helpers/esm/<name>.js` that does `export default fn`. The plugin previously embedded only the ESM variant and reused it for every caller, which meant `require("@oxc-project/runtime/helpers/X")` returned the ESM namespace `{ default: fn }` rather than the function itself. This PR embeds both variants and dispatches resolution by `ImportKind`: `require()` gets the CJS variant (callable directly), `import` / dynamic `import()` get the ESM variant. Relative imports between virtual helpers preserve the importer's directory so an ESM helper's `./typeof.js` stays in `esm/`. Fixes rolldown#9263, where `_defineProperty` resolved to the ESM namespace inside CJS-classified modules and threw `TypeError: _defineProperty is not a function` at init.
## [1.0.3] - 2026-05-27 ### 🚀 Features - transform: respect decorator strictNullChecks option (#9580) by @kylecannon - drop `defer` keyword (#9503) by @TheAlexLichter ### 🐛 Bug Fixes - ci: create target dir before cargo release-oxc update (#9584) by @shulaoda - ci: reorder prepare-release steps to avoid dirty git check failure (#9583) by @shulaoda - testing: canonicalize temp dir early and use platform-specific separator in test262 (#9582) by @shulaoda - testing: resolve symlinked temp dir in test262 snapshot normalization (#9581) by @shulaoda - testing: canonicalize temp dir path in test262 snapshot normalization (#9579) by @shulaoda - dev: `onOutput` called twice when initial build fails (#9552) by @hyf0 - dev: make `ensureCurrentBuildFinish` not returning error when engine closes (#9564) by @h-a-n-a - oxc-runtime: route require() to CJS helper variant (#9263) (#9526) by @IWANABETHATGUY - generator: use exporter chunk's export mode for CJS default re-exports (#9299) (#9529) by @IWANABETHATGUY - rolldown: always run reduced-atom static cycle check (#9441) (#9514) by @IWANABETHATGUY - apply transform.dropLabels before scanning (#9521) (#9522) by @IWANABETHATGUY - rolldown_watcher: take `rolldown` dep through the workspace (#9510) by @Boshen - cache: keep the scan-stage cache consistent when a build fails (#9495) by @h-a-n-a - skip JSON default-import namespace optimization for write targets (#9484) (#9489) by @IWANABETHATGUY - deps: skip pnpm frozen-lockfile on Netlify to dodge catalog mismatch bug (#9471) by @Boshen ### 🚜 Refactor - oxc-runtime: use Cow for helper path construction (#9538) by @IWANABETHATGUY - fold import defer phase drop into PreProcessor (#9524) by @IWANABETHATGUY - distinguish `map: null` vs `map: undefined` in transform hook output (#9497) by @sapphi-red ### 📚 Documentation - explain the policy for Rust crates (#9547) by @sapphi-red - cache: add design doc for cache (#9544) by @h-a-n-a - guide/troubleshooting: add TDZ error section (#9537) by @sapphi-red - dev-engine: add design doc for dev-engine (#9479) by @h-a-n-a - lazy-barrel: tweak some words (#9483) by @shulaoda - lazy-barrel: expand reasoning behind LARGE_BARREL_MODULES advice (#9477) by @shulaoda ### ⚡ Performance - generate: thread ast_table by value into codegen consumer (#9555) by @Boshen - finalizers: replace `_reExport` construction with a direct call to avoid calling `clone_in` (#9501) by @Dunqing - reorder hot-path boolean checks to short-circuit on cheap predicates first (#9523) by @Boshen ### 🧪 Testing - rolldown: regression fixture for #9401 (#9418) by @IWANABETHATGUY - failing test for #9441 (#9504) by @TheAlexLichter ### ⚙️ Miscellaneous Tasks - deps: upgrade oxc to 0.133.0 (#9563) by @Dunqing - deps: update crate-ci/typos action to v1.46.3 (#9576) by @renovate[bot] - deps: update mimalloc-safe to 0.1.62 (#9577) by @shulaoda - mimalloc-safe: update to a bug-fix branch for verification (#9569) by @shulaoda - deps: update test262 submodule for tests (#9551) by @rolldown-guard[bot] - point published crates' readme to root README.md (#9553) by @Boshen - replace actions-cool/issues-helper with gh CLI (#9543) by @Boshen - deps: update cargo-shear to 1.12.4 (#9541) by @Boshen - deps: update taiki-e/install-action action to v2.79.4 (#9535) by @renovate[bot] - deps: update github actions (#9532) by @renovate[bot] - deps: update rust crates (#9534) by @renovate[bot] - deps: update npm packages (#9533) by @renovate[bot] - gate experimental/testing-only items to silence dead_code in publish builds (#9517) by @Boshen - docs: deploy to Void (#9509) by @Boshen - release: set up cargo-release-oxc for publishing crates (#9476) by @Boshen - rolldown_plugin_lazy_compilation: add missing description (#9507) by @Boshen - mimalloc-safe: update to a bug-fix branch for verification (#9506) by @shulaoda - deps: update crate-ci/typos action to v1.46.2 (#9468) by @renovate[bot] ### ❤️ New Contributors * @kylecannon made their first contribution in [#9580](#9580)
## [1.0.3] - 2026-05-27 ### 🚀 Features - transform: respect decorator strictNullChecks option (#9580) by @kylecannon - drop `defer` keyword (#9503) by @TheAlexLichter ### 🐛 Bug Fixes - ci: create target dir before cargo release-oxc update (#9584) by @shulaoda - ci: reorder prepare-release steps to avoid dirty git check failure (#9583) by @shulaoda - testing: canonicalize temp dir early and use platform-specific separator in test262 (#9582) by @shulaoda - testing: resolve symlinked temp dir in test262 snapshot normalization (#9581) by @shulaoda - testing: canonicalize temp dir path in test262 snapshot normalization (#9579) by @shulaoda - dev: `onOutput` called twice when initial build fails (#9552) by @hyf0 - dev: make `ensureCurrentBuildFinish` not returning error when engine closes (#9564) by @h-a-n-a - oxc-runtime: route require() to CJS helper variant (#9263) (#9526) by @IWANABETHATGUY - generator: use exporter chunk's export mode for CJS default re-exports (#9299) (#9529) by @IWANABETHATGUY - rolldown: always run reduced-atom static cycle check (#9441) (#9514) by @IWANABETHATGUY - apply transform.dropLabels before scanning (#9521) (#9522) by @IWANABETHATGUY - rolldown_watcher: take `rolldown` dep through the workspace (#9510) by @Boshen - cache: keep the scan-stage cache consistent when a build fails (#9495) by @h-a-n-a - skip JSON default-import namespace optimization for write targets (#9484) (#9489) by @IWANABETHATGUY - deps: skip pnpm frozen-lockfile on Netlify to dodge catalog mismatch bug (#9471) by @Boshen ### 🚜 Refactor - oxc-runtime: use Cow for helper path construction (#9538) by @IWANABETHATGUY - fold import defer phase drop into PreProcessor (#9524) by @IWANABETHATGUY - distinguish `map: null` vs `map: undefined` in transform hook output (#9497) by @sapphi-red ### 📚 Documentation - explain the policy for Rust crates (#9547) by @sapphi-red - cache: add design doc for cache (#9544) by @h-a-n-a - guide/troubleshooting: add TDZ error section (#9537) by @sapphi-red - dev-engine: add design doc for dev-engine (#9479) by @h-a-n-a - lazy-barrel: tweak some words (#9483) by @shulaoda - lazy-barrel: expand reasoning behind LARGE_BARREL_MODULES advice (#9477) by @shulaoda ### ⚡ Performance - generate: thread ast_table by value into codegen consumer (#9555) by @Boshen - finalizers: replace `_reExport` construction with a direct call to avoid calling `clone_in` (#9501) by @Dunqing - reorder hot-path boolean checks to short-circuit on cheap predicates first (#9523) by @Boshen ### 🧪 Testing - rolldown: regression fixture for #9401 (#9418) by @IWANABETHATGUY - failing test for #9441 (#9504) by @TheAlexLichter ### ⚙️ Miscellaneous Tasks - deps: upgrade oxc to 0.133.0 (#9563) by @Dunqing - deps: update crate-ci/typos action to v1.46.3 (#9576) by @renovate[bot] - deps: update mimalloc-safe to 0.1.62 (#9577) by @shulaoda - mimalloc-safe: update to a bug-fix branch for verification (#9569) by @shulaoda - deps: update test262 submodule for tests (#9551) by @rolldown-guard[bot] - point published crates' readme to root README.md (#9553) by @Boshen - replace actions-cool/issues-helper with gh CLI (#9543) by @Boshen - deps: update cargo-shear to 1.12.4 (#9541) by @Boshen - deps: update taiki-e/install-action action to v2.79.4 (#9535) by @renovate[bot] - deps: update github actions (#9532) by @renovate[bot] - deps: update rust crates (#9534) by @renovate[bot] - deps: update npm packages (#9533) by @renovate[bot] - gate experimental/testing-only items to silence dead_code in publish builds (#9517) by @Boshen - docs: deploy to Void (#9509) by @Boshen - release: set up cargo-release-oxc for publishing crates (#9476) by @Boshen - rolldown_plugin_lazy_compilation: add missing description (#9507) by @Boshen - mimalloc-safe: update to a bug-fix branch for verification (#9506) by @shulaoda - deps: update crate-ci/typos action to v1.46.2 (#9468) by @renovate[bot] ### ❤️ New Contributors * @kylecannon made their first contribution in [#9580](#9580)


The on-disk
@oxc-project/runtimepackage ships two variants of every helper: a CJS form atsrc/helpers/<name>.jsthat setsmodule.exports = fn, and an ESM form atsrc/helpers/esm/<name>.jsthat doesexport default fn. The plugin previously embedded only the ESM variant and reused it for every caller, which meantrequire("@oxc-project/runtime/helpers/X")returned the ESM namespace{ default: fn }rather than the function itself.This PR embeds both variants and dispatches resolution by
ImportKind:require()gets the CJS variant (callable directly),import/ dynamicimport()get the ESM variant. Relative imports between virtual helpers preserve the importer's directory so an ESM helper's./typeof.jsstays inesm/. Fixes #9263, where_definePropertyresolved to the ESM namespace inside CJS-classified modules and threwTypeError: _defineProperty is not a functionat init.