I. Engineering Highlights (What Sets This Apart)
Layered decision engine: on the page,
RecoveryCoordinatorunifies recovery decisions across Webpack, Vite, DOM Observer, and SystemJS, while ownership / in-flight registries decide who may take over onelogicalKey. Service Worker keeps a separate legacyResolverfor fetch-layer subresources. This preserves shared page-side semantics without forcing SW constraints into every adapter.Full coverage of your own build outputs: Not just entry
<script>/<link>, but also Webpack chunk loader (__webpack_require__.l+ non-JS CSS chunk loaders in__webpack_require__.f), Vite dynamicimport()in output (current implementation: post-emitwriteBundle+es-module-lexer+MagicString+__RF__.load),vite:preloadErrorand async CSS/JS ordering, mini-css-extract style chunks, and other builder-coupled paths — a different boundary from "swap third-party library CDN" plugins.Aligned with browser quirks: Failed URL cache for
type="module"/ dynamicimport(),<script>cannot be fixed withcloneNode,getAttribute('src')vs.srcfor rule prefix/vs absolute URL — all handled explicitly at runtime (__rf=cache bust, strip timing), reducing trial-and-error for integrators.Ownership boundaries to reduce duplicate work and races: e.g. Webpack
data-webpack<script>→ adapter, Observer skips; same-attribute<link>→ Observer. Page-side ownership admission happens first, thenRecoveryCoordinatorlets concurrent work from the same owner share one in-flight recovery Promise — avoiding double-processing of async JS and white-screen chains.Observability and ops switches: CustomEvents (
rf:retry/rf:fallback/rf:success/rf:error) are granular enough for monitoring. To tell whether page-side fallback really started, preferrf:retry/rf:fallbackover parsing legacy Resolver-style reason strings fromrf:error. Kill switch and cross-tab circuit (localStorage) complement "change paths only via release" approaches.
Previous: Dev Experience Overview · Next: Technical Challenges