refactor(treeshake): migrate SideEffectDetector to Oxc's MayHaveSideEffects trait#8624
refactor(treeshake): migrate SideEffectDetector to Oxc's MayHaveSideEffects trait#8624
Conversation
✅ Deploy Preview for rolldown-rs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Pull request overview
This PR updates Rolldown’s side-effect analysis by migrating much of SideEffectDetector logic to Oxc’s MayHaveSideEffects machinery (via a new bundler-aware context), bumps Oxc to 0.117.0, and refreshes many integration snapshots to match the new tree-shaking/codegen output.
Changes:
- Refactor
SideEffectDetectorto delegate side-effect decisions to Oxc (MayHaveSideEffects) while preserving bundler-specific overrides viaBundlerSideEffectCtx. - Bump Oxc crate versions to
0.117.0and updateCargo.lockaccordingly. - Update numerous test snapshots to reflect new tree-shaking and runtime helper emission.
Reviewed changes
Copilot reviewed 43 out of 44 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| crates/rolldown/src/ast_scanner/side_effect_detector/mod.rs | Refactors side-effect detection to use Oxc MayHaveSideEffects with a bundler-aware context and adds parity assertions/tests. |
| crates/rolldown/src/ast_scanner/side_effect_detector/bundler_ctx.rs | New adapter implementing Oxc’s MayHaveSideEffectsContext using Rolldown options/scopes and cross-module pure-call marking. |
| crates/rolldown/src/ast_scanner/side_effect_detector/utils.rs | Removes most legacy helper logic after migration to Oxc’s implementation. |
| Cargo.toml | Bumps Oxc crates to 0.117.0 and adds a [patch.crates-io] section for local Oxc paths. |
| Cargo.lock | Updates lockfile for the Oxc bump and dependency graph changes. |
| crates/rolldown/tests/rolldown/tree_shaking/export_star/artifacts.snap | Snapshot update for changed export-star output/inlining. |
| crates/rolldown/tests/rolldown/tree_shaking/commonjs_mixed/artifacts.snap | Snapshot update reflecting new tree-shaking of global property accesses. |
| crates/rolldown/tests/rolldown/tree_shaking/commonjs_inline_const_computed_key_write_object/artifacts.snap | Snapshot update reflecting new tree-shaking of global property accesses. |
| crates/rolldown/tests/rolldown/topics/keep_names/issue_7481_2/artifacts.snap | Snapshot update reflecting changed emitted helpers/side-effect classification. |
| crates/rolldown/tests/rolldown/topics/keep_names/if_stmt/artifacts.snap | Snapshot update reflecting changed emitted helpers/side-effect classification. |
| crates/rolldown/tests/rolldown/topics/deconflict/wrapped_esm_export_named_function/artifacts.snap | Snapshot update reflecting changed prelude/helper emission and mapping offsets. |
| crates/rolldown/tests/rolldown/topics/deconflict/wrapped_esm_default_function/artifacts.snap | Snapshot update reflecting changed prelude/helper emission and mapping offsets. |
| crates/rolldown/tests/rolldown/plugin/plugin_context/custom_arg_in_resolve/artifacts.snap | Snapshot update reflecting new external require wrapper emission. |
| crates/rolldown/tests/rolldown/issues/5923/artifacts.snap | Snapshot update reflecting new tree-shaking behavior for export-star helpers. |
| crates/rolldown/tests/rolldown/issues/4472/artifacts.snap | Snapshot update reflecting new tree-shaking behavior for export-star helpers. |
| crates/rolldown/tests/rolldown/function/shim_missing_exports/basic_wrapped_esm/artifacts.snap | Snapshot update reflecting changed emitted helpers/side-effect classification. |
| crates/rolldown/tests/rolldown/function/module_types/issue-6345/artifacts.snap | Snapshot update reflecting inlining of CJS wrapper. |
| crates/rolldown/tests/rolldown/errors/plugin_error/artifacts.snap | Snapshot update; now includes a Rust backtrace in output. |
| crates/rolldown/tests/rolldown/cjs_compat/require/require_esm/artifacts.snap | Snapshot update reflecting changed emitted helpers/side-effect classification. |
| crates/rolldown/tests/rolldown/cjs_compat/esm_require_esm_unused/artifacts.snap | Snapshot update reflecting changed emitted helpers/side-effect classification. |
| crates/rolldown/tests/esbuild/ts/ts_export_missing_es6/artifacts.snap | Snapshot update reflecting export-all helper inlining. |
| crates/rolldown/tests/esbuild/ts/ts_experimental_decorators_keep_names/artifacts.snap | Snapshot update reflecting changed emitted helpers/side-effect classification. |
| crates/rolldown/tests/esbuild/ts/export_type_issue379/artifacts.snap | Snapshot update reflecting export-all helper inlining/reordering. |
| crates/rolldown/tests/esbuild/loader/require_custom_extension_string/artifacts.snap | Snapshot update reflecting inlining of CJS wrapper. |
| crates/rolldown/tests/esbuild/loader/require_custom_extension_data_url/artifacts.snap | Snapshot update reflecting inlining of CJS wrapper. |
| crates/rolldown/tests/esbuild/loader/require_custom_extension_base64/artifacts.snap | Snapshot update reflecting inlining of CJS wrapper. |
| crates/rolldown/tests/esbuild/loader/loader_file/artifacts.snap | Snapshot update reflecting inlining of CJS wrapper. |
| crates/rolldown/tests/esbuild/loader/auto_detect_mime_type_from_extension/artifacts.snap | Snapshot update reflecting inlining of CJS wrapper. |
| crates/rolldown/tests/esbuild/importstar/issue176/artifacts.snap | Snapshot update reflecting export-all helper inlining. |
| crates/rolldown/tests/esbuild/importstar_ts/ts_import_star_export_star_capture/artifacts.snap | Snapshot update reflecting export-all helper inlining. |
| crates/rolldown/tests/esbuild/importstar_ts/ts_import_star_export_star_as_capture/artifacts.snap | Snapshot update reflecting export-all helper inlining. |
| crates/rolldown/tests/esbuild/importstar_ts/ts_import_star_export_import_star_capture/artifacts.snap | Snapshot update reflecting export-all helper inlining. |
| crates/rolldown/tests/esbuild/importstar_ts/ts_import_star_common_js_no_capture/artifacts.snap | Snapshot update reflecting new tree-shaking of global property accesses. |
| crates/rolldown/tests/esbuild/importstar_ts/ts_import_star_capture/artifacts.snap | Snapshot update reflecting export-all helper inlining. |
| crates/rolldown/tests/esbuild/default/top_level_await_forbidden_require/artifacts.snap | Snapshot update reflecting changed emitted helpers/side-effect classification. |
| crates/rolldown/tests/esbuild/default/top_level_await_forbidden_require_dead_branch/artifacts.snap | Snapshot update reflecting changed emitted helpers/side-effect classification. |
| crates/rolldown/tests/esbuild/default/require_txt/artifacts.snap | Snapshot update reflecting inlining of CJS wrapper. |
| crates/rolldown/tests/esbuild/default/require_json/artifacts.snap | Snapshot update reflecting inlining of CJS wrapper. |
| crates/rolldown/tests/esbuild/default/require_fs_browser/artifacts.snap | Snapshot update reflecting new external require wrapper emission. |
| crates/rolldown/tests/esbuild/default/require_child_dir_common_js/artifacts.snap | Snapshot update reflecting inlining of CJS wrapper. |
| crates/rolldown/tests/esbuild/default/export_forms_common_js/artifacts.snap | Snapshot update reflecting changed emitted helpers/side-effect classification. |
| crates/rolldown/tests/esbuild/default/bundle_esm_with_nested_var_issue4348/artifacts.snap | Snapshot update reflecting changed emitted helpers/side-effect classification. |
| crates/rolldown/tests/esbuild/dce/package_json_side_effects_false_keep_bare_import_and_require_es6/artifacts.snap | Snapshot update reflecting changed emitted helpers/side-effect classification. |
| crates/rolldown/tests/esbuild/dce/dce_of_symbol_instances/artifacts.snap | Snapshot update reflecting new DCE behavior for Symbol.* references. |
crates/rolldown/tests/rolldown/errors/plugin_error/artifacts.snap
Outdated
Show resolved
Hide resolved
crates/rolldown/tests/rolldown/plugin/plugin_context/custom_arg_in_resolve/artifacts.snap
Show resolved
Hide resolved
32b1bbc to
f215fd6
Compare
|
I guess oxc doesn't care about cjs related stuffs? #8659 |
Yes, keep some Rolldown-specific checks as-is, and any others are delegated to Oxc |
3162ca3 to
1ee3871
Compare
0b9eb73 to
5ad37d9
Compare
MayHaveSideEffectsContext of Oxc41fb951 to
af5df21
Compare
Merging this PR will not alter performance
Comparing Footnotes
|
31ecc48 to
2d56a64
Compare
|
Ready to review now; the PR description explains what checks still remain on the Rolldown side. Note to reviewer: Due to the Oxc's |
Boshen
left a comment
There was a problem hiding this comment.
I see some discrepancies, the rule should be always follow the spec going forward.
…ffects trait Delegate expression/statement side-effect analysis to Oxc's `MayHaveSideEffects` trait instead of reimplementing it. SideEffectDetector now implements `MayHaveSideEffectsContext` and `GlobalContext` directly, keeping only bundler-specific logic (CJS exports, import.meta, module declarations, cross-module pure call tracking, metadata flags like GlobalVarAccess/PureAnnotation). - Remove `utils.rs` (593 lines) and `global_reference.rs` (828 lines) - Remove `BundlerSideEffectCtx` bridge type, merging fields/traits into SideEffectDetector - Remove `phf` dependency from rolldown_utils Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
2d56a64 to
82e6b4a
Compare
|
Thank you everyone for reviewing this! We have 5 approvals now; I am going to merge this! |
## [1.0.0-rc.12] - 2026-03-25 ### 🚀 Features - chunk-optimizer: skip circular dependency check when strict execution order is enabled (#8886) by @hyf0 ### 🐛 Bug Fixes - emit build warnings during watch mode rebuilds (#8897) by @IWANABETHATGUY - lazy-barrel: load import-then-export specifiers when barrel has local exports (#8895) by @shulaoda - correct execution order of transferred CJS init calls (#8877) by @IWANABETHATGUY - mcs: `entriesAware` should calculate sizes without duplication (#8887) by @hyf0 - non-deterministic chunk generation (#8882) by @sapphi-red - `is_top_level` incorrectly treats strict-mode scopes as top-level (#8878) by @Dunqing ### 🚜 Refactor - treeshake: migrate SideEffectDetector to Oxc's MayHaveSideEffects trait (#8624) by @Dunqing ### 🧪 Testing - make dev server tests deterministic by replacing fixed sleeps with event-driven polling (#8561) by @Boshen ### ⚙️ Miscellaneous Tasks - deps: update dependency vite-plus to v0.1.14 (#8902) by @camc314 - deps: update dependency oxfmt to ^0.42.0 (#8891) by @renovate[bot] - deps: update rust crate oxc_sourcemap to v6.1.1 (#8890) by @renovate[bot] - remove Rolldown MF plan (#8883) by @shulaoda - deps: update rollup submodule for tests to v4.60.0 (#8881) by @sapphi-red - deps: update test262 submodule for tests (#8880) by @sapphi-red - deps: upgrade oxc crates to 0.122.0 (#8879) by @shulaoda Co-authored-by: shulaoda <[email protected]>
Summary
Closes: #7918
MayHaveSideEffectstrait instead of reimplementing itSideEffectDetectornow implementsMayHaveSideEffectsContextandGlobalContextdirectly, keeping only bundler-specific logicutils.rs(593 lines) andglobal_reference.rs(828 lines) — logic now lives in OxcBundlerSideEffectCtxbridge type, merging its fields and trait impls intoSideEffectDetectorphfdependency fromrolldown_utils[] = rhs,{} = rhs) were incorrectly treated as side-effect-free — now delegated to Oxc which correctly identifiesGetIterator/RequireObjectCoercibleas observable+=,-=,||=, etc.) were missing a side-effect check — now delegated to Oxc which correctly treats them as always side-effectfulNet: -1555 lines
Why some checks still can't be delegated to Oxc
Oxc's
MayHaveSideEffectsis a pure JS semantics analysis — it has no concept of bundler-level concerns. The remaining Rolldown-specific overrides are:SideEffectDetailmetadata flags (GlobalVarAccess,PureAnnotation,PureCjs)bool.import.meta.*is side-effect-freeimport.metaas aMetaPropertywith no special semantics. The bundler knowsimport.meta.urletc. are safe reads because it controls their resolution.exports.foo = ...patternexports) — side-effectful. The bundler knows this is a CJS export assignment and marks itPureCjs. Must be checked before delegating to Oxc.side_effect_free_call_expr_addr)import/export)usingdeclarationsusingdeclarators (onlynull,undefined, orvoid exprinitializers are side-effect-free). This is stricter than generic analysis becauseusinginvokesSymbol.dispose.property_read_side_effects, array destructuring checks for nested patterns. These interact with bundler options that Oxc doesn't model at the statement level./*@__PURE__*/calls, Rolldown must re-check args through its own detector (not Oxc's) because bundler-specific overrides (e.g.import.meta.*) apply to args too.Test plan
Related: oxc-project/oxc#19673
🤖 Generated with Claude Code