@sveltejs/kit 1.0.0-next.430 → 1.0.0-next.433
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 +1 -2
- package/src/core/adapt/builder.js +28 -13
- package/src/core/generate_manifest/index.js +12 -33
- package/src/core/prerender/prerender.js +3 -2
- package/src/core/sync/create_manifest_data/index.js +273 -333
- package/src/core/sync/create_manifest_data/types.d.ts +1 -4
- package/src/core/sync/sync.js +3 -3
- package/src/core/sync/utils.js +0 -11
- package/src/core/sync/write_client_manifest.js +27 -13
- package/src/core/sync/write_root.js +1 -1
- package/src/core/sync/write_types.js +156 -384
- package/src/runtime/client/ambient.d.ts +4 -3
- package/src/runtime/client/client.js +208 -132
- package/src/runtime/client/parse.js +10 -5
- package/src/runtime/client/types.d.ts +10 -29
- package/src/runtime/server/endpoint.js +2 -10
- package/src/runtime/server/index.js +87 -44
- package/src/runtime/server/page/fetch.js +1 -1
- package/src/runtime/server/page/index.js +13 -25
- package/src/runtime/server/page/load_data.js +47 -10
- package/src/utils/array.js +9 -0
- package/src/utils/functions.js +16 -0
- package/src/utils/routing.js +30 -1
- package/src/vite/build/build_server.js +23 -12
- package/src/vite/dev/index.js +22 -30
- package/src/vite/index.js +7 -1
- package/src/vite/preview/index.js +1 -1
- package/types/index.d.ts +1 -1
- package/types/internal.d.ts +103 -41
|
@@ -7,11 +7,12 @@ declare module '__GENERATED__/client-manifest.js' {
|
|
|
7
7
|
export const nodes: CSRPageNodeLoader[];
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* A map of `[routeId: string]: [
|
|
10
|
+
* A map of `[routeId: string]: [leaf, layouts, errors]` tuples, which
|
|
11
11
|
* is parsed into an array of routes on startup. The numbers refer to the
|
|
12
|
-
* indices in `nodes`.
|
|
12
|
+
* indices in `nodes`. The route layout and error nodes are not referenced,
|
|
13
|
+
* they are always number 0 and 1 and always apply.
|
|
13
14
|
*/
|
|
14
|
-
export const dictionary: Record<string, [number
|
|
15
|
+
export const dictionary: Record<string, [leaf: number, layouts?: number[], errors?: number[]]>;
|
|
15
16
|
|
|
16
17
|
export const matchers: Record<string, ParamMatcher>;
|
|
17
18
|
}
|
|
@@ -16,10 +16,13 @@ const INDEX_KEY = 'sveltekit:index';
|
|
|
16
16
|
|
|
17
17
|
const routes = parse(nodes, dictionary, matchers);
|
|
18
18
|
|
|
19
|
+
const default_layout_loader = nodes[0];
|
|
20
|
+
const default_error_loader = nodes[1];
|
|
21
|
+
|
|
19
22
|
// we import the root layout/error nodes eagerly, so that
|
|
20
23
|
// connectivity errors after initialisation don't nuke the app
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
default_layout_loader();
|
|
25
|
+
default_error_loader();
|
|
23
26
|
|
|
24
27
|
// We track the scroll position associated with each history entry in sessionStorage,
|
|
25
28
|
// rather than on history.state itself, because when navigation is driven by
|
|
@@ -463,62 +466,57 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
463
466
|
* If `server_data` is passed, this is treated as the initial run and the page endpoint is not requested.
|
|
464
467
|
*
|
|
465
468
|
* @param {{
|
|
466
|
-
*
|
|
469
|
+
* loader: import('types').CSRPageNodeLoader;
|
|
467
470
|
* parent: () => Promise<Record<string, any>>;
|
|
468
471
|
* url: URL;
|
|
469
472
|
* params: Record<string, string>;
|
|
470
473
|
* routeId: string | null;
|
|
471
|
-
*
|
|
474
|
+
* server_data_node: import('./types').DataNode | null;
|
|
472
475
|
* }} options
|
|
473
476
|
* @returns {Promise<import('./types').BranchNode>}
|
|
474
477
|
*/
|
|
475
|
-
async function load_node({
|
|
478
|
+
async function load_node({ loader, parent, url, params, routeId, server_data_node }) {
|
|
479
|
+
/** @type {Record<string, any> | null} */
|
|
480
|
+
let data = null;
|
|
481
|
+
|
|
482
|
+
/** @type {import('types').Uses} */
|
|
476
483
|
const uses = {
|
|
477
|
-
params: new Set(),
|
|
478
|
-
url: false,
|
|
479
484
|
dependencies: new Set(),
|
|
480
|
-
|
|
485
|
+
params: new Set(),
|
|
486
|
+
parent: false,
|
|
487
|
+
url: false
|
|
481
488
|
};
|
|
482
489
|
|
|
483
|
-
|
|
484
|
-
function depends(...deps) {
|
|
485
|
-
for (const dep of deps) {
|
|
486
|
-
const { href } = new URL(dep, url);
|
|
487
|
-
uses.dependencies.add(href);
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
/** @type {Record<string, any> | null} */
|
|
492
|
-
let data = null;
|
|
490
|
+
const node = await loader();
|
|
493
491
|
|
|
494
|
-
if (node.
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
492
|
+
if (node.shared?.load) {
|
|
493
|
+
/** @param {string[]} deps */
|
|
494
|
+
function depends(...deps) {
|
|
495
|
+
for (const dep of deps) {
|
|
496
|
+
const { href } = new URL(dep, url);
|
|
497
|
+
uses.dependencies.add(href);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
501
500
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
501
|
+
/** @type {Record<string, string>} */
|
|
502
|
+
const uses_params = {};
|
|
503
|
+
for (const key in params) {
|
|
504
|
+
Object.defineProperty(uses_params, key, {
|
|
505
|
+
get() {
|
|
506
|
+
uses.params.add(key);
|
|
507
|
+
return params[key];
|
|
508
|
+
},
|
|
509
|
+
enumerable: true
|
|
510
|
+
});
|
|
511
|
+
}
|
|
513
512
|
|
|
514
|
-
|
|
513
|
+
const load_url = new LoadURL(url);
|
|
515
514
|
|
|
516
|
-
if (node.shared?.load) {
|
|
517
515
|
/** @type {import('types').LoadEvent} */
|
|
518
516
|
const load_input = {
|
|
519
517
|
routeId,
|
|
520
518
|
params: uses_params,
|
|
521
|
-
data:
|
|
519
|
+
data: server_data_node?.data ?? null,
|
|
522
520
|
get url() {
|
|
523
521
|
uses.url = true;
|
|
524
522
|
return load_url;
|
|
@@ -564,11 +562,9 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
564
562
|
},
|
|
565
563
|
setHeaders: () => {}, // noop
|
|
566
564
|
depends,
|
|
567
|
-
|
|
568
|
-
// uses.parent assignment here, not on method inokation, else we wouldn't notice when someone
|
|
569
|
-
// does await parent() inside an if branch which wasn't executed yet.
|
|
565
|
+
parent() {
|
|
570
566
|
uses.parent = true;
|
|
571
|
-
return parent;
|
|
567
|
+
return parent();
|
|
572
568
|
}
|
|
573
569
|
};
|
|
574
570
|
|
|
@@ -614,11 +610,55 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
614
610
|
|
|
615
611
|
return {
|
|
616
612
|
node,
|
|
617
|
-
|
|
618
|
-
|
|
613
|
+
loader,
|
|
614
|
+
server: server_data_node,
|
|
615
|
+
shared: node.shared?.load ? { type: 'data', data, uses } : null,
|
|
616
|
+
data: data ?? server_data_node?.data ?? null
|
|
619
617
|
};
|
|
620
618
|
}
|
|
621
619
|
|
|
620
|
+
/**
|
|
621
|
+
* @param {import('types').Uses | undefined} uses
|
|
622
|
+
* @param {boolean} parent_changed
|
|
623
|
+
* @param {{ url: boolean, params: string[] }} changed
|
|
624
|
+
*/
|
|
625
|
+
function has_changed(changed, parent_changed, uses) {
|
|
626
|
+
if (!uses) return false;
|
|
627
|
+
|
|
628
|
+
if (uses.parent && parent_changed) return true;
|
|
629
|
+
if (changed.url && uses.url) return true;
|
|
630
|
+
|
|
631
|
+
for (const param of changed.params) {
|
|
632
|
+
if (uses.params.has(param)) return true;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
for (const dep of uses.dependencies) {
|
|
636
|
+
if (invalidated.some((fn) => fn(dep))) return true;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
return false;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* @param {import('types').ServerDataNode | import('types').ServerDataSkippedNode | null} node
|
|
644
|
+
* @returns {import('./types').DataNode | null}
|
|
645
|
+
*/
|
|
646
|
+
function create_data_node(node) {
|
|
647
|
+
if (node?.type === 'data') {
|
|
648
|
+
return {
|
|
649
|
+
type: 'data',
|
|
650
|
+
data: node.data,
|
|
651
|
+
uses: {
|
|
652
|
+
dependencies: new Set(node.uses.dependencies ?? []),
|
|
653
|
+
params: new Set(node.uses.params ?? []),
|
|
654
|
+
parent: !!node.uses.parent,
|
|
655
|
+
url: !!node.uses.url
|
|
656
|
+
}
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
|
|
622
662
|
/**
|
|
623
663
|
* @param {import('./types').NavigationIntent} intent
|
|
624
664
|
* @returns {Promise<import('./types').NavigationResult | undefined>}
|
|
@@ -640,89 +680,95 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
640
680
|
// to act on the failures at this point)
|
|
641
681
|
[...errors, ...layouts, leaf].forEach((loader) => loader?.().catch(() => {}));
|
|
642
682
|
|
|
643
|
-
const
|
|
683
|
+
const loaders = [...layouts, leaf];
|
|
644
684
|
|
|
645
685
|
// To avoid waterfalls when someone awaits a parent, compute as much as possible here already
|
|
646
|
-
/** @type {boolean[]} */
|
|
647
|
-
const nodes_changed_since_last_render = [];
|
|
648
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
649
|
-
if (!nodes[i]) {
|
|
650
|
-
nodes_changed_since_last_render.push(false);
|
|
651
|
-
} else {
|
|
652
|
-
const previous = current.branch[i];
|
|
653
|
-
const changed_since_last_render =
|
|
654
|
-
!previous ||
|
|
655
|
-
(changed.url && previous.uses.url) ||
|
|
656
|
-
changed.params.some((param) => previous.uses.params.has(param)) ||
|
|
657
|
-
Array.from(previous.uses.dependencies).some((dep) => invalidated.some((fn) => fn(dep))) ||
|
|
658
|
-
(previous.uses.parent && nodes_changed_since_last_render.includes(true));
|
|
659
|
-
nodes_changed_since_last_render.push(changed_since_last_render);
|
|
660
|
-
}
|
|
661
|
-
}
|
|
662
686
|
|
|
663
|
-
/** @type {import('
|
|
664
|
-
let
|
|
687
|
+
/** @type {import('types').ServerData | null} */
|
|
688
|
+
let server_data = null;
|
|
665
689
|
|
|
666
|
-
|
|
690
|
+
const invalid_server_nodes = loaders.reduce((acc, loader, i) => {
|
|
691
|
+
const previous = current.branch[i];
|
|
692
|
+
const invalid =
|
|
693
|
+
loader &&
|
|
694
|
+
(previous?.loader !== loader ||
|
|
695
|
+
has_changed(changed, acc.some(Boolean), previous.server?.uses));
|
|
696
|
+
|
|
697
|
+
acc.push(invalid);
|
|
698
|
+
return acc;
|
|
699
|
+
}, /** @type {boolean[]} */ ([]));
|
|
700
|
+
|
|
701
|
+
if (route.uses_server_data && invalid_server_nodes.some(Boolean)) {
|
|
667
702
|
try {
|
|
668
703
|
const res = await native_fetch(
|
|
669
|
-
`${url.pathname}${url.pathname.endsWith('/') ? '' : '/'}__data.json${url.search}
|
|
704
|
+
`${url.pathname}${url.pathname.endsWith('/') ? '' : '/'}__data.json${url.search}`,
|
|
705
|
+
{
|
|
706
|
+
headers: {
|
|
707
|
+
'x-sveltekit-invalidated': invalid_server_nodes.map((x) => (x ? '1' : '')).join(',')
|
|
708
|
+
}
|
|
709
|
+
}
|
|
670
710
|
);
|
|
671
711
|
|
|
672
|
-
|
|
712
|
+
server_data = /** @type {import('types').ServerData} */ (await res.json());
|
|
673
713
|
|
|
674
714
|
if (!res.ok) {
|
|
675
|
-
throw
|
|
715
|
+
throw server_data;
|
|
676
716
|
}
|
|
677
717
|
} catch (e) {
|
|
678
|
-
|
|
718
|
+
// something went catastrophically wrong — bail and defer to the server
|
|
719
|
+
native_navigation(url);
|
|
720
|
+
return;
|
|
679
721
|
}
|
|
680
722
|
|
|
681
|
-
if (
|
|
682
|
-
return
|
|
723
|
+
if (server_data.type === 'redirect') {
|
|
724
|
+
return server_data;
|
|
683
725
|
}
|
|
684
726
|
}
|
|
685
727
|
|
|
686
|
-
const server_data_nodes =
|
|
728
|
+
const server_data_nodes = server_data?.nodes;
|
|
687
729
|
|
|
688
|
-
|
|
689
|
-
return Promise.resolve().then(async () => {
|
|
690
|
-
if (!loader) return;
|
|
691
|
-
const node = await loader();
|
|
730
|
+
let parent_changed = false;
|
|
692
731
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
const changed_since_last_render =
|
|
696
|
-
nodes_changed_since_last_render[i] || !previous || node !== previous.node;
|
|
732
|
+
const branch_promises = loaders.map(async (loader, i) => {
|
|
733
|
+
if (!loader) return;
|
|
697
734
|
|
|
698
|
-
|
|
699
|
-
|
|
735
|
+
/** @type {import('./types').BranchNode | undefined} */
|
|
736
|
+
const previous = current.branch[i];
|
|
700
737
|
|
|
701
|
-
|
|
702
|
-
throw error(payload.status, payload.message);
|
|
703
|
-
}
|
|
738
|
+
const server_data_node = server_data_nodes?.[i] ?? null;
|
|
704
739
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
740
|
+
const can_reuse_server_data = !server_data_node || server_data_node.type === 'skip';
|
|
741
|
+
// re-use data from previous load if it's still valid
|
|
742
|
+
const valid =
|
|
743
|
+
can_reuse_server_data &&
|
|
744
|
+
loader === previous?.loader &&
|
|
745
|
+
!has_changed(changed, parent_changed, previous.shared?.uses);
|
|
746
|
+
if (valid) return previous;
|
|
708
747
|
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
const data = {};
|
|
716
|
-
for (let j = 0; j < i; j += 1) {
|
|
717
|
-
Object.assign(data, (await branch_promises[j])?.data);
|
|
718
|
-
}
|
|
719
|
-
return data;
|
|
720
|
-
},
|
|
721
|
-
server_data: payload?.data ?? null
|
|
722
|
-
});
|
|
748
|
+
parent_changed = true;
|
|
749
|
+
|
|
750
|
+
if (server_data_node?.type === 'error') {
|
|
751
|
+
if (server_data_node.httperror) {
|
|
752
|
+
// reconstruct as an HttpError
|
|
753
|
+
throw error(server_data_node.httperror.status, server_data_node.httperror.message);
|
|
723
754
|
} else {
|
|
724
|
-
|
|
755
|
+
throw server_data_node.error;
|
|
725
756
|
}
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
return load_node({
|
|
760
|
+
loader,
|
|
761
|
+
url,
|
|
762
|
+
params,
|
|
763
|
+
routeId: route.id,
|
|
764
|
+
parent: async () => {
|
|
765
|
+
const data = {};
|
|
766
|
+
for (let j = 0; j < i; j += 1) {
|
|
767
|
+
Object.assign(data, (await branch_promises[j])?.data);
|
|
768
|
+
}
|
|
769
|
+
return data;
|
|
770
|
+
},
|
|
771
|
+
server_data_node: create_data_node(server_data_node) ?? previous?.server ?? null
|
|
726
772
|
});
|
|
727
773
|
});
|
|
728
774
|
|
|
@@ -732,8 +778,8 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
732
778
|
/** @type {Array<import('./types').BranchNode | undefined>} */
|
|
733
779
|
const branch = [];
|
|
734
780
|
|
|
735
|
-
for (let i = 0; i <
|
|
736
|
-
if (
|
|
781
|
+
for (let i = 0; i < loaders.length; i += 1) {
|
|
782
|
+
if (loaders[i]) {
|
|
737
783
|
try {
|
|
738
784
|
branch.push(await branch_promises[i]);
|
|
739
785
|
} catch (e) {
|
|
@@ -759,13 +805,10 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
759
805
|
try {
|
|
760
806
|
error_loaded = {
|
|
761
807
|
node: await errors[i](),
|
|
808
|
+
loader: errors[i],
|
|
762
809
|
data: {},
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
url: false,
|
|
766
|
-
dependencies: new Set(),
|
|
767
|
-
parent: false
|
|
768
|
-
}
|
|
810
|
+
server: null,
|
|
811
|
+
shared: null
|
|
769
812
|
};
|
|
770
813
|
|
|
771
814
|
return await get_navigation_result_from_branch({
|
|
@@ -782,12 +825,10 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
782
825
|
}
|
|
783
826
|
}
|
|
784
827
|
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
routeId: route.id
|
|
790
|
-
});
|
|
828
|
+
// if we get here, it's because the root `load` function failed,
|
|
829
|
+
// and we need to fall back to the server
|
|
830
|
+
native_navigation(url);
|
|
831
|
+
return;
|
|
791
832
|
}
|
|
792
833
|
} else {
|
|
793
834
|
// push an empty slot so we can rewind past gaps to the
|
|
@@ -813,30 +854,57 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
813
854
|
* url: URL;
|
|
814
855
|
* routeId: string | null
|
|
815
856
|
* }} opts
|
|
857
|
+
* @returns {Promise<import('./types').NavigationFinished>}
|
|
816
858
|
*/
|
|
817
859
|
async function load_root_error_page({ status, error, url, routeId }) {
|
|
818
860
|
/** @type {Record<string, string>} */
|
|
819
861
|
const params = {}; // error page does not have params
|
|
820
862
|
|
|
863
|
+
const node = await default_layout_loader();
|
|
864
|
+
|
|
865
|
+
/** @type {import('types').ServerDataNode | null} */
|
|
866
|
+
let server_data_node = null;
|
|
867
|
+
|
|
868
|
+
if (node.server) {
|
|
869
|
+
// TODO post-https://github.com/sveltejs/kit/discussions/6124 we can use
|
|
870
|
+
// existing root layout data
|
|
871
|
+
const res = await native_fetch(
|
|
872
|
+
`${url.pathname}${url.pathname.endsWith('/') ? '' : '/'}__data.json${url.search}`,
|
|
873
|
+
{
|
|
874
|
+
headers: {
|
|
875
|
+
'x-sveltekit-invalidated': '1'
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
);
|
|
879
|
+
|
|
880
|
+
const server_data_nodes = await res.json();
|
|
881
|
+
server_data_node = server_data_nodes?.[0] ?? null;
|
|
882
|
+
|
|
883
|
+
if (!res.ok || server_data_nodes?.type !== 'data') {
|
|
884
|
+
// at this point we have no choice but to fall back to the server
|
|
885
|
+
native_navigation(url);
|
|
886
|
+
|
|
887
|
+
// @ts-expect-error
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
|
|
821
892
|
const root_layout = await load_node({
|
|
822
|
-
|
|
893
|
+
loader: default_layout_loader,
|
|
823
894
|
url,
|
|
824
895
|
params,
|
|
825
896
|
routeId,
|
|
826
897
|
parent: () => Promise.resolve({}),
|
|
827
|
-
|
|
898
|
+
server_data_node: create_data_node(server_data_node)
|
|
828
899
|
});
|
|
829
900
|
|
|
901
|
+
/** @type {import('./types').BranchNode} */
|
|
830
902
|
const root_error = {
|
|
831
|
-
node: await
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
url: false,
|
|
837
|
-
dependencies: new Set(),
|
|
838
|
-
parent: false
|
|
839
|
-
}
|
|
903
|
+
node: await default_error_loader(),
|
|
904
|
+
loader: default_error_loader,
|
|
905
|
+
shared: null,
|
|
906
|
+
server: null,
|
|
907
|
+
data: null
|
|
840
908
|
};
|
|
841
909
|
|
|
842
910
|
return await get_navigation_result_from_branch({
|
|
@@ -985,7 +1053,8 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
985
1053
|
if (resource === undefined) {
|
|
986
1054
|
// Force rerun of all load functions, regardless of their dependencies
|
|
987
1055
|
for (const node of current.branch) {
|
|
988
|
-
node?.uses.dependencies.add('');
|
|
1056
|
+
node?.server?.uses.dependencies.add('');
|
|
1057
|
+
node?.shared?.uses.dependencies.add('');
|
|
989
1058
|
}
|
|
990
1059
|
invalidated.push(() => true);
|
|
991
1060
|
} else if (typeof resource === 'function') {
|
|
@@ -1230,12 +1299,19 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1230
1299
|
const script = document.querySelector(`script[sveltekit\\:data-type="${type}"]`);
|
|
1231
1300
|
return script?.textContent ? JSON.parse(script.textContent) : fallback;
|
|
1232
1301
|
};
|
|
1233
|
-
|
|
1302
|
+
/**
|
|
1303
|
+
* @type {Array<import('types').ServerDataNode | null>}
|
|
1304
|
+
* On initial navigation, this will only consist of data nodes or `null`.
|
|
1305
|
+
* A possible error is passed through the `error` property, in which case
|
|
1306
|
+
* the last entry of `node_ids` is an error page and the last entry of
|
|
1307
|
+
* `server_data_nodes` is `null`.
|
|
1308
|
+
*/
|
|
1309
|
+
const server_data_nodes = parse('server_data', []);
|
|
1234
1310
|
const validation_errors = parse('validation_errors', undefined);
|
|
1235
1311
|
|
|
1236
1312
|
const branch_promises = node_ids.map(async (n, i) => {
|
|
1237
1313
|
return load_node({
|
|
1238
|
-
|
|
1314
|
+
loader: nodes[n],
|
|
1239
1315
|
url,
|
|
1240
1316
|
params,
|
|
1241
1317
|
routeId,
|
|
@@ -1246,7 +1322,7 @@ export function create_client({ target, base, trailing_slash }) {
|
|
|
1246
1322
|
}
|
|
1247
1323
|
return data;
|
|
1248
1324
|
},
|
|
1249
|
-
|
|
1325
|
+
server_data_node: create_data_node(server_data_nodes[i])
|
|
1250
1326
|
});
|
|
1251
1327
|
});
|
|
1252
1328
|
|
|
@@ -2,14 +2,19 @@ import { exec, parse_route_id } from '../../utils/routing.js';
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @param {import('types').CSRPageNodeLoader[]} nodes
|
|
5
|
-
* @param {
|
|
5
|
+
* @param {typeof import('__GENERATED__/client-manifest.js').dictionary} dictionary
|
|
6
6
|
* @param {Record<string, (param: string) => boolean>} matchers
|
|
7
7
|
* @returns {import('types').CSRRoute[]}
|
|
8
8
|
*/
|
|
9
9
|
export function parse(nodes, dictionary, matchers) {
|
|
10
|
-
return Object.entries(dictionary).map(([id, [
|
|
10
|
+
return Object.entries(dictionary).map(([id, [leaf, layouts, errors]]) => {
|
|
11
11
|
const { pattern, names, types } = parse_route_id(id);
|
|
12
12
|
|
|
13
|
+
// whether or not the route uses the server data is
|
|
14
|
+
// encoded using the ones' complement, to save space
|
|
15
|
+
const uses_server_data = leaf < 0;
|
|
16
|
+
if (uses_server_data) leaf = ~leaf;
|
|
17
|
+
|
|
13
18
|
const route = {
|
|
14
19
|
id,
|
|
15
20
|
/** @param {string} path */
|
|
@@ -17,10 +22,10 @@ export function parse(nodes, dictionary, matchers) {
|
|
|
17
22
|
const match = pattern.exec(path);
|
|
18
23
|
if (match) return exec(match, names, types, matchers);
|
|
19
24
|
},
|
|
20
|
-
errors: errors.map((n) => nodes[n]),
|
|
21
|
-
layouts: layouts.map((n) => nodes[n]),
|
|
25
|
+
errors: [1, ...(errors || [])].map((n) => nodes[n]),
|
|
26
|
+
layouts: [0, ...(layouts || [])].map((n) => nodes[n]),
|
|
22
27
|
leaf: nodes[leaf],
|
|
23
|
-
uses_server_data
|
|
28
|
+
uses_server_data
|
|
24
29
|
};
|
|
25
30
|
|
|
26
31
|
// bit of a hack, but ensures that layout/error node lists are the same
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
prefetch,
|
|
7
7
|
prefetchRoutes
|
|
8
8
|
} from '$app/navigation';
|
|
9
|
-
import { CSRPageNode, CSRRoute } from 'types';
|
|
9
|
+
import { CSRPageNode, CSRPageNodeLoader, CSRRoute, ServerErrorNode, Uses } from 'types';
|
|
10
10
|
import { HttpError } from '../../index/private.js';
|
|
11
11
|
import { SerializedHttpError } from '../server/page/types.js';
|
|
12
12
|
|
|
@@ -65,15 +65,18 @@ export type NavigationFinished = {
|
|
|
65
65
|
|
|
66
66
|
export type BranchNode = {
|
|
67
67
|
node: CSRPageNode;
|
|
68
|
+
loader: CSRPageNodeLoader;
|
|
69
|
+
server: DataNode | null;
|
|
70
|
+
shared: DataNode | null;
|
|
68
71
|
data: Record<string, any> | null;
|
|
69
|
-
uses: {
|
|
70
|
-
params: Set<string>;
|
|
71
|
-
url: boolean; // TODO make more granular?
|
|
72
|
-
dependencies: Set<string>;
|
|
73
|
-
parent: boolean;
|
|
74
|
-
};
|
|
75
72
|
};
|
|
76
73
|
|
|
74
|
+
export interface DataNode {
|
|
75
|
+
type: 'data';
|
|
76
|
+
data: Record<string, any> | null;
|
|
77
|
+
uses: Uses;
|
|
78
|
+
}
|
|
79
|
+
|
|
77
80
|
export type NavigationState = {
|
|
78
81
|
branch: Array<BranchNode | undefined>;
|
|
79
82
|
error: HttpError | Error | null;
|
|
@@ -81,25 +84,3 @@ export type NavigationState = {
|
|
|
81
84
|
session_id: number;
|
|
82
85
|
url: URL;
|
|
83
86
|
};
|
|
84
|
-
|
|
85
|
-
export type ServerDataPayload = ServerDataRedirected | ServerDataLoaded;
|
|
86
|
-
|
|
87
|
-
export interface ServerDataRedirected {
|
|
88
|
-
type: 'redirect';
|
|
89
|
-
location: string;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
export interface ServerDataLoaded {
|
|
93
|
-
type: 'data';
|
|
94
|
-
nodes: Array<{
|
|
95
|
-
data?: Record<string, any> | null; // TODO or `-1` to indicate 'reuse cached data'?
|
|
96
|
-
status?: number;
|
|
97
|
-
message?: string;
|
|
98
|
-
error?: {
|
|
99
|
-
name: string;
|
|
100
|
-
message: string;
|
|
101
|
-
stack: string;
|
|
102
|
-
[key: string]: any;
|
|
103
|
-
};
|
|
104
|
-
}>;
|
|
105
|
-
}
|
|
@@ -3,14 +3,12 @@ import { check_method_names, method_not_allowed } from './utils.js';
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @param {import('types').RequestEvent} event
|
|
6
|
-
* @param {import('types').SSREndpoint}
|
|
6
|
+
* @param {import('types').SSREndpoint} mod
|
|
7
7
|
* @returns {Promise<Response>}
|
|
8
8
|
*/
|
|
9
|
-
export async function render_endpoint(event,
|
|
9
|
+
export async function render_endpoint(event, mod) {
|
|
10
10
|
const method = /** @type {import('types').HttpMethod} */ (event.request.method);
|
|
11
11
|
|
|
12
|
-
const mod = await route.load();
|
|
13
|
-
|
|
14
12
|
// TODO: Remove for 1.0
|
|
15
13
|
check_method_names(mod);
|
|
16
14
|
|
|
@@ -21,12 +19,6 @@ export async function render_endpoint(event, route) {
|
|
|
21
19
|
}
|
|
22
20
|
|
|
23
21
|
if (!handler) {
|
|
24
|
-
if (event.request.headers.get('x-sveltekit-load')) {
|
|
25
|
-
// TODO would be nice to avoid these requests altogether,
|
|
26
|
-
// by noting whether or not page endpoints export `get`
|
|
27
|
-
return new Response(undefined, { status: 204 });
|
|
28
|
-
}
|
|
29
|
-
|
|
30
22
|
return method_not_allowed(mod, method);
|
|
31
23
|
}
|
|
32
24
|
|