fix(web): bound lazy route recovery

This commit is contained in:
lingniu
2026-07-16 05:29:08 +08:00
parent b21f9a60cd
commit d669531128
5 changed files with 97 additions and 5 deletions

View File

@@ -2,6 +2,14 @@
This document records verified risks, the production controls that address them, and the next evidence to collect. It is intentionally operational: a passing build alone is not proof that the browser application is production-ready.
## 2026-07-16: bounded route-module recovery
The route shell already displayed a meaningful Suspense skeleton and recovered rejected lazy chunks, but a dynamic import that remained pending forever never reached the error boundary. Operators could therefore stay on a loading workspace indefinitely during a stalled resource request. React documents that `lazy` caches its Promise and that Suspense continues showing the nearest fallback until that Promise settles; a rejected Promise is then delivered to the nearest error boundary: <https://react.dev/reference/react/lazy>, <https://react.dev/reference/react/Suspense>.
Every route import now has a ten-second settlement boundary. An ordinary transient rejection is retried once after 180 ms before it reaches React, while a true timeout is not repeated and immediately enters the existing controlled reload path. This preserves fast recovery from a single network hiccup without turning one hung request into two consecutive waits. If the reload cooldown prevents another automatic reload, the visible recovery page now identifies a network/resource timeout instead of incorrectly describing every chunk failure as a version update.
Regression tests prove that a first failed import resolves on its single retry, a permanently pending import rejects once with `RouteChunkLoadTimeoutError`, the error classifier accepts that failure, and the route boundary renders an explicit timeout explanation plus refresh action. Authenticated production navigation across history, mileage and access was also checked from a retained older tab to exercise compatibility assets; all three routes remained non-blank and no route recovery error appeared.
## 2026-07-16: render-scoped fleet refresh
The incremental map update already avoided AMap mutations when a 15-second response changed only its `asOf` timestamp, but the effects still depended on the complete response object. Each metadata-only refresh therefore traversed all visible points to rebuild signatures, cluster counts and label diffs before discovering that there was nothing to draw. The cost was hidden from mutation-count tests and could still create a periodic main-thread spike in a dense viewport.