Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/ten-rats-spend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@sveltejs/kit': patch
---

fix: `afterNavigate` callback not running after hydration when experimental async is enabled
fix: Snapshot `restore` method not called after reload when experimental async is enabled
10 changes: 7 additions & 3 deletions packages/kit/src/runtime/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ async function _preload_code(url) {
* @param {HTMLElement} target
* @param {boolean} hydrate
*/
function initialize(result, target, hydrate) {
async function initialize(result, target, hydrate) {
if (DEV && result.state.error && document.querySelector('vite-error-overlay')) return;

current = result.state;
Expand All @@ -563,6 +563,10 @@ function initialize(result, target, hydrate) {
sync: false
});

// Wait for a microtask in case svelte experimental async is enabled,
// which causes component script blocks to run asynchronously
void (await Promise.resolve());

restore_snapshot(current_navigation_index);

if (hydrate) {
Expand Down Expand Up @@ -1691,7 +1695,7 @@ async function navigate({
update(navigation_result.props.page);
has_navigated = true;
} else {
initialize(navigation_result, target, false);
await initialize(navigation_result, target, false);
}

const { activeElement } = document;
Expand Down Expand Up @@ -2794,7 +2798,7 @@ async function _hydrate(
result.props.page.state = {};
}

initialize(result, target, hydrate);
await initialize(result, target, hydrate);
}

/**
Expand Down
24 changes: 24 additions & 0 deletions packages/kit/test/apps/async/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "test-async",
"private": true,
"version": "0.0.1",
"scripts": {
"dev": "vite dev",
"build": "vite build",
"preview": "vite preview",
"prepare": "svelte-kit sync",
"check": "svelte-kit sync && tsc && svelte-check",
"test": "pnpm test:dev && pnpm test:build",
"test:dev": "DEV=true playwright test",
"test:build": "playwright test"
},
"devDependencies": {
"@sveltejs/kit": "workspace:^",
"@sveltejs/vite-plugin-svelte": "catalog:",
"svelte": "catalog:",
"svelte-check": "catalog:",
"typescript": "^5.5.4",
"vite": "catalog:"
},
"type": "module"
}
1 change: 1 addition & 0 deletions packages/kit/test/apps/async/playwright.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { config as default } from '../../utils.js';
12 changes: 12 additions & 0 deletions packages/kit/test/apps/async/src/app.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/png" href="%sveltekit.assets%/favicon.png" />
%sveltekit.head%
</head>
<body>
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>
9 changes: 9 additions & 0 deletions packages/kit/test/apps/async/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<script>
import { setup } from '../../../../setup.js';

setup();

let { children } = $props();
</script>

{@render children()}
1 change: 1 addition & 0 deletions packages/kit/test/apps/async/src/routes/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<p>home</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<script>
import { afterNavigate } from '$app/navigation';

let runs = 0;
afterNavigate(() => {
runs += 1;
});
</script>

<pre>{runs}</pre>
14 changes: 14 additions & 0 deletions packages/kit/test/apps/async/src/routes/snapshot/+page.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<script>
let restored = 'initial';

export const snapshot = {
capture() {
return { restored: 'yes' };
},
restore(v) {
restored = v;
}
};
</script>

<pre>{JSON.stringify(restored)}</pre>
Binary file added packages/kit/test/apps/async/static/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions packages/kit/test/apps/async/svelte.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/** @type {import('@sveltejs/kit').Config} */
const config = {
kit: {},
compilerOptions: {
experimental: {
async: true
}
}
};

export default config;
20 changes: 20 additions & 0 deletions packages/kit/test/apps/async/test/test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { expect } from '@playwright/test';
import { test } from '../../../utils.js';

/** @typedef {import('@playwright/test').Response} Response */

test.skip(({ javaScriptEnabled }) => !javaScriptEnabled);

test.describe.configure({ mode: 'parallel' });

test('afterNavigate runs after hydration', async ({ page }) => {
await page.goto('/after_navigate');

expect(await page.innerText('pre')).toBe('1');
});

test('snapshots are restored after reload', async ({ page }) => {
await page.goto('/snapshot');
await page.reload();
expect(await page.innerText('pre')).toBe('{"restored":"yes"}');
});
10 changes: 10 additions & 0 deletions packages/kit/test/apps/async/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"noEmit": true,
"resolveJsonModule": true
},
"extends": "./.svelte-kit/tsconfig.json"
}
21 changes: 21 additions & 0 deletions packages/kit/test/apps/async/vite.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as path from 'node:path';
import { sveltekit } from '@sveltejs/kit/vite';

/** @type {import('vite').UserConfig} */
const config = {
build: {
minify: false
},
clearScreen: false,
plugins: [sveltekit()],
server: {
fs: {
allow: [path.resolve('../../../src')]
}
},
optimizeDeps: {
exclude: ['svelte']
}
};

export default config;
21 changes: 21 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.