Simplify loader flight and render acknowledgement ownership - #7926
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
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. Comment |
|
View your CI Pipeline Execution ↗ for commit bcde937
☁️ Nx Cloud last updated this comment at |
🚀 Changeset Version Preview4 package(s) bumped directly, 19 bumped as dependents. 🟩 Patch bumps
|
Bundle Size Benchmarks
The following scenarios have bundle-size changes compared with the baseline:
Current gzip tracks all emitted client JS chunks. Initial gzip tracks only the entry/import graph. Trend sparkline is historical current gzip ending with this PR measurement; lower is better. |
Merging this PR will regress 7 benchmarks
|
00d68c4
into
fix-router-core-lane-match-loader
Summary
This stacks on #7805 and simplifies its match-loading rewrite around one rule: each match ID has at most one discoverable loader generation, each flight has one normalized outcome, and lane ownership decides where that outcome may publish.
The change closes the supported orchestration races selected from #7911 without adding another flag, counter, deadline, or completion promise. The latest follow-up continues that direction:
_preflightidentity is the sole preflight authority, standalone preload retirement has onefinally, and refresh rollback belongs to the refresh transaction instead of the router.The production source diff against the base is now
+208/-223lines (net-15).Architecture
beforeLoadcontextualization, before the async frame yields. This removes the zero-owner handoff gap without a retry loop.errorandnotFound.onError-reentrant navigation starts a fresh generation._preflightidentity alone decides whether navigation preflight or hydration work is current. Replacement authority is installed before the previous controller is aborted, so abort-driven reentrancy cannot revive old work.finallythat removes their_preloadsauthority, transfers match resources, and aborts their public signal. A redirect continues only while that authority was still active.pendingComponentfinishes its own preload; route success still waits for the normal component.The resulting authorities are deliberately narrow:
_preflightowns preflight and hydration currentness._txowns foreground publication and any refresh rollback._preloadsowns speculative cancellation and private redirect continuation.The lazy pending callback is internal.
RouterCore.loadRouteChunkretains its previous two-argument public type.Intentional semantics and compromises
beforeLoad; its context and control flow remain lane-local.context()andbeforeLoaddo not rerun while hydrating them.shouldReload: truerequires a loader generation but does not bypass discoverable same-ID work. The active-flight overlap is otherwise undefined; using the uniform rule preserves the relevantmainbehavior and removes bytes.errorornotFound. A navigation planned after the terminal flight has retired retries normally.invalidate()reruns planning, routecontext(), andbeforeLoad, but does not introduce matches owned only by an active speculative preload as a second invalidation/admission authority. Same-ID loader work owned only by that preload can remain discoverable and reusable, including its old-context value.pendingMsor rebase apendingMinMsdeadline that an exact render acknowledgement has already established.How #7911 was integrated
#7911, the independent audit, and the proposed mechanism were used as sources of candidate specifications and reproductions, not adopted wholesale.
Adopted or reformulated
errorandnotFoundare shared with an already-joined navigation. The final tests use deterministic public-API gates.mainregression where the body is fresh but the head/title remains stale.onError.Corrected to match supported behavior
mainsemantics: one active same-ID parent loader may serve multiple successors, including its old-context value, whileloaderDeps-keyed child loaders supersede normally.onErrorreceives a fresh generation because the terminal flight is retired before callbacks.beforeLoad.Intentionally not adopted
shouldReload: trueto duplicate active same-ID loader work.beforeLoadcontext.main, redundant cases, and probes that required mutating internals.Size and performance
For
react-router.minimal, combining the exact-base measurement with the final-head follow-up gives:b8204ea9ad:89,298 Bgzip.89,211 Bgzip.-87 Bgzip,-88 Binitial gzip,-296 Braw, and-28 BBrotli.The latest follow-up alone changed that scenario from
89,231 Bto89,211 Bgzip (-20 B), with-23 Binitial gzip and-69 Braw. Measured independently, sole_preflightauthority accounted for about-9 Bgzip and centralized preload retirement for the remaining-11 B; the development-only HMR ownership and error-propagation changes had zero production impact.The preceding head's complete 17-scenario sweep improved every scenario's gzip size by
6–88 B, with no JS chunk-count changes. The final follow-up was remeasured on the representative React scenario rather than repeating the complete sweep. Its small+45 BBrotli movement is compression-layout noise against lower raw and gzip sizes; the final scenario remains28 Bbelow the exact base in Brotli.Focused runtime benchmarks on the first PR revision showed no regression signal:
-0.16%,-0.11%, and+0.24%throughput).1.13%with mean time down1.12%.1.85%with mean time down1.81%.Validation
git diff --checkpassed.