Skip to content

feat(router): reload once when a route chunk fails to load - #2348

Open
lxsmnsyc wants to merge 1 commit into
mainfrom
feat/route-chunk-reload
Open

lxsmnsyc wants to merge 1 commit into
mainfrom
feat/route-chunk-reload

Conversation

@lxsmnsyc

Copy link
Copy Markdown
Member

Closes #1644.

When a deploy replaces a route's chunk while a page is open, navigating to that route fails to import its component. The page ends on "Error | Uncaught Client Exception" until the user refreshes by hand.

Change

In production builds, FileRoutes wraps each route's component import with withRouteChunkReload. If the import fails:

  1. It checks a loop guard: a timestamp in sessionStorage. If the page already reloaded for this within the last 10 seconds, or storage is unavailable, it rethrows, so a chunk that is still missing shows the normal error instead of reloading in a loop.
  2. Otherwise it resolves with an empty component. Solid Router only moves to the destination URL after the route has loaded (navigateEnd runs in the transition's .finally), so a route that stays pending, or a reload from the placeholder's onMount, would reload the old URL. Resolving lets the router finish the navigation.
  3. It reloads as soon as location.href changes from the URL at the time of the failure. If it never changes within 1 second, for example a same-URL navigation, it reloads anyway. Watching the URL instead of relying on the router's internal order also works with params and with other routers.

Only route chunks are covered. The user is already leaving the page there, so the reload loses nothing extra. Nuxt does the same by default (emitRouteChunkError: "automatic"). Other dynamic imports, such as clientOnly or lazy() components in the middle of a page, are left alone, since a reload could throw away state. For those, Vite's vite:preloadError event is the place to hook in.

A new reloadOnRouteChunkError option, on by default, turns this off. It is passed to the client through define, the same way as devOverlay. Dev builds are not affected, since a failed import there is a real error.

Testing

A real deploy on the basic fixture, production build. Build v1 and open /. Then stop the server, change about.tsx, build v2, restart on the same port, and click About in the open v1 tab:

Build Reloads Final URL Page
before this change 0 /about "Error | Uncaught Client Exception"
this change 1 /about the v2 /about
this change, reloadOnRouteChunkError: false 0 /about "Error | Uncaught Client Exception"
this change, chunk still missing after the reload 1 /about no second reload

An earlier version of this change kept the route pending instead of resolving it. It reloaded back to /, because the router had not moved to the destination yet, which is why it now resolves with an empty component and watches the URL.

  • New route-chunk-reload.spec.ts (6 tests): passes the module through on success. On failure, resolves with an empty component and reloads only after the URL changes. Reloads after the timeout if the URL does not change. Rethrows a second failure within the window. Reloads again after the window. Rethrows without reloading when sessionStorage throws.
  • @solidjs/start test:ci (246 tests), typecheck, validate-imports and build pass. apps/tests unit tests (6), Playwright (42), bundled-dev Playwright (42) and e2e:base (3) pass. Those e2e configs run dev servers, so they cover that dev is unaffected but not the reload itself. The repo has no production e2e config, which is why the deploy test above was run by hand.

A matching PR for the 1.x branch follows.

🤖 Generated with Claude Code

When a deploy replaces a route's chunk while a page is open, navigating
to that route fails to import its component and ends on the error page
until the user refreshes by hand.

Wrap the route component import in production. On failure, resolve with
an empty component so the router finishes the navigation, then reload
once the URL is the destination. A failure within 10 seconds of the
last reload is rethrown, so a chunk that is still missing shows the
error instead of reloading in a loop. Add a reloadOnRouteChunkError
option, on by default, to turn it off.

Closes #1644.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@netlify

netlify Bot commented Oct 14, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for solid-start-landing-page ready!

Name Link
🔨 Latest commit 5ff9534
🔍 Latest deploy log https://app.netlify.com/projects/solid-start-landing-page/deploys/6acef90d3b54b4e694971c7c
😎 Deploy Preview https://deploy-preview-2348--solid-start-landing-page.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@changeset-bot

changeset-bot Bot commented Oct 14, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 5ff9534

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@solidjs/start Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Oct 14, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@solidjs/start@2348

commit: 5ff9534

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature?]: If page has error refresh the page

2 participants