Skip to content

Commit e7cd0c2

Browse files
fix: use __SVELTEKIT_PAYLOAD__ to reference boot payload (#14127)
* fix * changeset * reference the proxied object instead * use __SVELTEKIT_PAYLOAD__ to reference boot object * couple more comments * couple more comments * fix * remove unused property --------- Co-authored-by: Chew Tee Ming <[email protected]>
1 parent 6c13063 commit e7cd0c2

File tree

8 files changed

+61
-40
lines changed

8 files changed

+61
-40
lines changed

.changeset/cute-boats-hide.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+
fix: ensure `form()` remote functions work when the app is configured to a single output

packages/kit/src/exports/vite/index.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,10 @@ async function kit({ svelte_config }) {
331331
__SVELTEKIT_DEV__: 'false',
332332
__SVELTEKIT_EMBEDDED__: s(kit.embedded),
333333
__SVELTEKIT_EXPERIMENTAL__REMOTE_FUNCTIONS__: s(kit.experimental.remoteFunctions),
334-
__SVELTEKIT_CLIENT_ROUTING__: kit.router.resolution === 'client' ? 'true' : 'false'
334+
__SVELTEKIT_CLIENT_ROUTING__: kit.router.resolution === 'client' ? 'true' : 'false',
335+
__SVELTEKIT_PAYLOAD__: new_config.build.ssr
336+
? '{}'
337+
: `globalThis.__sveltekit_${version_hash}`
335338
};
336339

337340
if (!secondary_build_started) {
@@ -343,9 +346,13 @@ async function kit({ svelte_config }) {
343346
__SVELTEKIT_DEV__: 'true',
344347
__SVELTEKIT_EMBEDDED__: s(kit.embedded),
345348
__SVELTEKIT_EXPERIMENTAL__REMOTE_FUNCTIONS__: s(kit.experimental.remoteFunctions),
346-
__SVELTEKIT_CLIENT_ROUTING__: kit.router.resolution === 'client' ? 'true' : 'false'
349+
__SVELTEKIT_CLIENT_ROUTING__: kit.router.resolution === 'client' ? 'true' : 'false',
350+
__SVELTEKIT_PAYLOAD__: 'globalThis.__sveltekit_dev'
347351
};
348352

353+
// @ts-ignore this prevents a reference error if `client.js` is imported on the server
354+
globalThis.__sveltekit_dev = {};
355+
349356
// These Kit dependencies are packaged as CommonJS, which means they must always be externalized.
350357
// Without this, the tests will still pass but `pnpm dev` will fail in projects that link `@sveltejs/kit`.
351358
/** @type {NonNullable<import('vite').UserConfig['ssr']>} */ (new_config.ssr).external = [

packages/kit/src/runtime/app/server/remote/form.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export function form(fn) {
6767
// We don't need to care about args or deduplicating calls, because uneval results are only relevant in full page reloads
6868
// where only one form submission is active at the same time
6969
if (!event.isRemoteRequest) {
70-
state.form_result = [key, result];
70+
(state.remote_data ??= {})[__.id] = result;
7171
}
7272

7373
return result;
@@ -89,8 +89,8 @@ export function form(fn) {
8989
Object.defineProperty(instance, 'result', {
9090
get() {
9191
try {
92-
const { form_result } = get_event_state(getRequestEvent());
93-
return form_result && form_result[0] === key ? form_result[1] : undefined;
92+
const { remote_data } = get_event_state(getRequestEvent());
93+
return remote_data?.[__.id];
9494
} catch {
9595
return undefined;
9696
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ let target;
178178
export let app;
179179

180180
/** @type {Record<string, any>} */
181-
export let remote_responses;
181+
export const remote_responses = __SVELTEKIT_PAYLOAD__.data ?? {};
182182

183183
/** @type {Array<((url: URL) => boolean)>} */
184184
const invalidated = [];
@@ -288,7 +288,6 @@ export async function start(_app, _target, hydrate) {
288288
}
289289

290290
app = _app;
291-
remote_responses = hydrate?.remote ?? {};
292291

293292
await _app.hooks.init?.();
294293

packages/kit/src/runtime/client/remote-functions/form.svelte.js

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import * as devalue from 'devalue';
66
import { DEV } from 'esm-env';
77
import { HttpError } from '@sveltejs/kit/internal';
88
import { app, remote_responses, started, goto, set_nearest_error_page } from '../client.js';
9-
import { create_remote_cache_key } from '../../shared.js';
109
import { tick } from 'svelte';
1110
import { refresh_queries, release_overrides } from './shared.svelte.js';
1211

@@ -26,9 +25,7 @@ export function form(id) {
2625
const action = '?/remote=' + encodeURIComponent(action_id);
2726

2827
/** @type {any} */
29-
let result = $state(
30-
!started ? (remote_responses[create_remote_cache_key(action, '')] ?? undefined) : undefined
31-
);
28+
let result = $state(started ? undefined : remote_responses[action_id]);
3229

3330
/**
3431
* @param {FormData} data

packages/kit/src/runtime/server/event-state.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/** @import { RequestEvent } from '@sveltejs/kit' */
2-
/** @import { PrerenderOptions, ServerHooks, SSROptions, SSRState } from 'types' */
2+
/** @import { MaybePromise, PrerenderOptions, ServerHooks, SSROptions, SSRState } from 'types' */
33

44
export const EVENT_STATE = Symbol('remote');
55

@@ -11,8 +11,7 @@ export const EVENT_STATE = Symbol('remote');
1111
* transport: ServerHooks['transport'];
1212
* handleValidationError: ServerHooks['handleValidationError'];
1313
* form_instances?: Map<any, any>;
14-
* form_result?: [key: any, value: any];
15-
* remote_data?: Record<string, Promise<any>>;
14+
* remote_data?: Record<string, MaybePromise<any>>;
1615
* refreshes?: Record<string, any>;
1716
* }} RequestEventState
1817
*/

packages/kit/src/runtime/server/page/render.js

Lines changed: 25 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,29 @@ export async function render_response({
378378
}`);
379379
}
380380

381+
const { remote_data } = get_event_state(event);
382+
383+
if (remote_data) {
384+
/** @type {Record<string, any>} */
385+
const remote = {};
386+
387+
for (const key in remote_data) {
388+
remote[key] = await remote_data[key];
389+
}
390+
391+
// TODO this is repeated in a few places — dedupe it
392+
const replacer = (/** @type {any} */ thing) => {
393+
for (const key in options.hooks.transport) {
394+
const encoded = options.hooks.transport[key].encode(thing);
395+
if (encoded) {
396+
return `app.decode('${key}', ${devalue.uneval(encoded, replacer)})`;
397+
}
398+
}
399+
};
400+
401+
properties.push(`data: ${devalue.uneval(remote, replacer)}`);
402+
}
403+
381404
// create this before declaring `data`, which may contain references to `${global}`
382405
blocks.push(`${global} = {
383406
${properties.join(',\n\t\t\t\t\t\t')}
@@ -388,7 +411,7 @@ export async function render_response({
388411
blocks.push('const element = document.currentScript.parentElement;');
389412

390413
if (page_config.ssr) {
391-
const serialized = { form: 'null', error: 'null', remote: 'null' };
414+
const serialized = { form: 'null', error: 'null' };
392415

393416
if (form_value) {
394417
serialized.form = uneval_action_response(
@@ -402,35 +425,11 @@ export async function render_response({
402425
serialized.error = devalue.uneval(error);
403426
}
404427

405-
const { remote_data } = get_event_state(event);
406-
407-
if (remote_data) {
408-
/** @type {Record<string, any>} */
409-
const remote = {};
410-
411-
for (const key in remote_data) {
412-
remote[key] = await remote_data[key];
413-
}
414-
415-
// TODO this is repeated in a few places — dedupe it
416-
const replacer = (/** @type {any} */ thing) => {
417-
for (const key in options.hooks.transport) {
418-
const encoded = options.hooks.transport[key].encode(thing);
419-
if (encoded) {
420-
return `app.decode('${key}', ${devalue.uneval(encoded, replacer)})`;
421-
}
422-
}
423-
};
424-
425-
serialized.remote = devalue.uneval(remote, replacer);
426-
}
427-
428428
const hydrate = [
429429
`node_ids: [${branch.map(({ node }) => node.index).join(', ')}]`,
430430
`data: ${data}`,
431431
`form: ${serialized.form}`,
432-
`error: ${serialized.error}`,
433-
`remote: ${serialized.remote}`
432+
`error: ${serialized.error}`
434433
];
435434

436435
if (status !== 200) {

packages/kit/src/types/global-private.d.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,21 @@ declare global {
88
const __SVELTEKIT_EXPERIMENTAL__REMOTE_FUNCTIONS__: boolean;
99
/** True if `config.kit.router.resolution === 'client'` */
1010
const __SVELTEKIT_CLIENT_ROUTING__: boolean;
11+
/** The `__sveltekit_abc123` object in the init `<script>` */
12+
const __SVELTEKIT_PAYLOAD__: {
13+
/** The basepath, usually relative to the current page */
14+
base: string;
15+
/** Path to externally-hosted assets */
16+
assets?: string;
17+
/** Public environment variables */
18+
env?: Record<string, string>;
19+
/** Serialized data from remote functions */
20+
data?: Record<string, any>;
21+
/** Create a placeholder promise */
22+
defer?: (id: number) => Promise<any>;
23+
/** Resolve a placeholder promise */
24+
resolve?: (data: { id: number; data: any; error: any }) => void;
25+
};
1126
/**
1227
* This makes the use of specific features visible at both dev and build time, in such a
1328
* way that we can error when they are not supported by the target platform.

0 commit comments

Comments
 (0)