Skip to content

Commit 2e4a44f

Browse files
Try to fix SPA initial behavior for 404s (#4116)
* init * changeset * add test * update lockfile * only prevent reload for fallback pages * only render client-side 404 if pathname is unchanged * Update .changeset/blue-parents-invite.md Co-authored-by: Rich Harris <[email protected]>
1 parent 70f143f commit 2e4a44f

File tree

10 files changed

+134
-25
lines changed

10 files changed

+134
-25
lines changed

.changeset/blue-parents-invite.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
Only fall back to full page reload if pathname has changed

packages/adapter-static/test/apps/spa/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
"scripts": {
66
"dev": "../../../../kit/svelte-kit.js dev",
77
"build": "../../../../kit/svelte-kit.js build",
8-
"start": "../../../../kit/svelte-kit.js start"
8+
"start": "sirv -s 200.html build"
99
},
1010
"devDependencies": {
1111
"@sveltejs/adapter-node": "next",
1212
"@sveltejs/kit": "next",
13+
"sirv-cli": "^2.0.2",
1314
"svelte": "^3.43.0"
1415
},
1516
"type": "module"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/// <reference types="@sveltejs/kit" />
2+
3+
declare namespace App {
4+
interface Session {
5+
count: number;
6+
}
7+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export function getSession() {
2+
return {
3+
count: 0
4+
};
5+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<script context="module">
2+
/** @type {import('@sveltejs/kit').Load} */
3+
export function load({ session }) {
4+
return {
5+
props: session
6+
};
7+
}
8+
</script>
9+
10+
<script>
11+
import { browser } from '$app/env';
12+
import { page, session } from '$app/stores';
13+
14+
/** @type {number} */
15+
export let count;
16+
17+
if (browser) {
18+
$session.count += 1;
19+
}
20+
</script>
21+
22+
<h1>{$page.status}</h1>
23+
<h2>count: {count}</h2>
24+
25+
<button on:click={() => ($session.count += 1)}>+1</button>

packages/adapter-static/test/test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,8 @@ run('spa', (test) => {
3434
test('renders error page for missing page', async ({ base, page }) => {
3535
await page.goto(`${base}/nosuchpage`);
3636
assert.equal(await page.textContent('h1'), '404');
37+
assert.equal(await page.textContent('h2'), 'count: 1');
38+
39+
await page.waitForLoadState('networkidle', { timeout: 1000 });
3740
});
3841
});

packages/kit/src/runtime/client/renderer.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,14 @@ export class Renderer {
316316
const token = (this.token = {});
317317
let navigation_result = await this._get_navigation_result(info, no_cache);
318318

319+
if (!navigation_result && info.url.pathname === location.pathname) {
320+
navigation_result = await this._load_error({
321+
status: 404,
322+
error: new Error(`Not found: ${info.url.pathname}`),
323+
url: info.url
324+
});
325+
}
326+
319327
if (!navigation_result) {
320328
location.href = info.url.href;
321329
return;
@@ -523,14 +531,6 @@ export class Renderer {
523531
);
524532
if (result) return result;
525533
}
526-
527-
if (info.initial) {
528-
return await this._load_error({
529-
status: 404,
530-
error: new Error(`Not found: ${info.url.pathname}`),
531-
url: info.url
532-
});
533-
}
534534
}
535535

536536
/**

packages/kit/src/runtime/client/router.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ export class Router {
5656
* base: string;
5757
* routes: import('types').CSRRoute[];
5858
* trailing_slash: import('types').TrailingSlash;
59-
* renderer: import('./renderer').Renderer
59+
* renderer: import('./renderer').Renderer;
6060
* }} opts
6161
*/
6262
constructor({ base, routes, trailing_slash, renderer }) {
@@ -290,8 +290,7 @@ export class Router {
290290
id: url.pathname + url.search,
291291
routes: this.routes.filter(([pattern]) => pattern.test(path)),
292292
url,
293-
path,
294-
initial: !this.initialized
293+
path
295294
};
296295
}
297296
}

packages/kit/src/runtime/client/types.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ export type NavigationInfo = {
55
routes: CSRRoute[];
66
url: URL;
77
path: string;
8-
initial: boolean;
98
};
109

1110
export type NavigationCandidate = {

pnpm-lock.yaml

Lines changed: 77 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)