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.

The cache applies only when all runtime output is unchanged. If a component edit changes an already evaluated server entry, it must reevaluate; this proposal does not supply finer-grained server HMR or skip that work. The fixture measures correctness, including changed loader/CSS/renderer fallbacks, and does not demonstrate an application performance improvement.

Production/RSC, multiple-entry/client and broader concurrent-runtime behavior remain outside the public fixture's coverage.

No activity

Activity on this issue will appear here.

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