Skip to content

Comments

fix(dev/hmr): ensure cjs modules with no exports reference correct module identifier#7544

Merged
hyf0 merged 3 commits intorolldown:mainfrom
leegeunhyeok:fix/hmr-cjs-no-export
Dec 18, 2025
Merged

fix(dev/hmr): ensure cjs modules with no exports reference correct module identifier#7544
hyf0 merged 3 commits intorolldown:mainfrom
leegeunhyeok:fix/hmr-cjs-no-export

Conversation

@leegeunhyeok
Copy link
Contributor

@leegeunhyeok leegeunhyeok commented Dec 17, 2025

Description

Fixes an issue where CommonJS modules with no exports reference an incorrect module identifier when registering with the HMR runtime.

Problem

StackBlitz

When CommonJS modules without exports are registered with the HMR runtime, they reference the wrong module identifier:

// other_1.js
console.log('other_1 loaded');

// main.js
require('./other_1.js');
var require_other_1 = /* @__PURE__ */ __commonJSMin(() => {
  const other_1_hot = __rolldown_runtime__.createModuleHotContext("src/other_1.js");
  __rolldown_runtime__.registerModule("src/other_1.js", module); // Invalid `module` identifier
                                                          ^^
  console.log("other_1 loaded");
});

In Node.js, this references the global module object in CommonJS environment. In runtime environments like React Native, the module identifier doesn't exist, causing an error.

Even if a module identifier exists, CJS modules with no exports always share the same export reference, leading to incorrect behavior:

const mod0 = __rolldown_runtime__.loadExports('src/other_1.js');
const mod1 = __rolldown_runtime__.loadExports('src/other_2.js');

// Different modules but identical `exports` reference
mod0 === mod1; // true

After this changes

References the module identifier from __commonJSMin scope

var require_other_1 = /* @__PURE__ */ __commonJSMin((exports, module) => {
                                                                ^^
  const other_1_hot = __rolldown_runtime__.createModuleHotContext("src/other_1.js");
  __rolldown_runtime__.registerModule("src/other_1.js", module);
                                                          ^^
  console.log("other_1 loaded");
});

@leegeunhyeok leegeunhyeok marked this pull request as draft December 17, 2025 11:22
@leegeunhyeok leegeunhyeok marked this pull request as ready for review December 17, 2025 12:17
@hyf0 hyf0 self-assigned this Dec 17, 2025
@hyf0 hyf0 requested a review from Copilot December 18, 2025 07:56
Copy link
Member

@hyf0 hyf0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

@hyf0 hyf0 enabled auto-merge (squash) December 18, 2025 07:58
… identifier

Fixes an issue where CommonJS modules without exports were not properly
referencing the module identifier for HMR runtime registration.
@hyf0 hyf0 force-pushed the fix/hmr-cjs-no-export branch from f1295c0 to 58e5fad Compare December 18, 2025 07:58
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes an HMR bug where CommonJS modules with no exports referenced an incorrect module identifier when registering with the HMR runtime. The fix ensures that the module parameter is properly included in the __commonJSMin wrapper for such modules.

Key changes:

  • Updated the condition in ast_scanner/mod.rs to mark ModuleRef usage for both ExportsKind::None and ExportsKind::CommonJs when HMR is enabled
  • Added test cases for both CJS and ESM modules with no exports to validate the fix
  • Updated snapshot expectations for hash-based filenames

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated no comments.

File Description
crates/rolldown/src/ast_scanner/mod.rs Updated condition to include ExportsKind::None when marking ModuleRef usage for HMR, with improved documentation
crates/rolldown/tests/rolldown/topics/hmr/cjs_no_export/* New test case validating CJS modules with no exports correctly use module parameter from __commonJSMin wrapper
crates/rolldown/tests/rolldown/topics/hmr/esm_no_export/* New test case validating ESM modules with no exports correctly create unique exports objects
crates/rolldown/tests/snapshots/integration_rolldown__filename_with_hash.snap Updated hash expectations for new test cases

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@netlify
Copy link

netlify bot commented Dec 18, 2025

Deploy Preview for rolldown-rs canceled.

Name Link
🔨 Latest commit 58e5fad
🔍 Latest deploy log https://app.netlify.com/projects/rolldown-rs/deploys/6943b43ac3507a0008a0e891

@hyf0 hyf0 changed the title fix(hmr): ensure cjs modules with no exports reference correct module identifier fix(dev/hmr): ensure cjs modules with no exports reference correct module identifier Dec 18, 2025
@hyf0 hyf0 merged commit 2a103e7 into rolldown:main Dec 18, 2025
26 checks passed
shulaoda added a commit that referenced this pull request Dec 22, 2025
## [1.0.0-beta.56] - 2025-12-22

### 💥 BREAKING CHANGES

- rename `MIXED_EXPORT` error to `MIXED_EXPORTS` (#7565) by @sapphi-red

### 🚀 Features

- rename `id` property to `exporter` in CIRCULAR_REEXPORT error (#7592) by @sapphi-red
- add `ids` property to `CIRCULAR_DEPENDENCY` error (#7591) by @sapphi-red
- node/dev: expose `devMode.lazy` (#7549) by @hyf0
- set log and pos properties for `parseAst` function errors (#7568) by @sapphi-red
- set log and pos properties for logs (#7567) by @sapphi-red
- test-dev-sever: support to manually configure port, run tests in concurrent (#7576) by @hyf0
- add `exporter` property to `MISSING_EXPORT` error (#7564) by @sapphi-red
- add `id` property to `PARSE_ERROR` error (#7563) by @sapphi-red
- support ImporterId hook filter (#7540) by @IWANABETHATGUY

### 🐛 Bug Fixes

- types: better "go to definition" experience for interface `OutputPlugin` (#7610) by @KazariEX
- `postBanner` content should be placed after shebang (#7583) by @btea
- use sanitized filename for preserve modules chunk name (#7603) by @IWANABETHATGUY
- correct filter out unused cjs namespace  (#7602) by @IWANABETHATGUY
- watch: property respect `notify.pollInternal` and `notify.compareContents` (#7595) by @sapphi-red
- make `cleanDir` work with default output directory (#7579) by @shulaoda
- merge `MISSING_NAME_OPTION_FOR_UMD_EXPORT` error to `MISSING_NAME_OPTION_FOR_IIFE_EXPORT` error (#7566) by @sapphi-red
- dev/hmr: ensure cjs modules with no exports reference correct `module` identifier (#7544) by @leegeunhyeok

### 🚜 Refactor

- remove `stable_id` field from `PARSE_ERROR` error (#7593) by @sapphi-red
- make include_runtime_symbol reuseable after linking stage (#7580) by @IWANABETHATGUY
- rust/dev: construct the bundler within itself (#7553) by @hyf0
- rust/watcher: polish API of `Watcher` struct (#7551) by @hyf0
- use `LinkingMetadata::stmt_info_included` to check if a stmt_info is included (#7572) by @IWANABETHATGUY
- use `LinkingMetadata::is_included` to check if a module is included (#7571) by @IWANABETHATGUY
- store module and stmt_info is included info to module meta (#7570) by @IWANABETHATGUY
- make include_* method reunsable after linking stage (#7552) by @IWANABETHATGUY
- rust/watcher: construct the bundler within watcher itself (#7550) by @hyf0
- extract make include_runtime_symbol reusable (#7546) by @IWANABETHATGUY

### ⚙️ Miscellaneous Tasks

- renovate: add `kill-port` in `ignoreDeps` in renovate.json (#7619) by @sapphi-red
- deps: update rust crates (#7617) by @renovate[bot]
- deps: update npm packages (#7616) by @renovate[bot]
- deps: update github-actions (#7615) by @renovate[bot]
- ci: skip benchmark workflows on draft PRs (#7611) by @Copilot
- deps: update dependency rolldown-plugin-dts to ^0.19.0 (#7607) by @renovate[bot]
- deps: update dependency oxlint-tsgolint to v0.10.0 (#7601) by @renovate[bot]
- deps: update dependency rolldown-plugin-dts to v0.18.4 (#7599) by @renovate[bot]
- deps: update notify (#7594) by @sapphi-red
- test-dev-server: add retry mechanism to hmr-full-bundle-mode tests (#7588) by @Copilot
- deps: update napi to v3.7.1 (#7590) by @renovate[bot]
- add JSDoc documentation for memfs type (#7587) by @Copilot
- deps: update dependency oxlint to v1.34.0 (#7589) by @renovate[bot]
- move some tests in ignored-by-unsupported-features that are passing (#7569) by @sapphi-red
- deps: update dependency oxlint-tsgolint to v0.9.2 (#7582) by @renovate[bot]
- deps: update oxc resolver to v11.16.0 (#7574) by @renovate[bot]
- test/dev-server: don't run `pnpm install` during tests (#7560) by @hyf0
- test/dev-server: use `kill-port@1` to improve performance (#7575) by @hyf0
- normalize error object to make some Rollup tests pass (#7562) by @sapphi-red
- ci: separate dev-server(hmr) tests and normal tests (#7558) by @hyf0
- ci: make native rolldown build reusable (#7557) by @hyf0
- resolve some TODOs (#7561) by @sapphi-red

### ❤️ New Contributors

* @KazariEX made their first contribution in [#7610](#7610)
* @leegeunhyeok made their first contribution in [#7544](#7544)

Co-authored-by: shulaoda <[email protected]>
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.

2 participants