Skip to content

Commit b6a0be7

Browse files
gtm-nayandummdidummbenmccannRich-Harris
authored
chore: deprecate top level promise await behaviour (#11175)
* chore: deprecate top level promise await behaviour * format * Update packages/kit/src/utils/promises.js Co-authored-by: Ben McCann <[email protected]> * more descriptive warning - we can take the developer directly to the file * while we're at it * ugh eslint * gah no good deed goes unpunished * ugh shut up eslint. no-one cares. go home --------- Co-authored-by: Simon H <[email protected]> Co-authored-by: Ben McCann <[email protected]> Co-authored-by: Rich Harris <[email protected]>
1 parent 15422d2 commit b6a0be7

File tree

5 files changed

+66
-11
lines changed

5 files changed

+66
-11
lines changed

.changeset/long-cheetahs-explain.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': minor
3+
---
4+
5+
chore: deprecate top level promise await behaviour

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ export function create_client(app, target) {
559559
} else {
560560
data = (await node.universal.load.call(null, load_input)) ?? null;
561561
}
562-
data = data ? await unwrap_promises(data) : null;
562+
data = data ? await unwrap_promises(data, route.id) : null;
563563
}
564564

565565
return {

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

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,9 @@ export async function load_server_data({
125125
url
126126
});
127127

128-
const data = result ? await unwrap_promises(result) : null;
128+
const data = result ? await unwrap_promises(result, node.server_id) : null;
129129
if (__SVELTEKIT_DEV__) {
130-
validate_load_response(data, /** @type {string} */ (event.route.id));
130+
validate_load_response(data, node.server_id);
131131
}
132132

133133
done = true;
@@ -181,9 +181,9 @@ export async function load_data({
181181
parent
182182
});
183183

184-
const data = result ? await unwrap_promises(result) : null;
184+
const data = result ? await unwrap_promises(result, node.universal_id) : null;
185185
if (__SVELTEKIT_DEV__) {
186-
validate_load_response(data, /** @type {string} */ (event.route.id));
186+
validate_load_response(data, node.universal_id);
187187
}
188188

189189
return data;
@@ -360,12 +360,12 @@ async function stream_to_string(stream) {
360360

361361
/**
362362
* @param {any} data
363-
* @param {string} [routeId]
363+
* @param {string} [id]
364364
*/
365-
function validate_load_response(data, routeId) {
365+
function validate_load_response(data, id) {
366366
if (data != null && Object.getPrototypeOf(data) !== Object.prototype) {
367367
throw new Error(
368-
`a load function related to route '${routeId}' returned ${
368+
`a load function in ${id} returned ${
369369
typeof data !== 'object'
370370
? `a ${typeof data}`
371371
: data instanceof Response

packages/kit/src/utils/promises.js

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,54 @@
1+
import { DEV } from 'esm-env';
2+
3+
/** @type {Set<string> | null} */
4+
let warned = null;
5+
6+
// TODO v2: remove all references to unwrap_promises
7+
18
/**
29
* Given an object, return a new object where all top level values are awaited
310
*
411
* @param {Record<string, any>} object
12+
* @param {string | null} [id]
513
* @returns {Promise<Record<string, any>>}
614
*/
7-
export async function unwrap_promises(object) {
15+
export async function unwrap_promises(object, id) {
16+
if (DEV) {
17+
/** @type {string[]} */
18+
const promises = [];
19+
20+
for (const key in object) {
21+
if (typeof object[key]?.then === 'function') {
22+
promises.push(key);
23+
}
24+
}
25+
26+
if (promises.length > 0) {
27+
if (!warned) warned = new Set();
28+
29+
const last = promises.pop();
30+
31+
const properties =
32+
promises.length > 0
33+
? `${promises.map((p) => `"${p}"`).join(', ')} and "${last}" properties`
34+
: `"${last}" property`;
35+
36+
const location = id ? `the \`load\` function in ${id}` : 'a `load` function';
37+
38+
const description = promises.length > 0 ? 'are promises' : 'is a promise';
39+
40+
const message = `The top-level ${properties} returned from ${location} ${description}.`;
41+
42+
if (!warned.has(message)) {
43+
console.warn(
44+
`\n${message}\n\nIn SvelteKit 2.0, these will longer be awaited automatically. To get rid of this warning, await all promises included as top-level properties in \`load\` return values.\n`
45+
);
46+
47+
warned.add(message);
48+
}
49+
}
50+
}
51+
852
for (const key in object) {
953
if (typeof object[key]?.then === 'function') {
1054
return Object.fromEntries(

packages/kit/test/apps/basics/test/cross-platform/test.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,13 @@ test.describe('Errors', () => {
236236
}
237237

238238
expect(await page.textContent('footer')).toBe('Custom layout');
239+
240+
const details = javaScriptEnabled
241+
? "related to route '/errors/invalid-load-response'"
242+
: 'in src/routes/errors/invalid-load-response/+page.js';
243+
239244
expect(await page.textContent('#message')).toBe(
240-
'This is your custom error page saying: "a load function related to route \'/errors/invalid-load-response\' returned an array, but must return a plain object at the top level (i.e. `return {...}`)"'
245+
`This is your custom error page saying: "a load function ${details} returned an array, but must return a plain object at the top level (i.e. \`return {...}\`)"`
241246
);
242247
});
243248

@@ -254,8 +259,9 @@ test.describe('Errors', () => {
254259
}
255260

256261
expect(await page.textContent('footer')).toBe('Custom layout');
262+
257263
expect(await page.textContent('#message')).toBe(
258-
'This is your custom error page saying: "a load function related to route \'/errors/invalid-server-load-response\' returned an array, but must return a plain object at the top level (i.e. `return {...}`)"'
264+
'This is your custom error page saying: "a load function in src/routes/errors/invalid-server-load-response/+page.server.js returned an array, but must return a plain object at the top level (i.e. `return {...}`)"'
259265
);
260266
});
261267
}

0 commit comments

Comments
 (0)