Skip to content

fix(core): preserve lazy compilation HMR state#8091

Open
ScriptedAlchemy wants to merge 11 commits into
mainfrom
codex/lazy-compilation-hmr-provenance
Open

fix(core): preserve lazy compilation HMR state#8091
ScriptedAlchemy wants to merge 11 commits into
mainfrom
codex/lazy-compilation-hmr-provenance

Conversation

@ScriptedAlchemy

@ScriptedAlchemy ScriptedAlchemy commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Preserves completed-build provenance per environment so Rsbuild distinguishes proven lazy activations from file-backed or ambiguous invalidations, including delayed clients, duplicate stats, reconnects, and errors. Normal invalidations dominate mixed cycles and ambiguous state fails closed to a document reload.

The client uses a pure immutable hash-state reducer and applies proven lazy updates with ignoreUnaccepted plus Rspack's preserveDisposedModuleFactories option. Initial-chunk-set changes retain the existing safety reload because newly introduced static module factories cannot be installed by a hot update alone. The compatibility helper remains guarded by TODO(rspack#14753) until the minimum Rspack version contains the upstream API.

Related links

Tests

  • Focused core/server unit tests passed, including new-hash provenance and initial-chunk reload regressions.
  • Lazy add-initial-chunk E2E passed through the required reload path.
  • Dynamic import, source/CSS HMR, reconnect, and stale-restart E2Es passed without document reload.
  • Paired local Rspack binding: exact lazy E2E files passed.
  • CI is tracked on the latest head.

@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The change adds cause-aware lazy-compilation HMR tracking to the server and client. Build invalidation causes are propagated into websocket messages, while the client maintains reducer-backed hash state and applies lazy-specific HMR options. Server and reducer tests cover provenance, reconnects, duplicate hashes, resets, and fail-closed reloads. End-to-end coverage verifies document-load counts, initial chunks, active lazy-entry updates, websocket reconnects, and stale-hash reloads.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately summarizes the main change: preserving lazy compilation HMR state.
Description check ✅ Passed The description matches the implemented lazy-compilation HMR state and reload behavior changes.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e4c1e93d51

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/core/src/server/socketServer.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/core/src/server/socketServer.ts (1)

264-277: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Delay clearing lazy-compilation state until after sendStats()

sendStats() reads both lazyCompilationInvalidationTokens and currentHashLazyCompilation; clearing them before the socket loop makes the current build look like a normal rebuild, so the client misses the lazy-compilation-hash signal. Move those clears to after the loop, while keeping the no-sockets path cleared.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/server/socketServer.ts` around lines 264 - 277, In
onBuildDone(), defer clearing lazyCompilationInvalidationTokens and
currentHashLazyCompilation until after the sendStats() loop so the current build
retains its lazy-compilation state; preserve clearing for the no-sockets path
before returning.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/server/assets-middleware/index.ts`:
- Around line 119-133: Isolate the Rspack-specific lazy-compilation detection in
a compatibility helper, including access to the
Symbol.for('rspack.lazyCompilationCurrent') flag and modifiedFiles/removedFiles;
keep the helper version-locked to the supported `@rspack/core` range and have the
thisCompilation hook use that helper instead of accessing internals directly.

---

Outside diff comments:
In `@packages/core/src/server/socketServer.ts`:
- Around line 264-277: In onBuildDone(), defer clearing
lazyCompilationInvalidationTokens and currentHashLazyCompilation until after the
sendStats() loop so the current build retains its lazy-compilation state;
preserve clearing for the no-sockets path before returning.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5008a20d-0a60-4db6-8cd6-6fd40af177de

📥 Commits

Reviewing files that changed from the base of the PR and between ac66d10 and e4c1e93.

📒 Files selected for processing (5)
  • e2e/cases/lazy-compilation/dynamic-import/index.test.ts
  • packages/core/rslib.config.ts
  • packages/core/src/client/hmr.ts
  • packages/core/src/server/assets-middleware/index.ts
  • packages/core/src/server/socketServer.ts

Comment thread packages/core/src/server/assets-middleware/index.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/core/tests/server.test.ts (1)

528-529: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove duplicate sendStats declaration in the type cast.

Line 529 is an exact duplicate of line 528 — the sendStats method signature appears twice in the internals type assertion. This is a copy-paste artifact with no functional effect but should be cleaned up.

♻️ Proposed fix
     const internals = socketServer as unknown as {
       lazyCompilationInvalidationTokens: Set<string>;
       socketsMap: Map<string, Set<never>>;
       sendStats(options: { token: string }): void;
-      sendStats(options: { token: string }): void;
     };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/tests/server.test.ts` around lines 528 - 529, Remove the
duplicate sendStats declaration from the internals type assertion in the server
test, keeping a single sendStats(options: { token: string }): void signature
alongside socketsMap.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/core/tests/server.test.ts`:
- Around line 528-529: Remove the duplicate sendStats declaration from the
internals type assertion in the server test, keeping a single sendStats(options:
{ token: string }): void signature alongside socketsMap.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 88400665-0780-4103-aa3f-e36cc8eb31d7

📥 Commits

Reviewing files that changed from the base of the PR and between e4c1e93 and 1b9e9d5.

📒 Files selected for processing (2)
  • packages/core/src/server/socketServer.ts
  • packages/core/tests/server.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/server/socketServer.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/core/src/client/hmr.ts (1)

411-428: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Minor duplication between hash and lazy-compilation-hash cases.

The two branches differ only in the boolean passed to rememberHash; could be merged into a single fallthrough case.

♻️ Optional consolidation
       case 'hash':
-        rememberHash(message.data, false);
-
-        if (clearOverlay && shouldUpdate()) {
-          clearOverlay();
-        }
-        break;
       case 'lazy-compilation-hash':
-        rememberHash(message.data, true);
+        rememberHash(message.data, message.type === 'lazy-compilation-hash');
 
         if (clearOverlay && shouldUpdate()) {
           clearOverlay();
         }
         break;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/src/client/hmr.ts` around lines 411 - 428, Merge the `hash` and
`lazy-compilation-hash` branches in `onMessage` into a shared case, preserving
their distinct `rememberHash` boolean values while consolidating the duplicated
`clearOverlay` and `shouldUpdate` logic. Keep both message types’ existing
behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/core/src/client/hmr.ts`:
- Around line 411-428: Merge the `hash` and `lazy-compilation-hash` branches in
`onMessage` into a shared case, preserving their distinct `rememberHash` boolean
values while consolidating the duplicated `clearOverlay` and `shouldUpdate`
logic. Keep both message types’ existing behavior unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 71feeb31-7c0b-4205-a9e2-50e9ae588ec3

📥 Commits

Reviewing files that changed from the base of the PR and between 1b9e9d5 and 73643c2.

📒 Files selected for processing (2)
  • packages/core/src/client/hmr.ts
  • packages/core/src/server/assets-middleware/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/server/assets-middleware/index.ts

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 13, 2026

Copy link
Copy Markdown

Deploying rsbuild with  Cloudflare Pages  Cloudflare Pages

Latest commit: e6040a9
Status: ✅  Deploy successful!
Preview URL: https://2a8cc807.rsbuild-v2.pages.dev
Branch Preview URL: https://codex-lazy-compilation-hmr-p.rsbuild-v2.pages.dev

View logs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/core/tests/server.test.ts (1)

518-605: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Solid coverage of the retention/override contract; consider one more case.

The three tests thoroughly verify same-hash retention and normal-overrides-lazy behavior, but none vary stats.hash across onBuildDone() calls. Add a case where a build produces a new hash with no pending cause set, to explicitly assert that a prior 'lazy' record doesn't leak forward onto an unrelated hash (the implementation already handles this correctly via the previousRecord?.hash === hash guard, but it isn't directly asserted).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/core/tests/server.test.ts` around lines 518 - 605, Add a test
alongside the existing provenance tests using createSocketServerHarness that
records a lazy build, changes stats.hash to a new value, then calls onBuildDone
without setting another invalidation cause. Assert connect() emits a normal hash
message for the new hash, confirming the prior lazy provenance does not carry
across hashes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/core/tests/server.test.ts`:
- Around line 518-605: Add a test alongside the existing provenance tests using
createSocketServerHarness that records a lazy build, changes stats.hash to a new
value, then calls onBuildDone without setting another invalidation cause. Assert
connect() emits a normal hash message for the new hash, confirming the prior
lazy provenance does not carry across hashes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 89b0de67-dfb9-4b65-892a-b670f8d1e2c9

📥 Commits

Reviewing files that changed from the base of the PR and between 73643c2 and e6040a9.

📒 Files selected for processing (14)
  • e2e/cases/lazy-compilation/add-initial-chunk/index.test.ts
  • e2e/cases/lazy-compilation/add-initial-chunk/rsbuild.config.ts
  • e2e/cases/lazy-compilation/hmr-lifecycle/index.test.ts
  • e2e/cases/lazy-compilation/hmr-lifecycle/rsbuild.config.ts
  • e2e/cases/lazy-compilation/hmr-lifecycle/src/page1/App.css
  • e2e/cases/lazy-compilation/hmr-lifecycle/src/page1/App.jsx
  • e2e/cases/lazy-compilation/hmr-lifecycle/src/page1/index.jsx
  • e2e/cases/lazy-compilation/hmr-lifecycle/src/page2/index.js
  • packages/core/src/client/hmr.ts
  • packages/core/src/client/hmrHashState.ts
  • packages/core/src/server/assets-middleware/index.ts
  • packages/core/src/server/socketServer.ts
  • packages/core/tests/hmrHashState.test.ts
  • packages/core/tests/server.test.ts

@ScriptedAlchemy

Copy link
Copy Markdown
Contributor Author

Added the suggested cross-hash provenance regression in 9f23a69. It records a lazy build at hash-1, advances to hash-2 without a pending cause, and verifies the new hash emits the normal hash message. Focused packages/core/tests/server.test.ts: 11/11 passed; rslint and oxfmt passed.

@ScriptedAlchemy

Copy link
Copy Markdown
Contributor Author

Paired validation found one necessary boundary: a proven lazy cycle may stay in-document only while the initial chunk set is stable. A newly introduced static initial module has no installed factory, so the existing safety reload must remain. Commit 49ec591 restores that guard, adds a focused server regression, and keeps dynamic-import/lifecycle HMR same-document. Focused server tests and exact lazy E2Es pass.

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.

1 participant