From df3192d1483918721367d6aa9525c85c204cfc74 Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Wed, 22 Oct 2025 17:17:41 +0800 Subject: [PATCH 1/4] add test --- .../hash-based-routing/src/routes/resolve/+page.svelte | 5 +++++ packages/kit/test/apps/hash-based-routing/test/test.js | 9 +++++++++ 2 files changed, 14 insertions(+) create mode 100644 packages/kit/test/apps/hash-based-routing/src/routes/resolve/+page.svelte diff --git a/packages/kit/test/apps/hash-based-routing/src/routes/resolve/+page.svelte b/packages/kit/test/apps/hash-based-routing/src/routes/resolve/+page.svelte new file mode 100644 index 000000000000..e86f737a7b40 --- /dev/null +++ b/packages/kit/test/apps/hash-based-routing/src/routes/resolve/+page.svelte @@ -0,0 +1,5 @@ + + +go to home diff --git a/packages/kit/test/apps/hash-based-routing/test/test.js b/packages/kit/test/apps/hash-based-routing/test/test.js index de423cc9bcb0..1b020d5560ec 100644 --- a/packages/kit/test/apps/hash-based-routing/test/test.js +++ b/packages/kit/test/apps/hash-based-routing/test/test.js @@ -126,4 +126,13 @@ test.describe('hash based navigation', () => { await expect(page.locator('#button3')).toBeFocused(); await expect(page.locator('button[id="button3"]')).toBeFocused(); }); + + test('resolve works', async ({ page }) => { + await page.goto('/#/resolve'); + await page.locator('a', { hasText: 'go to home' }).click(); + await expect(page.locator('p')).toHaveText('home'); + const url = new URL(page.url()); + expect(url.pathname).toBe('/'); + expect(url.hash).toBe('#/'); + }) }); From 76e4a0c357f62d4e542653e59604d8bf8a309817 Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Wed, 22 Oct 2025 17:17:49 +0800 Subject: [PATCH 2/4] add fix --- packages/kit/src/exports/vite/index.js | 1 + packages/kit/src/runtime/app/paths/client.js | 6 ++++-- packages/kit/src/runtime/app/paths/internal/client.js | 1 + packages/kit/src/types/global-private.d.ts | 2 ++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/kit/src/exports/vite/index.js b/packages/kit/src/exports/vite/index.js index 4a441b23d4d5..7d6cf2a9589f 100644 --- a/packages/kit/src/exports/vite/index.js +++ b/packages/kit/src/exports/vite/index.js @@ -350,6 +350,7 @@ async function kit({ svelte_config }) { __SVELTEKIT_PATHS_BASE__: s(kit.paths.base), __SVELTEKIT_PATHS_RELATIVE__: s(kit.paths.relative), __SVELTEKIT_CLIENT_ROUTING__: s(kit.router.resolution === 'client'), + __SVELTEKIT_HASH_ROUTING__: s(kit.router.type === 'hash'), __SVELTEKIT_SERVER_TRACING_ENABLED__: s(kit.experimental.tracing.server) }; diff --git a/packages/kit/src/runtime/app/paths/client.js b/packages/kit/src/runtime/app/paths/client.js index 510f42ede418..982b0d194434 100644 --- a/packages/kit/src/runtime/app/paths/client.js +++ b/packages/kit/src/runtime/app/paths/client.js @@ -1,6 +1,6 @@ /** @import { Asset, RouteId, Pathname, ResolvedPathname } from '$app/types' */ /** @import { ResolveArgs } from './types.js' */ -import { base, assets } from './internal/client.js'; +import { base, assets, hash_routing } from './internal/client.js'; import { resolve_route } from '../../../utils/routing.js'; /** @@ -25,6 +25,8 @@ export function asset(file) { return (assets || base) + file; } +const pathname_prefix = hash_routing ? '#' : ''; + /** * Resolve a pathname by prefixing it with the base path, if any, or resolve a route ID by populating dynamic segments with parameters. * @@ -51,7 +53,7 @@ export function asset(file) { export function resolve(...args) { // The type error is correct here, and if someone doesn't pass params when they should there's a runtime error, // but we don't want to adjust the internal resolve_route function to accept `undefined`, hence the type cast. - return base + resolve_route(args[0], /** @type {Record} */ (args[1])); + return base + pathname_prefix + resolve_route(args[0], /** @type {Record} */ (args[1])); } export { base, assets, resolve as resolveRoute }; diff --git a/packages/kit/src/runtime/app/paths/internal/client.js b/packages/kit/src/runtime/app/paths/internal/client.js index 462b95de28b9..a5679afff6ef 100644 --- a/packages/kit/src/runtime/app/paths/internal/client.js +++ b/packages/kit/src/runtime/app/paths/internal/client.js @@ -1,3 +1,4 @@ export const base = __SVELTEKIT_PAYLOAD__?.base ?? __SVELTEKIT_PATHS_BASE__; export const assets = __SVELTEKIT_PAYLOAD__?.assets ?? base ?? __SVELTEKIT_PATHS_ASSETS__; export const app_dir = __SVELTEKIT_APP_DIR__; +export const hash_routing = __SVELTEKIT_HASH_ROUTING__; diff --git a/packages/kit/src/types/global-private.d.ts b/packages/kit/src/types/global-private.d.ts index 3ab871bd5b48..47c78935ba23 100644 --- a/packages/kit/src/types/global-private.d.ts +++ b/packages/kit/src/types/global-private.d.ts @@ -13,6 +13,8 @@ declare global { const __SVELTEKIT_EXPERIMENTAL__REMOTE_FUNCTIONS__: boolean; /** True if `config.kit.router.resolution === 'client'` */ const __SVELTEKIT_CLIENT_ROUTING__: boolean; + /** True if `config.kit.router.type === 'hash'` */ + const __SVELTEKIT_HASH_ROUTING__: boolean; /** * True if any node in the manifest has a server load function. * Used for treeshaking server load code from client bundles when no server loads exist. From bcd3b7e864e5d302049e4038aa617bddbe1f83bb Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Wed, 22 Oct 2025 17:24:10 +0800 Subject: [PATCH 3/4] changeset --- .changeset/blue-baboons-jam.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/blue-baboons-jam.md diff --git a/.changeset/blue-baboons-jam.md b/.changeset/blue-baboons-jam.md new file mode 100644 index 000000000000..1b8e646a27b0 --- /dev/null +++ b/.changeset/blue-baboons-jam.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: include hash when using `resolve` with hash routing enabled From 4318d08c32a48d3637fd5dbb54e6f4283378c12b Mon Sep 17 00:00:00 2001 From: Tee Ming Chew Date: Wed, 22 Oct 2025 17:25:44 +0800 Subject: [PATCH 4/4] format --- packages/kit/src/runtime/app/paths/client.js | 4 +++- packages/kit/test/apps/hash-based-routing/test/test.js | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/kit/src/runtime/app/paths/client.js b/packages/kit/src/runtime/app/paths/client.js index 982b0d194434..4de84a1d7c8f 100644 --- a/packages/kit/src/runtime/app/paths/client.js +++ b/packages/kit/src/runtime/app/paths/client.js @@ -53,7 +53,9 @@ const pathname_prefix = hash_routing ? '#' : ''; export function resolve(...args) { // The type error is correct here, and if someone doesn't pass params when they should there's a runtime error, // but we don't want to adjust the internal resolve_route function to accept `undefined`, hence the type cast. - return base + pathname_prefix + resolve_route(args[0], /** @type {Record} */ (args[1])); + return ( + base + pathname_prefix + resolve_route(args[0], /** @type {Record} */ (args[1])) + ); } export { base, assets, resolve as resolveRoute }; diff --git a/packages/kit/test/apps/hash-based-routing/test/test.js b/packages/kit/test/apps/hash-based-routing/test/test.js index 1b020d5560ec..6801d80444d0 100644 --- a/packages/kit/test/apps/hash-based-routing/test/test.js +++ b/packages/kit/test/apps/hash-based-routing/test/test.js @@ -134,5 +134,5 @@ test.describe('hash based navigation', () => { const url = new URL(page.url()); expect(url.pathname).toBe('/'); expect(url.hash).toBe('#/'); - }) + }); });