V. Reusable Principles
When multiple load mechanisms coexist, define ownership first (Webpack script / Observer / SW / SystemJS); then implement retry — otherwise request volume grows multiplicatively.
ESM failure is cacheable state: break it with an explicit URL change strategy, not just a different DOM API.
Vite dynamic import: late is safer than early: the current implementation rewrites after
writeBundlewithes-module-lexer+MagicStringto preserve__vitePreload/__vite__mapDeps/ async CSS topology; treatrenderBuiltUrl/renderDynamicImportas earlier, rejected approaches.Vite:
vite:preloadErrormustpreventDefault(), read payload frompayload— otherwise CSS preload failure throws and blocks__RF__.load(). The current page runtime only suppresses that throw; it does not turn the preload event itself into an old-Resolver failure record.When Vite
baseand rulebasediverge, don't open the build gate: useshouldRewriteUrls(compare afterensureTrailingSlashon both sides) to prevent accidental CDN URL assembly.Don't use
cloneNodeto swap script src; create new elements + attribute whitelist + SRI policy.Use
getAttribute(src)for prefix consistency — avoid/vs absolute URL confusion.Use
joinAssetPrefixfor CDN prefix + filename — avoidprod+js/x.js→prodjs.Webpack CSS chunk: suppress CSS loader reject in RuntimeModule, not just Observer — otherwise
import()still fails; iterate__webpack_require__.fnon-j, not onlyminiCss.SystemJS and Observer must register URLs for mutual exclusion.
Only the SW legacy Resolver keeps the
isFallback === true→urls-prefix-match rule. Page-side recovery is now coordinated byRecoveryCoordinator, so do not treat Resolver match order, duplicate rulebaseprecedence, or per-rule circuits as current page API.Page-side
rf:erroris a terminal signal, not a stable reason-string contract: if you need evidence that fallback actually started, preferrf:retry/rf:fallback; keepno-match/rules-exhausteddiscussion in historical or SW-specific contexts.SW default path must align with scope:
scope: '/'→/rf-sw.js; don't makeService-Worker-Alloweda default deploy burden.SW config can't rely on page
postMessagealone: preload manifest at build time for early img/font/CSS subresources.Opaque response is a policy choice: default conservative; use
fallbackOnOpaqueto probe CORS and handle readable cross-origin HTTP errors, while remembering that opaque responses remain accepted when CORS is unavailable.SW local debug: check origin — localhost, 127.0.0.1, LAN IP differ; LAN HTTP is not secure context.
Verify visual resources by real load: img →
naturalWidth; font →document.fonts.check(); background → Network/SW events;toBeVisible()only proves DOM exists.Rules use string rule
baseonly — no RegExp / function matchers; SW preload embeds JSON-serializable config.SW events should target
clientId— broadcast pollutes multi-tab observability.SW ultimate failure should return
Response.error()— emitrf:errorwithout fake 503 body.SW circuit must not share page
localStorage— page cross-tab state must not poison SW fetch decisions.Full fetch interception for arbitrary resources → lean SW; Webpack+Vite consistent runtime semantics → plugin +
__RF__+ Observer.
Previous: Case Studies · Back to Dev Experience Overview