@sveltejs/kit 1.0.0-next.445 → 1.0.0-next.448
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -9
- package/src/{core/constants.js → constants.js} +2 -0
- package/src/core/env.js +1 -1
- package/src/core/sync/write_ambient.js +1 -1
- package/src/core/sync/write_client_manifest.js +17 -20
- package/src/exports/vite/dev/index.js +1 -1
- package/src/exports/vite/preview/index.js +1 -1
- package/src/runtime/client/ambient.d.ts +8 -2
- package/src/runtime/client/client.js +71 -56
- package/src/runtime/client/parse.js +17 -4
- package/src/runtime/client/start.js +2 -0
- package/src/runtime/client/types.d.ts +2 -0
- package/src/runtime/server/data/index.js +146 -0
- package/src/runtime/server/index.js +20 -143
- package/src/runtime/server/page/index.js +17 -12
- package/src/runtime/server/page/load_data.js +1 -45
- package/src/runtime/server/page/render.js +29 -11
- package/src/runtime/server/page/respond_with_error.js +0 -1
- package/src/runtime/server/utils.js +21 -0
- package/types/internal.d.ts +0 -1
- package/src/core/sync/write_types/test/layout/+layout.js +0 -5
- package/src/core/sync/write_types/test/layout/+layout.server.js +0 -5
- package/src/core/sync/write_types/test/layout/+layout.svelte +0 -0
- package/src/core/sync/write_types/test/layout/+page.js +0 -5
- package/src/core/sync/write_types/test/layout/+page.server.js +0 -5
- package/src/core/sync/write_types/test/layout/+page.svelte +0 -0
- package/src/core/sync/write_types/test/layout/_expected/$types.d.ts +0 -67
- package/src/core/sync/write_types/test/layout-advanced/(main)/+layout.server.js +0 -5
- package/src/core/sync/write_types/test/layout-advanced/(main)/+layout.svelte +0 -0
- package/src/core/sync/write_types/test/layout-advanced/(main)/+page.js +0 -5
- package/src/core/sync/write_types/test/layout-advanced/(main)/+page@.svelte +0 -0
- package/src/core/sync/write_types/test/layout-advanced/(main)/sub/+page.js +0 -5
- package/src/core/sync/write_types/test/layout-advanced/(main)/sub/+page.svelte +0 -0
- package/src/core/sync/write_types/test/layout-advanced/+layout.js +0 -5
- package/src/core/sync/write_types/test/layout-advanced/+layout.svelte +0 -0
- package/src/core/sync/write_types/test/layout-advanced/_expected/$types.d.ts +0 -32
- package/src/core/sync/write_types/test/layout-advanced/_expected/(main)/$types.d.ts +0 -42
- package/src/core/sync/write_types/test/layout-advanced/_expected/(main)/sub/$types.d.ts +0 -33
- package/src/core/sync/write_types/test/simple-page-server-and-shared/+page.js +0 -5
- package/src/core/sync/write_types/test/simple-page-server-and-shared/+page.server.js +0 -5
- package/src/core/sync/write_types/test/simple-page-server-and-shared/+page.svelte +0 -0
- package/src/core/sync/write_types/test/simple-page-server-and-shared/_expected/$types.d.ts +0 -44
- package/src/core/sync/write_types/test/simple-page-server-only/+page.server.js +0 -5
- package/src/core/sync/write_types/test/simple-page-server-only/+page.svelte +0 -0
- package/src/core/sync/write_types/test/simple-page-server-only/_expected/$types.d.ts +0 -30
- package/src/core/sync/write_types/test/simple-page-shared-only/+page.js +0 -5
- package/src/core/sync/write_types/test/simple-page-shared-only/+page.svelte +0 -0
- package/src/core/sync/write_types/test/simple-page-shared-only/_expected/$types.d.ts +0 -33
- package/src/core/sync/write_types/test/slugs/+layout.js +0 -1
- package/src/core/sync/write_types/test/slugs/+layout.svelte +0 -1
- package/src/core/sync/write_types/test/slugs/[...rest]/+page.js +0 -3
- package/src/core/sync/write_types/test/slugs/[...rest]/+page.svelte +0 -0
- package/src/core/sync/write_types/test/slugs/[slug]/+page.js +0 -3
- package/src/core/sync/write_types/test/slugs/[slug]/+page.svelte +0 -0
- package/src/core/sync/write_types/test/slugs/_expected/$types.d.ts +0 -32
- package/src/core/sync/write_types/test/slugs/_expected/[...rest]/$types.d.ts +0 -29
- package/src/core/sync/write_types/test/slugs/_expected/[slug]/$types.d.ts +0 -29
- package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/+layout.js +0 -1
- package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/+layout.svelte +0 -1
- package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/$types.d.ts +0 -30
- package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/nested/$types.d.ts +0 -32
- package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/nested/[...rest]/$types.d.ts +0 -37
- package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/nested/[slug]/$types.d.ts +0 -17
- package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/+layout.js +0 -1
- package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/+layout.svelte +0 -1
- package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/[...rest]/+page.js +0 -3
- package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/[...rest]/+page.svelte +0 -0
- package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/nested/[slug]/+page@.svelte +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltejs/kit",
|
|
3
|
-
"version": "1.0.0-next.
|
|
3
|
+
"version": "1.0.0-next.448",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/sveltejs/kit",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@sveltejs/vite-plugin-svelte": "^1.0.1",
|
|
14
14
|
"cookie": "^0.5.0",
|
|
15
|
-
"devalue": "^
|
|
15
|
+
"devalue": "^3.1.2",
|
|
16
16
|
"kleur": "^4.1.4",
|
|
17
17
|
"magic-string": "^0.26.2",
|
|
18
18
|
"mime": "^3.0.0",
|
|
@@ -36,7 +36,6 @@
|
|
|
36
36
|
"rollup": "^2.75.7",
|
|
37
37
|
"svelte": "^3.48.0",
|
|
38
38
|
"svelte-preprocess": "^4.10.6",
|
|
39
|
-
"tiny-glob": "^0.2.9",
|
|
40
39
|
"typescript": "^4.7.4",
|
|
41
40
|
"uvu": "^0.5.3",
|
|
42
41
|
"vite": "^3.0.9"
|
|
@@ -51,17 +50,16 @@
|
|
|
51
50
|
"files": [
|
|
52
51
|
"src",
|
|
53
52
|
"!src/**/*.spec.js",
|
|
54
|
-
"!src/packaging/test",
|
|
55
53
|
"!src/core/**/fixtures",
|
|
56
|
-
"!src/core
|
|
54
|
+
"!src/core/**/test",
|
|
57
55
|
"types",
|
|
58
56
|
"svelte-kit.js"
|
|
59
57
|
],
|
|
60
58
|
"exports": {
|
|
61
59
|
"./package.json": "./package.json",
|
|
62
60
|
".": {
|
|
63
|
-
"
|
|
64
|
-
"
|
|
61
|
+
"types": "./types/index.d.ts",
|
|
62
|
+
"import": "./src/exports/index.js"
|
|
65
63
|
},
|
|
66
64
|
"./node": {
|
|
67
65
|
"import": "./src/exports/node/index.js"
|
|
@@ -78,7 +76,7 @@
|
|
|
78
76
|
},
|
|
79
77
|
"types": "types/index.d.ts",
|
|
80
78
|
"engines": {
|
|
81
|
-
"node": ">=16.
|
|
79
|
+
"node": ">=16.14"
|
|
82
80
|
},
|
|
83
81
|
"scripts": {
|
|
84
82
|
"build": "npm run types",
|
|
@@ -88,7 +86,7 @@
|
|
|
88
86
|
"format": "npm run lint -- --write",
|
|
89
87
|
"test": "npm run test:unit && npm run test:integration",
|
|
90
88
|
"test:integration": "pnpm run -r --workspace-concurrency 1 --filter=\"./test/**\" test",
|
|
91
|
-
"test:unit": "uvu src \"(spec\\.js|test[\\\\/]index\\.js)\"
|
|
89
|
+
"test:unit": "uvu src \"(spec\\.js|test[\\\\/]index\\.js)\"",
|
|
92
90
|
"types": "node scripts/extract-types.js",
|
|
93
91
|
"postinstall": "node svelte-kit.js sync"
|
|
94
92
|
}
|
package/src/core/env.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { get_env } from '../../exports/vite/utils.js';
|
|
3
|
-
import { GENERATED_COMMENT } from '
|
|
3
|
+
import { GENERATED_COMMENT } from '../../constants.js';
|
|
4
4
|
import { create_types } from '../env.js';
|
|
5
5
|
import { write_if_changed } from './utils.js';
|
|
6
6
|
|
|
@@ -43,22 +43,29 @@ export function write_client_manifest(manifest_data, output) {
|
|
|
43
43
|
})
|
|
44
44
|
.join(',\n\t');
|
|
45
45
|
|
|
46
|
+
const layouts_with_server_load = new Set();
|
|
47
|
+
|
|
46
48
|
const dictionary = `{
|
|
47
49
|
${manifest_data.routes
|
|
48
50
|
.map((route) => {
|
|
49
51
|
if (route.page) {
|
|
50
52
|
const errors = route.page.errors.slice(1).map((n) => n ?? '');
|
|
51
|
-
const layouts = route.page.layouts.slice(1).map((n) =>
|
|
52
|
-
if (n == undefined) {
|
|
53
|
-
return '';
|
|
54
|
-
}
|
|
55
|
-
return get_node_id(manifest_data.nodes, n);
|
|
56
|
-
});
|
|
53
|
+
const layouts = route.page.layouts.slice(1).map((n) => n ?? '');
|
|
57
54
|
|
|
58
55
|
while (layouts.at(-1) === '') layouts.pop();
|
|
59
56
|
while (errors.at(-1) === '') errors.pop();
|
|
60
57
|
|
|
61
|
-
|
|
58
|
+
// Encode whether or not the route uses server data
|
|
59
|
+
// using the ones' complement, to save space
|
|
60
|
+
const array = [`${route.leaf?.server ? '~' : ''}${route.page.leaf}`];
|
|
61
|
+
// Encode whether or not the layout uses server data.
|
|
62
|
+
// It's a different method compared to pages because layouts
|
|
63
|
+
// are reused across pages, so we safe space by doing it this way.
|
|
64
|
+
route.page.layouts.forEach((layout) => {
|
|
65
|
+
if (layout != undefined && manifest_data.nodes[layout].server) {
|
|
66
|
+
layouts_with_server_load.add(layout);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
62
69
|
|
|
63
70
|
// only include non-root layout/error nodes if they exist
|
|
64
71
|
if (layouts.length > 0 || errors.length > 0) array.push(`[${layouts.join(',')}]`);
|
|
@@ -77,21 +84,11 @@ export function write_client_manifest(manifest_data, output) {
|
|
|
77
84
|
trim(`
|
|
78
85
|
export { matchers } from './client-matchers.js';
|
|
79
86
|
|
|
80
|
-
export const nodes = [
|
|
81
|
-
|
|
82
|
-
];
|
|
87
|
+
export const nodes = [${nodes}];
|
|
88
|
+
|
|
89
|
+
export const server_loads = [${[...layouts_with_server_load].join(',')}];
|
|
83
90
|
|
|
84
91
|
export const dictionary = ${dictionary};
|
|
85
92
|
`)
|
|
86
93
|
);
|
|
87
94
|
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Encode whether or not the route uses the server data
|
|
91
|
-
* using the ones' complement, to save space
|
|
92
|
-
* @param {import('types').PageNode[]} nodes
|
|
93
|
-
* @param {number} id
|
|
94
|
-
*/
|
|
95
|
-
function get_node_id(nodes, id) {
|
|
96
|
-
return `${nodes[id].server ? '~' : ''}${id}`;
|
|
97
|
-
}
|
|
@@ -8,7 +8,7 @@ import { installPolyfills } from '../../../exports/node/polyfills.js';
|
|
|
8
8
|
import { coalesce_to_error } from '../../../utils/error.js';
|
|
9
9
|
import { posixify } from '../../../utils/filesystem.js';
|
|
10
10
|
import { load_template } from '../../../core/config/index.js';
|
|
11
|
-
import { SVELTE_KIT_ASSETS } from '../../../
|
|
11
|
+
import { SVELTE_KIT_ASSETS } from '../../../constants.js';
|
|
12
12
|
import * as sync from '../../../core/sync/sync.js';
|
|
13
13
|
import { get_mime_lookup, runtime_base, runtime_prefix } from '../../../core/utils.js';
|
|
14
14
|
import { get_env, prevent_illegal_vite_imports, resolve_entry } from '../utils.js';
|
|
@@ -4,7 +4,7 @@ import sirv from 'sirv';
|
|
|
4
4
|
import { pathToFileURL } from 'url';
|
|
5
5
|
import { getRequest, setResponse } from '../../../exports/node/index.js';
|
|
6
6
|
import { installPolyfills } from '../../../exports/node/polyfills.js';
|
|
7
|
-
import { SVELTE_KIT_ASSETS } from '../../../
|
|
7
|
+
import { SVELTE_KIT_ASSETS } from '../../../constants.js';
|
|
8
8
|
import { loadEnv } from 'vite';
|
|
9
9
|
|
|
10
10
|
/** @typedef {import('http').IncomingMessage} Req */
|
|
@@ -6,13 +6,19 @@ declare module '__GENERATED__/client-manifest.js' {
|
|
|
6
6
|
*/
|
|
7
7
|
export const nodes: CSRPageNodeLoader[];
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* A list of all layout node ids that have a server load function.
|
|
11
|
+
* Pages are not present because it's shorter to encode it on the leaf itself.
|
|
12
|
+
*/
|
|
13
|
+
export const server_loads: number[];
|
|
14
|
+
|
|
9
15
|
/**
|
|
10
16
|
* A map of `[routeId: string]: [leaf, layouts, errors]` tuples, which
|
|
11
17
|
* is parsed into an array of routes on startup. The numbers refer to the indices in `nodes`.
|
|
12
|
-
* If the number is negative, it means it does use a server load function and the complement is the node index.
|
|
18
|
+
* If the leaf number is negative, it means it does use a server load function and the complement is the node index.
|
|
13
19
|
* The route layout and error nodes are not referenced, they are always number 0 and 1 and always apply.
|
|
14
20
|
*/
|
|
15
|
-
export const dictionary: Record<string, [leaf: number, layouts
|
|
21
|
+
export const dictionary: Record<string, [leaf: number, layouts: number[], errors?: number[]]>;
|
|
16
22
|
|
|
17
23
|
export const matchers: Record<string, ParamMatcher>;
|
|
18
24
|
}
|
|
@@ -7,14 +7,15 @@ import { parse } from './parse.js';
|
|
|
7
7
|
import { error } from '../../exports/index.js';
|
|
8
8
|
|
|
9
9
|
import Root from '__GENERATED__/root.svelte';
|
|
10
|
-
import { nodes, dictionary, matchers } from '__GENERATED__/client-manifest.js';
|
|
10
|
+
import { nodes, server_loads, dictionary, matchers } from '__GENERATED__/client-manifest.js';
|
|
11
11
|
import { HttpError, Redirect } from '../control.js';
|
|
12
12
|
import { stores } from './singletons.js';
|
|
13
|
+
import { DATA_SUFFIX } from '../../constants.js';
|
|
13
14
|
|
|
14
15
|
const SCROLL_KEY = 'sveltekit:scroll';
|
|
15
16
|
const INDEX_KEY = 'sveltekit:index';
|
|
16
17
|
|
|
17
|
-
const routes = parse(nodes, dictionary, matchers);
|
|
18
|
+
const routes = parse(nodes, server_loads, dictionary, matchers);
|
|
18
19
|
|
|
19
20
|
const default_layout_loader = nodes[0];
|
|
20
21
|
const default_error_loader = nodes[1];
|
|
@@ -393,7 +394,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
393
394
|
* status: number;
|
|
394
395
|
* error: HttpError | Error | null;
|
|
395
396
|
* routeId: string | null;
|
|
396
|
-
* validation_errors?: string |
|
|
397
|
+
* validation_errors?: Record<string, any> | null;
|
|
397
398
|
* }} opts
|
|
398
399
|
*/
|
|
399
400
|
async function get_navigation_result_from_branch({
|
|
@@ -715,24 +716,14 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
715
716
|
|
|
716
717
|
if (invalid_server_nodes.some(Boolean)) {
|
|
717
718
|
try {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
);
|
|
726
|
-
|
|
727
|
-
server_data = /** @type {import('types').ServerData} */ (await res.json());
|
|
728
|
-
|
|
729
|
-
if (!res.ok) {
|
|
730
|
-
throw server_data;
|
|
731
|
-
}
|
|
732
|
-
} catch (e) {
|
|
733
|
-
// something went catastrophically wrong — bail and defer to the server
|
|
734
|
-
native_navigation(url);
|
|
735
|
-
return;
|
|
719
|
+
server_data = await load_data(url, invalid_server_nodes);
|
|
720
|
+
} catch (error) {
|
|
721
|
+
return load_root_error_page({
|
|
722
|
+
status: 500,
|
|
723
|
+
error: /** @type {Error} */ (error),
|
|
724
|
+
url,
|
|
725
|
+
routeId: route.id
|
|
726
|
+
});
|
|
736
727
|
}
|
|
737
728
|
|
|
738
729
|
if (server_data.type === 'redirect') {
|
|
@@ -882,19 +873,18 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
882
873
|
if (node.server) {
|
|
883
874
|
// TODO post-https://github.com/sveltejs/kit/discussions/6124 we can use
|
|
884
875
|
// existing root layout data
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
{
|
|
888
|
-
headers: {
|
|
889
|
-
'x-sveltekit-invalidated': '1'
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
);
|
|
876
|
+
try {
|
|
877
|
+
const server_data = await load_data(url, [true]);
|
|
893
878
|
|
|
894
|
-
|
|
895
|
-
|
|
879
|
+
if (
|
|
880
|
+
server_data.type !== 'data' ||
|
|
881
|
+
(server_data.nodes[0] && server_data.nodes[0].type !== 'data')
|
|
882
|
+
) {
|
|
883
|
+
throw 0;
|
|
884
|
+
}
|
|
896
885
|
|
|
897
|
-
|
|
886
|
+
server_data_node = server_data.nodes[0] ?? null;
|
|
887
|
+
} catch {
|
|
898
888
|
// at this point we have no choice but to fall back to the server
|
|
899
889
|
native_navigation(url);
|
|
900
890
|
|
|
@@ -1298,32 +1288,24 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1298
1288
|
});
|
|
1299
1289
|
},
|
|
1300
1290
|
|
|
1301
|
-
_hydrate: async ({
|
|
1291
|
+
_hydrate: async ({
|
|
1292
|
+
status,
|
|
1293
|
+
error: original_error, // TODO get rid of this
|
|
1294
|
+
node_ids,
|
|
1295
|
+
params,
|
|
1296
|
+
routeId,
|
|
1297
|
+
data: server_data_nodes,
|
|
1298
|
+
errors: validation_errors
|
|
1299
|
+
}) => {
|
|
1302
1300
|
const url = new URL(location.href);
|
|
1303
1301
|
|
|
1304
1302
|
/** @type {import('./types').NavigationFinished | undefined} */
|
|
1305
1303
|
let result;
|
|
1306
1304
|
|
|
1307
1305
|
try {
|
|
1308
|
-
/**
|
|
1309
|
-
* @param {string} type
|
|
1310
|
-
* @param {any} fallback
|
|
1311
|
-
*/
|
|
1312
|
-
const parse = (type, fallback) => {
|
|
1313
|
-
const script = document.querySelector(`script[sveltekit\\:data-type="${type}"]`);
|
|
1314
|
-
return script?.textContent ? JSON.parse(script.textContent) : fallback;
|
|
1315
|
-
};
|
|
1316
|
-
/**
|
|
1317
|
-
* @type {Array<import('types').ServerDataNode | null>}
|
|
1318
|
-
* On initial navigation, this will only consist of data nodes or `null`.
|
|
1319
|
-
* A possible error is passed through the `error` property, in which case
|
|
1320
|
-
* the last entry of `node_ids` is an error page and the last entry of
|
|
1321
|
-
* `server_data_nodes` is `null`.
|
|
1322
|
-
*/
|
|
1323
|
-
const server_data_nodes = parse('server_data', []);
|
|
1324
|
-
const validation_errors = parse('validation_errors', undefined);
|
|
1325
|
-
|
|
1326
1306
|
const branch_promises = node_ids.map(async (n, i) => {
|
|
1307
|
+
const server_data_node = server_data_nodes[i];
|
|
1308
|
+
|
|
1327
1309
|
return load_node({
|
|
1328
1310
|
loader: nodes[n],
|
|
1329
1311
|
url,
|
|
@@ -1336,7 +1318,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1336
1318
|
}
|
|
1337
1319
|
return data;
|
|
1338
1320
|
},
|
|
1339
|
-
server_data_node: create_data_node(
|
|
1321
|
+
server_data_node: create_data_node(server_data_node)
|
|
1340
1322
|
});
|
|
1341
1323
|
});
|
|
1342
1324
|
|
|
@@ -1345,13 +1327,15 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1345
1327
|
params,
|
|
1346
1328
|
branch: await Promise.all(branch_promises),
|
|
1347
1329
|
status,
|
|
1348
|
-
error: /** @type {import('../server/page/types').SerializedHttpError} */ (
|
|
1330
|
+
error: /** @type {import('../server/page/types').SerializedHttpError} */ (original_error)
|
|
1349
1331
|
?.__is_http_error
|
|
1350
1332
|
? new HttpError(
|
|
1351
|
-
/** @type {import('../server/page/types').SerializedHttpError} */ (
|
|
1352
|
-
|
|
1333
|
+
/** @type {import('../server/page/types').SerializedHttpError} */ (
|
|
1334
|
+
original_error
|
|
1335
|
+
).status,
|
|
1336
|
+
original_error.message
|
|
1353
1337
|
)
|
|
1354
|
-
:
|
|
1338
|
+
: original_error,
|
|
1355
1339
|
validation_errors,
|
|
1356
1340
|
routeId
|
|
1357
1341
|
});
|
|
@@ -1377,3 +1361,34 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1377
1361
|
}
|
|
1378
1362
|
};
|
|
1379
1363
|
}
|
|
1364
|
+
|
|
1365
|
+
let data_id = 1;
|
|
1366
|
+
|
|
1367
|
+
/**
|
|
1368
|
+
* @param {URL} url
|
|
1369
|
+
* @param {boolean[]} invalid
|
|
1370
|
+
* @returns {Promise<import('types').ServerData>}
|
|
1371
|
+
*/
|
|
1372
|
+
async function load_data(url, invalid) {
|
|
1373
|
+
const data_url = new URL(url);
|
|
1374
|
+
data_url.pathname = url.pathname.replace(/\/$/, '') + DATA_SUFFIX;
|
|
1375
|
+
data_url.searchParams.set('__invalid', invalid.map((x) => (x ? 'y' : 'n')).join(''));
|
|
1376
|
+
data_url.searchParams.set('__id', String(data_id++));
|
|
1377
|
+
|
|
1378
|
+
// The __data.js file is generated by the server and looks like
|
|
1379
|
+
// `window.__sveltekit_data = ${devalue(data)}`. We do this instead
|
|
1380
|
+
// of `export const data` because modules are cached indefinitely,
|
|
1381
|
+
// and that would cause memory leaks.
|
|
1382
|
+
//
|
|
1383
|
+
// The data is read and deleted in the same tick as the promise
|
|
1384
|
+
// resolves, so it's not vulnerable to race conditions
|
|
1385
|
+
await import(/* @vite-ignore */ data_url.href);
|
|
1386
|
+
|
|
1387
|
+
// @ts-expect-error
|
|
1388
|
+
const server_data = window.__sveltekit_data;
|
|
1389
|
+
|
|
1390
|
+
// @ts-expect-error
|
|
1391
|
+
delete window.__sveltekit_data;
|
|
1392
|
+
|
|
1393
|
+
return server_data;
|
|
1394
|
+
}
|
|
@@ -2,11 +2,14 @@ import { exec, parse_route_id } from '../../utils/routing.js';
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @param {import('types').CSRPageNodeLoader[]} nodes
|
|
5
|
+
* @param {number[]} server_loads
|
|
5
6
|
* @param {typeof import('__GENERATED__/client-manifest.js').dictionary} dictionary
|
|
6
7
|
* @param {Record<string, (param: string) => boolean>} matchers
|
|
7
8
|
* @returns {import('types').CSRRoute[]}
|
|
8
9
|
*/
|
|
9
|
-
export function parse(nodes, dictionary, matchers) {
|
|
10
|
+
export function parse(nodes, server_loads, dictionary, matchers) {
|
|
11
|
+
const layouts_with_server_load = new Set(server_loads);
|
|
12
|
+
|
|
10
13
|
return Object.entries(dictionary).map(([id, [leaf, layouts, errors]]) => {
|
|
11
14
|
const { pattern, names, types } = parse_route_id(id);
|
|
12
15
|
|
|
@@ -18,8 +21,8 @@ export function parse(nodes, dictionary, matchers) {
|
|
|
18
21
|
if (match) return exec(match, names, types, matchers);
|
|
19
22
|
},
|
|
20
23
|
errors: [1, ...(errors || [])].map((n) => nodes[n]),
|
|
21
|
-
layouts: [0, ...(layouts || [])].map(
|
|
22
|
-
leaf:
|
|
24
|
+
layouts: [0, ...(layouts || [])].map(create_layout_loader),
|
|
25
|
+
leaf: create_leaf_loader(leaf)
|
|
23
26
|
};
|
|
24
27
|
|
|
25
28
|
// bit of a hack, but ensures that layout/error node lists are the same
|
|
@@ -37,11 +40,21 @@ export function parse(nodes, dictionary, matchers) {
|
|
|
37
40
|
* @param {number} id
|
|
38
41
|
* @returns {[boolean, import('types').CSRPageNodeLoader]}
|
|
39
42
|
*/
|
|
40
|
-
function
|
|
43
|
+
function create_leaf_loader(id) {
|
|
41
44
|
// whether or not the route uses the server data is
|
|
42
45
|
// encoded using the ones' complement, to save space
|
|
43
46
|
const uses_server_data = id < 0;
|
|
44
47
|
if (uses_server_data) id = ~id;
|
|
45
48
|
return [uses_server_data, nodes[id]];
|
|
46
49
|
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @param {number | undefined} id
|
|
53
|
+
* @returns {[boolean, import('types').CSRPageNodeLoader] | undefined}
|
|
54
|
+
*/
|
|
55
|
+
function create_layout_loader(id) {
|
|
56
|
+
// whether or not the layout uses the server data is
|
|
57
|
+
// encoded in the layouts array, to save space
|
|
58
|
+
return id === undefined ? id : [layouts_with_server_load.has(id), nodes[id]];
|
|
59
|
+
}
|
|
47
60
|
}
|
|
@@ -20,6 +20,8 @@ export { set_public_env } from '../env-public.js';
|
|
|
20
20
|
* node_ids: number[];
|
|
21
21
|
* params: Record<string, string>;
|
|
22
22
|
* routeId: string | null;
|
|
23
|
+
* data: Array<import('types').ServerDataNode | null>;
|
|
24
|
+
* errors: Record<string, any> | null;
|
|
23
25
|
* };
|
|
24
26
|
* }} opts
|
|
25
27
|
*/
|
|
@@ -27,6 +27,8 @@ export interface Client {
|
|
|
27
27
|
node_ids: number[];
|
|
28
28
|
params: Record<string, string>;
|
|
29
29
|
routeId: string | null;
|
|
30
|
+
data: Array<import('types').ServerDataNode | null>;
|
|
31
|
+
errors: Record<string, any> | null;
|
|
30
32
|
}) => Promise<void>;
|
|
31
33
|
_start_router: () => void;
|
|
32
34
|
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { HttpError, Redirect } from '../../control.js';
|
|
2
|
+
import { normalize_error } from '../../../utils/error.js';
|
|
3
|
+
import { once } from '../../../utils/functions.js';
|
|
4
|
+
import { load_server_data } from '../page/load_data.js';
|
|
5
|
+
import { data_response, error_to_pojo } from '../utils.js';
|
|
6
|
+
import { normalize_path } from '../../../utils/url.js';
|
|
7
|
+
import { DATA_SUFFIX } from '../../../constants.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @param {import('types').RequestEvent} event
|
|
11
|
+
* @param {import('types').SSRRoute} route
|
|
12
|
+
* @param {import('types').SSROptions} options
|
|
13
|
+
* @param {import('types').SSRState} state
|
|
14
|
+
* @returns {Promise<Response>}
|
|
15
|
+
*/
|
|
16
|
+
export async function render_data(event, route, options, state) {
|
|
17
|
+
if (!route.page) {
|
|
18
|
+
// requesting /__data.js should fail for a +server.js
|
|
19
|
+
return new Response(undefined, {
|
|
20
|
+
status: 404
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const node_ids = [...route.page.layouts, route.page.leaf];
|
|
26
|
+
|
|
27
|
+
const invalidated =
|
|
28
|
+
event.url.searchParams
|
|
29
|
+
.get('__invalid')
|
|
30
|
+
?.split('')
|
|
31
|
+
.map((x) => x === 'y') ?? node_ids.map(() => true);
|
|
32
|
+
|
|
33
|
+
let aborted = false;
|
|
34
|
+
|
|
35
|
+
const url = new URL(event.url);
|
|
36
|
+
url.pathname = normalize_path(
|
|
37
|
+
url.pathname.slice(0, -DATA_SUFFIX.length),
|
|
38
|
+
options.trailing_slash
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
url.searchParams.delete('__invalid');
|
|
42
|
+
url.searchParams.delete('__id');
|
|
43
|
+
|
|
44
|
+
const new_event = { ...event, url };
|
|
45
|
+
|
|
46
|
+
const functions = node_ids.map((n, i) => {
|
|
47
|
+
return once(async () => {
|
|
48
|
+
try {
|
|
49
|
+
if (aborted) {
|
|
50
|
+
return /** @type {import('types').ServerDataSkippedNode} */ ({
|
|
51
|
+
type: 'skip'
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// == because it could be undefined (in dev) or null (in build, because of JSON.stringify)
|
|
56
|
+
const node = n == undefined ? n : await options.manifest._.nodes[n]();
|
|
57
|
+
return load_server_data({
|
|
58
|
+
event: new_event,
|
|
59
|
+
state,
|
|
60
|
+
node,
|
|
61
|
+
parent: async () => {
|
|
62
|
+
/** @type {Record<string, any>} */
|
|
63
|
+
const data = {};
|
|
64
|
+
for (let j = 0; j < i; j += 1) {
|
|
65
|
+
const parent = /** @type {import('types').ServerDataNode | null} */ (
|
|
66
|
+
await functions[j]()
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
if (parent) {
|
|
70
|
+
Object.assign(data, parent.data);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return data;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
} catch (e) {
|
|
77
|
+
aborted = true;
|
|
78
|
+
throw e;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const promises = functions.map(async (fn, i) => {
|
|
84
|
+
if (!invalidated[i]) {
|
|
85
|
+
return /** @type {import('types').ServerDataSkippedNode} */ ({
|
|
86
|
+
type: 'skip'
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return fn();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
let length = promises.length;
|
|
94
|
+
const nodes = await Promise.all(
|
|
95
|
+
promises.map((p, i) =>
|
|
96
|
+
p.catch((e) => {
|
|
97
|
+
const error = normalize_error(e);
|
|
98
|
+
|
|
99
|
+
if (error instanceof Redirect) {
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Math.min because array isn't guaranteed to resolve in order
|
|
104
|
+
length = Math.min(length, i + 1);
|
|
105
|
+
|
|
106
|
+
if (error instanceof HttpError) {
|
|
107
|
+
return /** @type {import('types').ServerErrorNode} */ ({
|
|
108
|
+
type: 'error',
|
|
109
|
+
httperror: { ...error }
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
options.handle_error(error, event);
|
|
114
|
+
|
|
115
|
+
return /** @type {import('types').ServerErrorNode} */ ({
|
|
116
|
+
type: 'error',
|
|
117
|
+
error: error_to_pojo(error, options.get_stack)
|
|
118
|
+
});
|
|
119
|
+
})
|
|
120
|
+
)
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
/** @type {import('types').ServerData} */
|
|
124
|
+
const server_data = {
|
|
125
|
+
type: 'data',
|
|
126
|
+
nodes: nodes.slice(0, length)
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
return data_response(server_data);
|
|
130
|
+
} catch (e) {
|
|
131
|
+
const error = normalize_error(e);
|
|
132
|
+
|
|
133
|
+
if (error instanceof Redirect) {
|
|
134
|
+
/** @type {import('types').ServerData} */
|
|
135
|
+
const server_data = {
|
|
136
|
+
type: 'redirect',
|
|
137
|
+
location: error.location
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
return data_response(server_data);
|
|
141
|
+
} else {
|
|
142
|
+
// TODO make it clearer that this was an unexpected error
|
|
143
|
+
return data_response(error_to_pojo(error, options.get_stack));
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|