Skip to content

fix: skip inlining stale CJS export constants on module.exports reassignment#8990

Merged
graphite-app[bot] merged 1 commit intomainfrom
04-02-fix_default_property_read_should_not_use
Apr 2, 2026
Merged

fix: skip inlining stale CJS export constants on module.exports reassignment#8990
graphite-app[bot] merged 1 commit intomainfrom
04-02-fix_default_property_read_should_not_use

Conversation

@IWANABETHATGUY
Copy link
Copy Markdown
Member

@IWANABETHATGUY IWANABETHATGUY commented Apr 2, 2026

Summary

When a CJS module uses both exports.foo = 1 and module.exports = { foo: 2 }, the exports.foo constant was incorrectly inlined as 1 instead of preserving the runtime property access that yields 2.

This PR adds fine-grained detection of module.exports reassignment during scanning:

  • Object literal RHS (module.exports = { foo, bar }): only invalidates exports.xxx constants whose names overlap with the object's static properties. Non-conflicting constants are still eligible for inlining.
  • Non-analyzable RHS (function call, variable, computed keys, spread): invalidates all exports.xxx constants since we can't statically determine the property set.

Uses a ModuleExportsReassignment enum (None / KnownProps(set) / Unknown) to track this, feeding stale symbol IDs into the existing bailout_inlined_cjs_exports_symbol_ids set.

Test plan

  • Added default_property_read_should_not_use_stale_exports — object literal RHS, conflicting prop is not inlined, non-conflicting prop is still inlined
  • Added default_property_read_should_not_use_stale_exports_non_object — function call RHS, blanket bailout on all CJS constants
  • All 768 fixture tests pass
  • just lint passes (clippy + fmt + check)

Copy link
Copy Markdown
Member Author


How to use the Graphite Merge Queue

Add 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.

@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 2, 2026

Deploy Preview for rolldown-rs canceled.

Name Link
🔨 Latest commit 7bcb2e0
🔍 Latest deploy log https://app.netlify.com/projects/rolldown-rs/deploys/69ce26db913b5b0008feecb6

@IWANABETHATGUY IWANABETHATGUY force-pushed the 04-02-fix_default_property_read_should_not_use branch from 042d271 to 2d41d65 Compare April 2, 2026 05:27
@IWANABETHATGUY IWANABETHATGUY changed the title fix: default property read should not use fix: skip inlining stale CJS export constants on module.exports reassignment Apr 2, 2026
@IWANABETHATGUY IWANABETHATGUY force-pushed the 04-02-fix_default_property_read_should_not_use branch from 8f331c0 to 6397dbe Compare April 2, 2026 05:51
@IWANABETHATGUY IWANABETHATGUY marked this pull request as ready for review April 2, 2026 08:18
@graphite-app
Copy link
Copy Markdown
Contributor

graphite-app Bot commented Apr 2, 2026

Merge activity

…ignment (#8990)

## Summary

When a CJS module uses both `exports.foo = 1` and `module.exports = { foo: 2 }`, the `exports.foo` constant was incorrectly inlined as `1` instead of preserving the runtime property access that yields `2`.

This PR adds fine-grained detection of `module.exports` reassignment during scanning:
- **Object literal RHS** (`module.exports = { foo, bar }`): only invalidates `exports.xxx` constants whose names overlap with the object's static properties. Non-conflicting constants are still eligible for inlining.
- **Non-analyzable RHS** (function call, variable, computed keys, spread): invalidates all `exports.xxx` constants since we can't statically determine the property set.

Uses a `ModuleExportsReassignment` enum (`None` / `KnownProps(set)` / `Unknown`) to track this, feeding stale symbol IDs into the existing `bailout_inlined_cjs_exports_symbol_ids` set.

## Test plan

- [x] Added `default_property_read_should_not_use_stale_exports` — object literal RHS, conflicting prop is not inlined, non-conflicting prop is still inlined
- [x] Added `default_property_read_should_not_use_stale_exports_non_object` — function call RHS, blanket bailout on all CJS constants
- [x] All 768 fixture tests pass
- [x] `just lint` passes (clippy + fmt + check)
@graphite-app graphite-app Bot force-pushed the 04-02-fix_default_property_read_should_not_use branch from 6397dbe to 7bcb2e0 Compare April 2, 2026 08:20
@graphite-app graphite-app Bot merged commit 7bcb2e0 into main Apr 2, 2026
31 checks passed
@graphite-app graphite-app Bot deleted the 04-02-fix_default_property_read_should_not_use branch April 2, 2026 08:24
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Apr 2, 2026

Merging this PR will not alter performance

✅ 4 untouched benchmarks
⏩ 10 skipped benchmarks1


Comparing 04-02-fix_default_property_read_should_not_use (7bcb2e0) with main (eb1ab09)2

Open in CodSpeed

Footnotes

  1. 10 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on main (7bcb2e0) during the generation of this report, so eb1ab09 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

This was referenced Apr 8, 2026
shulaoda added a commit that referenced this pull request Apr 8, 2026
## [1.0.0-rc.14] - 2026-04-08

### 🚀 Features

- rust: add `disable_panic_hook` feature to disable the panic hook (#9023) by @sapphi-red
- support inlineConst for CJS exports accessed through module.exports (#8976) by @h-a-n-a

### 🐛 Bug Fixes

- rolldown_plugin_vite_import_glob: normalize resolved alias path to prevent double slashes (#9032) by @shulaoda
- rolldown_plugin_vite_import_glob: follow symlinks in file scanning (#9000) by @Copilot
- wrap CJS entry modules for IIFE/UMD when using exports/module (#8999) by @IWANABETHATGUY
- emit separate __toESM bindings for mixed ESM/CJS external imports (#8987) by @IWANABETHATGUY
- tree-shake dead dynamic imports to side-effect-free CJS modules (#8529) by @sapphi-red
- skip inlining stale CJS export constants on module.exports reassignment (#8990) by @IWANABETHATGUY

### 🚜 Refactor

- generator: migrate ecma formatting from npx oxfmt to vp fmt (#9022) by @shulaoda
- generator: replace npx oxfmt with vp fmt for ecma formatting (#9021) by @shulaoda

### 📚 Documentation

- contrib-guide: mention that running tests on older Node.js version will have different stat results (#8996) by @claude

### ⚙️ Miscellaneous Tasks

- deps: update npm packages (#9002) by @renovate[bot]
- deps: update dependency @napi-rs/cli to v3.6.1 (#9034) by @renovate[bot]
- deps: upgrade oxc to 0.124.0 (#9018) by @shulaoda
- deps: update test262 submodule for tests (#9010) by @sapphi-red
- deps: update dependency oxfmt to ^0.44.0 (#9012) by @renovate[bot]
- deps: update dependency vite to v8.0.5 [security] (#9009) by @renovate[bot]
- deps: update dependency vite-plus to v0.1.16 (#9008) by @renovate[bot]
- deps: update rust crates (#9003) by @renovate[bot]
- deps: update github-actions (#9004) by @renovate[bot]
- deps: update dependency lodash-es to v4.18.1 [security] (#8992) by @renovate[bot]
- deps: update crate-ci/typos action to v1.45.0 (#8988) by @renovate[bot]
- upgrade oxc npm packages to 0.123.0 (#8985) by @shulaoda

### ◀️ Revert

- "chore(deps): update dependency oxfmt to ^0.44.0 (#9012)" (#9019) by @shulaoda

Co-authored-by: shulaoda <165626830+shulaoda@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants