Skip to content

offline navigations: boot fallback from exact-url data (10/25)#93632

Closed
feedthejim wants to merge 10 commits into
feedthejim/offline-navigations-persist-exact-url-datafrom
feedthejim/offline-navigations-fallback-boot
Closed

offline navigations: boot fallback from exact-url data (10/25)#93632
feedthejim wants to merge 10 commits into
feedthejim/offline-navigations-persist-exact-url-datafrom
feedthejim/offline-navigations-fallback-boot

Conversation

@feedthejim

@feedthejim feedthejim commented May 8, 2026

Copy link
Copy Markdown
Contributor

Stack Position

10/25 in the offline navigations first-usable stack.

This stack turns experimental.offlineNavigations into a usable cache-components experiment for regular apps. The service worker owns document survival only. Cache Storage owns generated fallback artifacts. The cache-components client router owns IndexedDB, route semantics, replay, visible misses, and invalidation. Output export, dev simulation, custom miss UI, and broad production-hardening matrices are intentionally deferred.

Review guide: https://gist.github.com/feedthejim/b3d9fe26a7c05655fd57adcce371b93d

Full Stack

  1. offline navigations: add cache-components flag (1/25)
  2. offline navigations: emit fallback document (2/25)
  3. offline navigations: emit fallback manifest (3/25)
  4. offline navigations: register pass-through service worker (4/25)
  5. offline navigations: cache fallback artifacts (5/25)
  6. offline navigations: serve fallback document (6/25)
  7. offline navigations: bridge fallback state to useOffline (7/25)
  8. offline navigations: add navigation cache primitives (8/25)
  9. offline navigations: persist exact-url navigation data (9/25)
  10. offline navigations: boot fallback from exact-url data (10/25) ← this PR
  11. offline navigations: persist initial-load navigation data (11/25)
  12. offline navigations: centralize cache eligibility (12/25)
  13. offline navigations: replay request-sensitive exact urls (13/25)
  14. offline navigations: wire exact-url invalidation (14/25)
  15. offline navigations: harden fallback diagnostics and misses (15/25)
  16. offline navigations: cover exact-url app replay basics (16/25)
  17. offline navigations: define persistent router schema (17/25)
  18. offline navigations: persist route records and known routes (18/25)
  19. offline navigations: persist segment and head records (19/25)
  20. offline navigations: hydrate persisted router caches (20/25)
  21. offline navigations: reconstruct prefetched routes offline (21/25)
  22. offline navigations: replay dynamic routes from known routes (22/25)
  23. offline navigations: mirror router cache invalidation (23/25)
  24. offline navigations: cover mutation invalidation (24/25)
  25. offline navigations: add app cache reset API (25/25)

What This PR Does

Lets the fallback document ask the client for an exact-URL record and render from it when the record is valid.

What Works After This PR

A previously persisted exact URL can hard-load offline through the fallback document, and a missing record renders visible cache-miss UI.

Reviewer Focus

Fallback bootstrap flow, exact-URL lookup, visible miss UI, diagnostics, and fail-closed behavior when the cache cannot satisfy the URL.

Not In This PR

Initial-load records, personalized same-browser replay, and route/segment reconstruction are later PRs.

Proof in This PR

  • Relevant coverage: Exact-URL fallback boot and missing-entry assertions in the production fixture plus stack-level build/e2e verification.
  • Restack verification run at the cleaned stack tip:
    • pnpm --filter=next build
    • NEXT_SKIP_ISOLATE=1 NEXT_TEST_MODE=start pnpm testheadless test/production/app-dir/offline-navigations/offline-navigations.test.ts
    • NEXT_TEST_MODE=start pnpm testheadless test/production/app-dir/offline-navigations/offline-navigations.test.ts
    • IS_WEBPACK_TEST=1 NEXT_TEST_MODE=start pnpm testheadless test/production/app-dir/offline-navigations/offline-navigations.test.ts

Deferred Coverage

Initial-load records, personalized same-browser replay, and route/segment reconstruction are later PRs.

@github-actions

github-actions Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Tests Passed

Commit: 00af9b0

@github-actions

github-actions Bot commented May 8, 2026

Copy link
Copy Markdown
Contributor

Stats from current PR

🔴 1 regression

Metric Canary PR Change Trend
node_modules Size 505 MB 506 MB 🔴 +919 kB (+0%) ▁▁▁▁█
📊 All Metrics
📖 Metrics Glossary

Dev Server Metrics:

  • Listen = TCP port starts accepting connections
  • First Request = HTTP server returns successful response
  • Cold = Fresh build (no cache)
  • Warm = With cached build artifacts

Build Metrics:

  • Fresh = Clean build (no .next directory)
  • Cached = With existing .next directory

Change Thresholds:

  • Time: Changes < 50ms AND < 10%, OR < 2% are insignificant
  • Size: Changes < 1KB AND < 1% are insignificant
  • All other changes are flagged to catch regressions

⚡ Dev Server

Metric Canary PR Change Trend
Cold (Listen) 811ms 810ms ▅▁▅▅▃
Cold (Ready in log) 790ms 788ms ▅▇█▂▁
Cold (First Request) 1.234s 1.231s ▄▄▆▂▂
Warm (Listen) 810ms 809ms ▃▁▆▆▃
Warm (Ready in log) 787ms 789ms ▅▆█▂▂
Warm (First Request) 606ms 606ms ▅▇█▂▃
📦 Dev Server (Webpack) (Legacy)

📦 Dev Server (Webpack)

Metric Canary PR Change Trend
Cold (Listen) 810ms 810ms █████
Cold (Ready in log) 778ms 778ms █████
Cold (First Request) 3.186s 3.204s ▆▇▅▄█
Warm (Listen) 811ms 810ms █████
Warm (Ready in log) 780ms 779ms ██▇██
Warm (First Request) 3.198s 3.199s ▆▇▄▃█

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 4.736s 4.781s ██▆▁▁
Cached Build 4.794s 4.784s ▃▆▅▁▄
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
Fresh Build 23.480s 23.596s ▆▅▆▆█
Cached Build 23.629s 23.653s ▄▄▅▆▇
node_modules Size 505 MB 506 MB 🔴 +919 kB (+0%) ▁▁▁▁█
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles
Canary PR Change
0-_gc56kf9tfo.js gzip 154 B N/A -
047ad-p-61fjn.js gzip 156 B N/A -
04hm05ar7kldw.js gzip 5.73 kB N/A -
0714gv_gbisrs.js gzip 70.8 kB N/A -
0cz1d0mv5g_q7.js gzip 39.4 kB 39.4 kB
0dvitrl5zg37g.js gzip 8.82 kB N/A -
0sf7ysou-72zd.js gzip 8.71 kB N/A -
11ny9t-iyn9yw.js gzip 154 B N/A -
157abun3hwc_s.js gzip 10.3 kB N/A -
1bhal_i5byhy7.js gzip 162 B N/A -
1elt1qium-r2m.css gzip 115 B 115 B
1jfwzy3ri2pyr.js gzip 154 B N/A -
1jj68jv9537mc.js gzip 13.8 kB N/A -
1jpaub6y8xlfr.js gzip 2.3 kB N/A -
1ot0mvscrc_uf.js gzip 233 B N/A -
2_m3xv2uq3sjc.js gzip 1.46 kB N/A -
224i1-g0lqvss.js gzip 49.5 kB N/A -
24y34mwgrkqp4.js gzip 8.78 kB N/A -
28lrkt28g7fpx.js gzip 155 B N/A -
2c-fd4y1zozz8.js gzip 8.79 kB N/A -
2d7416h_xd36x.js gzip 8.71 kB N/A -
2extn3odmmem_.js gzip 12.9 kB N/A -
2fyhyy7niw9r6.js gzip 7.61 kB N/A -
2lyuhit6rn8fy.js gzip 9.44 kB N/A -
2q0gr8wfr3jwl.js gzip 8.77 kB N/A -
2qmtk0zius6fd.js gzip 157 B N/A -
2t9e75oz6r0zp.js gzip 8.76 kB N/A -
2uku_olcn15b7.js gzip 8.79 kB N/A -
30r8mm-46bdqy.js gzip 220 B 220 B
3c03ks8ic59bl.js gzip 160 B N/A -
3c03yiy5ds-h6.js gzip 65.5 kB N/A -
3d0blqiuhma_c.js gzip 155 B N/A -
3inab2jybr4k9.js gzip 450 B N/A -
3jkm5tdjvaf_q.js gzip 13.1 kB N/A -
3mix8ikliw_bj.js gzip 169 B N/A -
3mt67agm5wp40.js gzip 10.6 kB N/A -
3saabek4kohwi.js gzip 10 kB N/A -
3x_ftwxjtc4jr.js gzip 152 B N/A -
3x0-g47j0wg_t.js gzip 154 B N/A -
40pcd44z40i4a.js gzip 156 B N/A -
4189xmby9yu1p.js gzip 13.6 kB N/A -
turbopack-02..93y4.js gzip 4.2 kB N/A -
turbopack-0m..eii3.js gzip 4.2 kB N/A -
turbopack-0t..cm46.js gzip 4.2 kB N/A -
turbopack-13..1jkn.js gzip 4.2 kB N/A -
turbopack-1m..-lpg.js gzip 4.18 kB N/A -
turbopack-1s..s1zo.js gzip 4.21 kB N/A -
turbopack-23..--2_.js gzip 4.2 kB N/A -
turbopack-28..zluk.js gzip 4.2 kB N/A -
turbopack-2a..kxyc.js gzip 4.2 kB N/A -
turbopack-2s..sur4.js gzip 4.2 kB N/A -
turbopack-2z..x5dq.js gzip 4.19 kB N/A -
turbopack-3h..65h_.js gzip 4.2 kB N/A -
turbopack-3s..rdjl.js gzip 4.2 kB N/A -
turbopack-3y..gfl4.js gzip 4.2 kB N/A -
0_i7nqgx23st7.js gzip N/A 10 kB -
05e40c15cx1dd.js gzip N/A 7.61 kB -
06puhytyxk31p.js gzip N/A 8.82 kB -
0cgwxw9wez5uz.js gzip N/A 155 B -
0m34gln_kt4fg.js gzip N/A 5.73 kB -
0wjn_zvopg8j7.js gzip N/A 155 B -
1g3q1ww01thnl.js gzip N/A 2.3 kB -
1hraqxuiymq6v.js gzip N/A 8.79 kB -
1l9un1sl77287.js gzip N/A 1.46 kB -
1oj2783a6mjmk.js gzip N/A 153 B -
1tu42mhgspxaj.js gzip N/A 152 B -
2_n5io6i3e7-d.js gzip N/A 65.6 kB -
21-eavqb1k_36.js gzip N/A 13.9 kB -
2147zgtf14z-q.js gzip N/A 234 B -
23bz3xsg-5-1s.js gzip N/A 8.71 kB -
25m28ppgv1r-l.js gzip N/A 156 B -
27441mytv7pbm.js gzip N/A 9.43 kB -
294duycu1s258.js gzip N/A 70.9 kB -
2cjkwjgm1zcfs.js gzip N/A 8.71 kB -
2feeljlwn03ka.js gzip N/A 156 B -
2sb1y1swq-aoa.js gzip N/A 50.9 kB -
2scd8zaoyb8md.js gzip N/A 8.79 kB -
2st_qs6p_9us0.js gzip N/A 13.1 kB -
2zo2exm1d8qj1.js gzip N/A 13.6 kB -
31gszfpoi49o_.js gzip N/A 157 B -
3g88fx8gbrpbb.js gzip N/A 159 B -
3hn75zuxly9az.js gzip N/A 10.3 kB -
3hqh7m128tvsn.js gzip N/A 8.77 kB -
3hqti_t-zy1x4.js gzip N/A 449 B -
3k_ox9mqvj991.js gzip N/A 162 B -
3lwd3rbxfr02f.js gzip N/A 157 B -
3mnawenie1flm.js gzip N/A 8.76 kB -
3sxqvx3vn2_or.js gzip N/A 155 B -
3ubsozlu6zs38.js gzip N/A 10.6 kB -
41_yhm_31fcf8.js gzip N/A 155 B -
41mf-x3mmsxae.js gzip N/A 12.9 kB -
41ovqpfyyufzz.js gzip N/A 168 B -
43iwfqjnx1cy_.js gzip N/A 8.78 kB -
turbopack-0g..-9g6.js gzip N/A 4.2 kB -
turbopack-0x..uby1.js gzip N/A 4.18 kB -
turbopack-1b..n71_.js gzip N/A 4.2 kB -
turbopack-1e..hu78.js gzip N/A 4.2 kB -
turbopack-1g..7-n-.js gzip N/A 4.2 kB -
turbopack-1l..qd49.js gzip N/A 4.21 kB -
turbopack-1t..oruv.js gzip N/A 4.2 kB -
turbopack-2q..tzzk.js gzip N/A 4.2 kB -
turbopack-2s..khje.js gzip N/A 4.2 kB -
turbopack-31..xepd.js gzip N/A 4.2 kB -
turbopack-3q..wh7s.js gzip N/A 4.2 kB -
turbopack-3t..pfdy.js gzip N/A 4.2 kB -
turbopack-3y..qhsx.js gzip N/A 4.2 kB -
turbopack-43..rc4q.js gzip N/A 4.2 kB -
Total 468 kB 470 kB ⚠️ +1.51 kB

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 716 B 717 B
Total 716 B 717 B ⚠️ +1 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 429 B 433 B
Total 429 B 433 B ⚠️ +4 B

📦 Webpack

Client

Main Bundles
Canary PR Change
2258-HASH.js gzip 61.1 kB N/A -
2266-HASH.js gzip 4.69 kB N/A -
3317.HASH.js gzip 169 B N/A -
4866-HASH.js gzip 5.64 kB N/A -
9e302639-HASH.js gzip 62.7 kB N/A -
framework-HASH.js gzip 59.5 kB 59.5 kB
main-app-HASH.js gzip 255 B 254 B
main-HASH.js gzip 39.9 kB 39.9 kB
webpack-HASH.js gzip 1.68 kB 1.68 kB
175fd0fd-HASH.js gzip N/A 62.7 kB -
2596-HASH.js gzip N/A 5.63 kB -
34-HASH.js gzip N/A 62.5 kB -
5691.HASH.js gzip N/A 169 B -
9156-HASH.js gzip N/A 4.68 kB -
Total 236 kB 237 kB ⚠️ +1.38 kB
Polyfills
Canary PR Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Total 39.4 kB 39.4 kB
Pages
Canary PR Change
_app-HASH.js gzip 193 B 193 B
_error-HASH.js gzip 181 B 182 B
css-HASH.js gzip 334 B 332 B
dynamic-HASH.js gzip 1.79 kB 1.81 kB
edge-ssr-HASH.js gzip 255 B 255 B
head-HASH.js gzip 351 B 348 B
hooks-HASH.js gzip 385 B 384 B
image-HASH.js gzip 580 B 580 B
index-HASH.js gzip 257 B 259 B
link-HASH.js gzip 2.51 kB 2.52 kB
routerDirect..HASH.js gzip 318 B 319 B
script-HASH.js gzip 387 B 386 B
withRouter-HASH.js gzip 316 B 316 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Total 7.97 kB 7.99 kB ⚠️ +19 B

Server

Edge SSR
Canary PR Change
edge-ssr.js gzip 126 kB 126 kB
page.js gzip 275 kB 271 kB 🟢 4.13 kB (-2%)
Total 401 kB 397 kB ✅ -4.34 kB
Middleware
Canary PR Change
middleware-b..fest.js gzip 616 B 615 B
middleware-r..fest.js gzip 155 B 155 B
middleware.js gzip 44.4 kB 44.9 kB
edge-runtime..pack.js gzip 842 B 842 B
Total 46.1 kB 46.5 kB ⚠️ +440 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 719 B 717 B
Total 719 B 717 B ✅ -2 B
Build Cache
Canary PR Change
0.pack gzip 4.45 MB 4.47 MB 🔴 +20.2 kB (+0%)
index.pack gzip 114 kB 115 kB
index.pack.old gzip 114 kB 115 kB
Total 4.68 MB 4.7 MB ⚠️ +21.4 kB

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 349 kB 351 kB 🔴 +2.05 kB (+1%)
app-page-exp..prod.js gzip 194 kB 195 kB
app-page-tur...dev.js gzip 349 kB 351 kB 🔴 +2.05 kB (+1%)
app-page-tur..prod.js gzip 194 kB 195 kB
app-page-tur...dev.js gzip 345 kB 347 kB
app-page-tur..prod.js gzip 192 kB 193 kB
app-page.run...dev.js gzip 346 kB 348 kB
app-page.run..prod.js gzip 192 kB 193 kB
app-route-ex...dev.js gzip 77.5 kB 77.5 kB
app-route-ex..prod.js gzip 52.9 kB 52.9 kB
app-route-tu...dev.js gzip 77.6 kB 77.6 kB
app-route-tu..prod.js gzip 52.9 kB 52.9 kB
app-route-tu...dev.js gzip 77.2 kB 77.2 kB
app-route-tu..prod.js gzip 52.7 kB 52.7 kB
app-route.ru...dev.js gzip 77.1 kB 77.1 kB
app-route.ru..prod.js gzip 52.7 kB 52.7 kB
dist_client_...dev.js gzip 324 B 324 B
dist_client_...dev.js gzip 326 B 326 B
dist_client_...dev.js gzip 318 B 318 B
dist_client_...dev.js gzip 317 B 317 B
pages-api-tu...dev.js gzip 44.3 kB 44.3 kB
pages-api-tu..prod.js gzip 33.8 kB 33.8 kB
pages-api.ru...dev.js gzip 44.3 kB 44.3 kB
pages-api.ru..prod.js gzip 33.7 kB 33.7 kB
pages-turbo....dev.js gzip 53.7 kB 53.7 kB
pages-turbo...prod.js gzip 39.4 kB 39.4 kB
pages.runtim...dev.js gzip 53.6 kB 53.6 kB
pages.runtim..prod.js gzip 39.3 kB 39.3 kB
server.runti..prod.js gzip 63.2 kB 63.2 kB
use-cache-pr...dev.js gzip 69.7 kB 69.7 kB
use-cache-pr...dev.js gzip 69.7 kB 69.7 kB
use-cache-pr...dev.js gzip 68 kB 68 kB
use-cache-pr...dev.js gzip 68 kB 68 kB
Total 3.36 MB 3.38 MB ⚠️ +14.3 kB
📝 Changed Files (9 files)

Files with changes:

  • app-page-exp..ntime.dev.js
  • app-page-exp..time.prod.js
  • app-page-tur..ntime.dev.js
  • app-page-tur..time.prod.js
  • app-page-tur..ntime.dev.js
  • app-page-tur..time.prod.js
  • app-page.runtime.dev.js
  • app-page.runtime.prod.js
  • server.runtime.prod.js
View diffs
app-page-exp..ntime.dev.js
failed to diff
app-page-exp..time.prod.js
failed to diff
app-page-tur..ntime.dev.js
failed to diff
app-page-tur..time.prod.js
failed to diff
app-page-tur..ntime.dev.js
failed to diff
app-page-tur..time.prod.js
failed to diff
app-page.runtime.dev.js
failed to diff
app-page.runtime.prod.js
failed to diff
server.runtime.prod.js

Diff too large to display

📎 Tarball URL
https://vercel-packages.vercel.app/next/commits/00af9b0b4924d334b4cd5045c736c9843940e55e/next

Commit: 00af9b0

@feedthejim feedthejim force-pushed the feedthejim/offline-navigations-fallback-boot branch from 401a2c0 to 5ca7c5f Compare May 8, 2026 04:03
@feedthejim feedthejim force-pushed the feedthejim/offline-navigations-persist-exact-url-data branch 2 times, most recently from 58fead3 to bb5cc45 Compare May 8, 2026 08:17
@feedthejim feedthejim force-pushed the feedthejim/offline-navigations-fallback-boot branch from 5ca7c5f to d8e418c Compare May 8, 2026 08:17
@feedthejim feedthejim force-pushed the feedthejim/offline-navigations-persist-exact-url-data branch from bb5cc45 to bd9034a Compare May 8, 2026 17:45
@feedthejim feedthejim force-pushed the feedthejim/offline-navigations-fallback-boot branch from d8e418c to 00af9b0 Compare May 8, 2026 17:45
@feedthejim feedthejim changed the title (10/10) Boot fallback document from exact-URL data offline navigations: boot fallback from exact-url data (10/25) May 8, 2026
@feedthejim feedthejim force-pushed the feedthejim/offline-navigations-persist-exact-url-data branch from bd9034a to fff03ee Compare May 8, 2026 20:30
@feedthejim

Copy link
Copy Markdown
Contributor Author

Closing as folded into the compressed 13-PR offline navigations review stack. fallback boot from exact URL data now lives with the exact URL replay slice; see #93631. The branch is intentionally left intact for audit.

@feedthejim feedthejim closed this May 8, 2026
@github-actions github-actions Bot locked as resolved and limited conversation to collaborators May 23, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant