Skip to content

Commit

Permalink
fix: change server-side route resolution endpoint (#13461)
Browse files Browse the repository at this point in the history
Instead of doing route resolution requests through `_app/route/...`, do it through `<pathname>/__route.js`:
- more consistent with what we do for `/__data.json` requests already
- avoids problems with cookies: If you set a cookie on `/foo`, we would need to add it to `_app/route/foo` aswell, if we didn't change this
  • Loading branch information
dummdidumm authored Feb 13, 2025
1 parent 9719e1e commit 3d88ae3
Show file tree
Hide file tree
Showing 9 changed files with 26 additions and 25 deletions.
6 changes: 6 additions & 0 deletions .changeset/modern-fishes-chew.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@sveltejs/adapter-vercel': patch
'@sveltejs/kit': patch
---

fix: change server-side route resolution endpoint
2 changes: 1 addition & 1 deletion packages/adapter-vercel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ const plugin = function (defaults = {}) {
);

static_config.routes.push({
src: `${builder.config.kit.paths.base}/${builder.config.kit.appDir}/route(\\.js|/.*)`,
src: `${builder.config.kit.paths.base}/(|.+/)__route\\.js`,
dest: `${builder.config.kit.paths.base}/${builder.config.kit.appDir}/route`
});
}
Expand Down
4 changes: 2 additions & 2 deletions packages/kit/src/runtime/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { INVALIDATED_PARAM, TRAILING_SLASH_PARAM, validate_depends } from '../sh
import { get_message, get_status } from '../../utils/error.js';
import { writable } from 'svelte/store';
import { page, update, navigating } from './state.svelte.js';
import { add_data_suffix, add_resolution_prefix } from '../pathname.js';
import { add_data_suffix, add_resolution_suffix } from '../pathname.js';

const ICON_REL_ATTRIBUTES = new Set(['icon', 'shortcut icon', 'apple-touch-icon']);

Expand Down Expand Up @@ -1265,7 +1265,7 @@ async function get_navigation_intent(url, invalidating) {
/** @type {{ route?: import('types').CSRRouteServer, params: Record<string, string>}} */
const { route, params } = await import(
/* @vite-ignore */
add_resolution_prefix(url.pathname)
add_resolution_suffix(url.pathname)
);

if (!route) return;
Expand Down
19 changes: 7 additions & 12 deletions packages/kit/src/runtime/pathname.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { base, app_dir } from '__sveltekit/paths';

const DATA_SUFFIX = '/__data.json';
const HTML_DATA_SUFFIX = '.html__data.json';

Expand All @@ -23,32 +21,29 @@ export function strip_data_suffix(pathname) {
return pathname.slice(0, -DATA_SUFFIX.length);
}

const ROUTE_PREFIX = `${base}/${app_dir}/route`;
const ROUTE_SUFFIX = '/__route.js';

/**
* @param {string} pathname
* @returns {boolean}
*/
export function has_resolution_prefix(pathname) {
return pathname === `${ROUTE_PREFIX}.js` || pathname.startsWith(`${ROUTE_PREFIX}/`);
export function has_resolution_suffix(pathname) {
return pathname.endsWith(ROUTE_SUFFIX);
}

/**
* Convert a regular URL to a route to send to SvelteKit's server-side route resolution endpoint
* @param {string} pathname
* @returns {string}
*/
export function add_resolution_prefix(pathname) {
let normalized = pathname.slice(base.length);
if (normalized.endsWith('/')) normalized = normalized.slice(0, -1);

return `${ROUTE_PREFIX}${normalized}.js`;
export function add_resolution_suffix(pathname) {
return pathname.replace(/\/$/, '') + ROUTE_SUFFIX;
}

/**
* @param {string} pathname
* @returns {string}
*/
export function strip_resolution_prefix(pathname) {
return base + (pathname.slice(ROUTE_PREFIX.length, -3) || '/');
export function strip_resolution_suffix(pathname) {
return pathname.slice(0, -ROUTE_SUFFIX.length);
}
6 changes: 3 additions & 3 deletions packages/kit/src/runtime/server/page/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { create_async_iterator } from '../../../utils/streaming.js';
import { SVELTE_KIT_ASSETS } from '../../../constants.js';
import { SCHEME } from '../../../utils/url.js';
import { create_server_routing_response, generate_route_object } from './server_routing.js';
import { add_resolution_prefix } from '../../pathname.js';
import { add_resolution_suffix } from '../../pathname.js';

// TODO rename this function/module

Expand Down Expand Up @@ -321,9 +321,9 @@ export async function render_response({
}
}

// prerender a `/_app/route/path/to/page.js` module
// prerender a `/path/to/page/__route.js` module
if (manifest._.client.routes && state.prerendering && !state.prerendering.fallback) {
const pathname = add_resolution_prefix(event.url.pathname);
const pathname = add_resolution_suffix(event.url.pathname);

state.prerendering.dependencies.set(
pathname,
Expand Down
8 changes: 4 additions & 4 deletions packages/kit/src/runtime/server/respond.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ import { resolve_route } from './page/server_routing.js';
import { validateHeaders } from './validate-headers.js';
import {
has_data_suffix,
has_resolution_prefix,
has_resolution_suffix,
strip_data_suffix,
strip_resolution_prefix
strip_resolution_suffix
} from '../pathname.js';

/* global __SVELTEKIT_ADAPTER_NAME__ */
Expand Down Expand Up @@ -94,11 +94,11 @@ export async function respond(request, options, manifest, state) {
* If the request is for a route resolution, first modify the URL, then continue as normal
* for path resolution, then return the route object as a JS file.
*/
const is_route_resolution_request = has_resolution_prefix(url.pathname);
const is_route_resolution_request = has_resolution_suffix(url.pathname);
const is_data_request = has_data_suffix(url.pathname);

if (is_route_resolution_request) {
url.pathname = strip_resolution_prefix(url.pathname);
url.pathname = strip_resolution_suffix(url.pathname);
} else if (is_data_request) {
url.pathname =
strip_data_suffix(url.pathname) +
Expand Down
2 changes: 1 addition & 1 deletion packages/kit/src/types/internal.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export type CSRRoute = {
};

/**
* Definition of a client side route as transported via `_app/route/...` when using server-side route resolution.
* Definition of a client side route as transported via `<pathname>/__route.js` when using server-side route resolution.
*/
export type CSRRouteServer = {
id: string;
Expand Down
2 changes: 1 addition & 1 deletion packages/kit/test/apps/basics/test/client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ test.describe('Load', () => {

// 4. We expect the same data and no new request (except a navigation request in case of server-side route resolution) because it was cached.
expect(await page.textContent('h2')).toBe('a / b');
expect(requests.filter((r) => !r.includes('_app/route'))).toEqual([]);
expect(requests.filter((r) => !r.includes('/__route.js'))).toEqual([]);
});

test('permits 3rd party patching of fetch in universal load functions', async ({ page }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -864,7 +864,7 @@ test.describe('Routing', () => {
await page.locator('button').click();

// Filter out server-side route resolution request
expect(requests.filter((r) => !r.includes('_app/route'))).toEqual([]);
expect(requests.filter((r) => !r.includes('__route.js'))).toEqual([]);
expect(await page.textContent('h1')).toBe('updated');
expect(await page.textContent('h2')).toBe('form');
expect(await page.textContent('h3')).toBe('bar');
Expand Down

0 comments on commit 3d88ae3

Please sign in to comment.