Skip to content

[Perf]: reuse unchanged server builds while preserving manifest and data refresh #140

Description

@matthewdavis-oai

Problem

A new Node compilation can reevaluate unchanged server modules before Hot Data Revalidation (HDR) refreshes route loader data. Requested: retain an evaluated build when compatible, while still committing the matching browser manifest and acknowledging HDR for the accepted compilation.

Published rsbuild-plugin-react-router 0.8.1 evaluates server builds when the Node compilation changes. evaluateServerBuilds calls loadBundle for each entry. Rsbuild 2.2.9 caches by Stats and entry, so a new compilation creates a fresh runner on first load.

Local implementation and contract

An unpublished source candidate adds:

pluginReactRouter({ unstableDevServerBuildCache: true })

It retains the accepted build only when all non-debug-map runtime outputs, membership and loading layout remain unchanged after complete successful emission. Changed unloaded JavaScript and same-name JSON/WASM changes take fresh evaluation. Unknown metadata, failures and superseded generations invalidate reuse. The option defaults off and applies only to classic development. Published 0.8.1 does not include it; the local package still carries that version.

Module state and initialization-time reads persist across same-output edits, including registered dependencies. Read changing data per request, encode it into output, or restart development to reset. Source-map-only changes need not refresh existing VM debugging state. This is an explicit state-lifetime policy.

Every accepted generation still receives a new manifest-pinned envelope and advances Node identity before notifications. Existing dependency snapshots and compiler-pairing checks remain. The cache reads compiler metadata, not asset contents; its observer still has measurable overhead.

Reproduction and source patches

Download the source-only reproduction and setup instructions. Run node public-repro-package.mjs ./router-cache-repro, then follow its README. The package contains three patches against published commit dc11d26292f014a62276eb7dddf9c16e7b5faa47: separate CSS-manifest prerequisites, the single-development-entry prerequisite, then the typed seven-file cache implementation. All three reproduce the candidate's 82 source files exactly. Its README gives source-build commands and pinned dependencies; fresh dependency installation remains untested, and the fixture has no transitive lockfile.

The fixture uses Node 24.19.0, Rsbuild 2.2.8, Rspack 2.2.6 and React Router 7.18.1. Omitted/enabled controls cover 20 stages each: singleton continuity, intentionally retained registered-input values, same-name emitted JSON changes with identical JavaScript, changed loaders/CSS/renderer, unloaded imports, output removal, post-emission failure and superseded evaluation. WebSocket receipts check committed manifest identity and manifest-before-HDR order. Results and package hashes accompany this tiny compiler/SSR test; it has no browser or performance claim.

Remaining boundary

Rsbuild #8496 contains the executed public reproduction of the broader consumed-output request: preserve eager modules when only an unloaded chunk changes, while ensuring future imports are fresh. That requires runner-level support; this Router candidate rejects that case.

A separate application diagnostic recorded the entry actually passed to the VM changing from 65,400,789 to 65,400,850 bytes on a component edit. Restoration restored those bytes. Neither unchanged-output policy can skip that edit at the current bundle boundary. This diagnostic is not a timing sample and lacks a final process record.

The local application lane on Rsbuild 2.2.9 / Rspack 2.2.7 reused two CSS generations and evaluated two component generations. Two clean samples establish no speedup. All 15 original application development tests passed, including lazy navigation, JS/CSS HMR, streamed SSR, reload and checkout; exact source/config/package restoration was independently checked. This uses local patches, not released-package behavior. Known fixture 404s and a nonce-only hydration warning remain. Production/RSC, multi-entry/client and broader concurrency coverage remain separate.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    blockedBlocked on an external dependency or upstream change

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions