@sveltejs/kit 1.0.0-next.441 → 1.0.0-next.444

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.
Files changed (35) hide show
  1. package/package.json +6 -6
  2. package/src/core/prerender/prerender.js +1 -1
  3. package/src/core/sync/write_ambient.js +1 -1
  4. package/src/core/sync/write_client_manifest.js +18 -13
  5. package/src/core/sync/write_root.js +1 -1
  6. package/src/core/sync/write_types/index.js +28 -9
  7. package/src/core/sync/write_types/test/layout-advanced/_expected/(main)/sub/$types.d.ts +5 -4
  8. package/src/core/sync/write_types/test/slugs-layout-not-all-pages-have-load/_expected/nested/[...rest]/$types.d.ts +5 -4
  9. package/src/exports/hooks/index.js +1 -0
  10. package/src/{hooks.js → exports/hooks/sequence.js} +0 -0
  11. package/src/{index → exports}/index.js +1 -1
  12. package/src/{node → exports/node}/index.js +0 -0
  13. package/src/{node → exports/node}/polyfills.js +0 -0
  14. package/src/{vite → exports/vite}/build/build_server.js +4 -4
  15. package/src/{vite → exports/vite}/build/build_service_worker.js +1 -1
  16. package/src/{vite → exports/vite}/build/utils.js +0 -0
  17. package/src/{vite → exports/vite}/dev/index.js +9 -9
  18. package/src/{vite → exports/vite}/index.js +8 -8
  19. package/src/{vite → exports/vite}/preview/index.js +3 -3
  20. package/src/{vite → exports/vite}/types.d.ts +0 -0
  21. package/src/{vite → exports/vite}/utils.js +2 -2
  22. package/src/runtime/client/ambient.d.ts +3 -3
  23. package/src/runtime/client/client.js +40 -23
  24. package/src/runtime/client/parse.js +14 -8
  25. package/src/runtime/client/types.d.ts +2 -2
  26. package/src/{index/private.js → runtime/control.js} +0 -0
  27. package/src/runtime/server/endpoint.js +1 -1
  28. package/src/runtime/server/index.js +7 -4
  29. package/src/runtime/server/page/index.js +2 -2
  30. package/src/runtime/server/page/render.js +1 -1
  31. package/src/runtime/server/page/types.d.ts +1 -1
  32. package/src/runtime/server/utils.js +1 -1
  33. package/src/utils/error.js +1 -1
  34. package/types/index.d.ts +1 -1
  35. package/types/internal.d.ts +10 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "1.0.0-next.441",
3
+ "version": "1.0.0-next.444",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/sveltejs/kit",
@@ -60,20 +60,20 @@
60
60
  "exports": {
61
61
  "./package.json": "./package.json",
62
62
  ".": {
63
- "import": "./src/index/index.js",
63
+ "import": "./src/exports/index.js",
64
64
  "types": "./types/index.d.ts"
65
65
  },
66
66
  "./node": {
67
- "import": "./src/node/index.js"
67
+ "import": "./src/exports/node/index.js"
68
68
  },
69
69
  "./node/polyfills": {
70
- "import": "./src/node/polyfills.js"
70
+ "import": "./src/exports/node/polyfills.js"
71
71
  },
72
72
  "./hooks": {
73
- "import": "./src/hooks.js"
73
+ "import": "./src/exports/hooks/index.js"
74
74
  },
75
75
  "./vite": {
76
- "import": "./src/vite/index.js"
76
+ "import": "./src/exports/vite/index.js"
77
77
  }
78
78
  },
79
79
  "types": "types/index.d.ts",
@@ -2,7 +2,7 @@ import { readFileSync, writeFileSync } from 'fs';
2
2
  import { dirname, join } from 'path';
3
3
  import { pathToFileURL, URL } from 'url';
4
4
  import { mkdirp, posixify, walk } from '../../utils/filesystem.js';
5
- import { installPolyfills } from '../../node/polyfills.js';
5
+ import { installPolyfills } from '../../exports/node/polyfills.js';
6
6
  import { is_root_relative, resolve } from '../../utils/url.js';
7
7
  import { queue } from './queue.js';
8
8
  import { crawl } from './crawl.js';
@@ -1,5 +1,5 @@
1
1
  import path from 'path';
2
- import { get_env } from '../../vite/utils.js';
2
+ import { get_env } from '../../exports/vite/utils.js';
3
3
  import { GENERATED_COMMENT } from '../constants.js';
4
4
  import { create_types } from '../env.js';
5
5
  import { write_if_changed } from './utils.js';
@@ -48,23 +48,17 @@ export function write_client_manifest(manifest_data, output) {
48
48
  .map((route) => {
49
49
  if (route.page) {
50
50
  const errors = route.page.errors.slice(1).map((n) => n ?? '');
51
- const layouts = route.page.layouts.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
+ });
52
57
 
53
58
  while (layouts.at(-1) === '') layouts.pop();
54
59
  while (errors.at(-1) === '') errors.pop();
55
60
 
56
- /** @type {import('types').PageNode | null} */
57
- let current_node = route.leaf;
58
-
59
- let uses_server_data = false;
60
- while (current_node && !uses_server_data) {
61
- uses_server_data = !!current_node?.server;
62
- current_node = current_node?.parent ?? null;
63
- }
64
-
65
- // encode whether or not the route uses the server data
66
- // using the ones' complement, to save space
67
- const array = [`${uses_server_data ? '~' : ''}${route.page.leaf}`];
61
+ const array = [get_node_id(manifest_data.nodes, route.page.leaf)];
68
62
 
69
63
  // only include non-root layout/error nodes if they exist
70
64
  if (layouts.length > 0 || errors.length > 0) array.push(`[${layouts.join(',')}]`);
@@ -77,6 +71,7 @@ export function write_client_manifest(manifest_data, output) {
77
71
  .join(',\n\t\t')}
78
72
  }`.replace(/^\t/gm, '');
79
73
 
74
+ // String representation of __GENERATED__/client-manifest.js
80
75
  write_if_changed(
81
76
  `${output}/client-manifest.js`,
82
77
  trim(`
@@ -90,3 +85,13 @@ export function write_client_manifest(manifest_data, output) {
90
85
  `)
91
86
  );
92
87
  }
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
+ }
@@ -21,7 +21,7 @@ export function write_root(manifest_data, output) {
21
21
 
22
22
  let l = max_depth;
23
23
 
24
- let pyramid = `<svelte:component this={components[${l}]} data={data_${l}}/>`;
24
+ let pyramid = `<svelte:component this={components[${l}]} data={data_${l}} {errors}/>`;
25
25
 
26
26
  while (l--) {
27
27
  pyramid = `
@@ -167,15 +167,20 @@ function update_types(config, routes, route) {
167
167
  `type RouteParams = { ${route.names.map((param) => `${param}: string`).join('; ')} }`
168
168
  );
169
169
 
170
+ // These could also be placed in our public types, but it would bloat them unnecessarily and we may want to change these in the future
170
171
  if (route.layout || route.leaf) {
171
- // These could also be placed in our public types, but it would bloat them unnecessarily and we may want to change these in the future
172
+ // If T extends the empty object, void is also allowed as a return type
172
173
  declarations.push(`type MaybeWithVoid<T> = {} extends T ? T | void : T;`);
174
+ // Returns the key of the object whose values are required.
173
175
  declarations.push(
174
176
  `export type RequiredKeys<T> = { [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K; }[keyof T];`
175
177
  );
178
+ // Helper type to get the correct output type for load functions. It should be passed the parent type to check what types from App.PageData are still required.
179
+ // If none, void is also allowed as a return type.
176
180
  declarations.push(
177
181
  `type OutputDataShape<T> = MaybeWithVoid<Omit<App.PageData, RequiredKeys<T>> & Partial<Pick<App.PageData, keyof T & keyof App.PageData>> & Record<string, any>>`
178
182
  );
183
+ // null & {} == null, we need to prevent that in some situations
179
184
  declarations.push(`type EnsureParentData<T> = NonNullable<T> extends never ? {} : T;`);
180
185
  }
181
186
 
@@ -277,9 +282,7 @@ function process_node(node, outdir, is_page, all_pages_have_load = true) {
277
282
 
278
283
  const parent_type = `${prefix}ServerParentData`;
279
284
 
280
- declarations.push(
281
- `type ${parent_type} = EnsureParentData<${get_parent_type(node, 'LayoutServerData')}>;`
282
- );
285
+ declarations.push(`type ${parent_type} = ${get_parent_type(node, 'LayoutServerData')};`);
283
286
 
284
287
  // +page.js load present -> server can return all-optional data
285
288
  const output_data_shape =
@@ -317,9 +320,7 @@ function process_node(node, outdir, is_page, all_pages_have_load = true) {
317
320
  exports.push(`export type ${prefix}ServerData = ${server_data};`);
318
321
 
319
322
  const parent_type = `${prefix}ParentData`;
320
- declarations.push(
321
- `type ${parent_type} = EnsureParentData<${get_parent_type(node, 'LayoutData')}>;`
322
- );
323
+ declarations.push(`type ${parent_type} = ${get_parent_type(node, 'LayoutData')};`);
323
324
 
324
325
  if (node.shared) {
325
326
  const content = fs.readFileSync(node.shared, 'utf8');
@@ -394,12 +395,14 @@ function get_parent_type(node, type) {
394
395
  parent = parent.parent;
395
396
  }
396
397
 
397
- let parent_str = parent_imports[0] || '{}';
398
+ let parent_str = `EnsureParentData<${parent_imports[0] || '{}'}>`;
398
399
  for (let i = 1; i < parent_imports.length; i++) {
399
400
  // Omit is necessary because a parent could have a property with the same key which would
400
401
  // cause a type conflict. At runtime the child overwrites the parent property in this case,
401
402
  // so reflect that in the type definition.
402
- parent_str = `Omit<${parent_str}, keyof ${parent_imports[i]}> & ${parent_imports[i]}`;
403
+ // EnsureParentData is necessary because {something: string} & null becomes null.
404
+ // Output types of server loads can be null but when passed in through the `parent` parameter they are the empty object instead.
405
+ parent_str = `Omit<${parent_str}, keyof ${parent_imports[i]}> & EnsureParentData<${parent_imports[i]}>`;
403
406
  }
404
407
  return parent_str;
405
408
  }
@@ -556,7 +559,13 @@ export function tweak_types(content, names) {
556
559
  arg.name.end,
557
560
  `: Parameters<${type}>[0]` + (add_parens ? ')' : '')
558
561
  );
562
+ } else {
563
+ // prevent "type X is imported but not used" (isn't silenced by @ts-nocheck) when svelte-check runs
564
+ code.append(`;${type};`);
559
565
  }
566
+ } else {
567
+ // prevent "type X is imported but not used" (isn't silenced by @ts-nocheck) when svelte-check runs
568
+ code.append(`;${type};`);
560
569
  }
561
570
 
562
571
  modified = true;
@@ -566,6 +575,16 @@ export function tweak_types(content, names) {
566
575
  }
567
576
  });
568
577
 
578
+ if (modified) {
579
+ // Ignore all type errors so they don't show up twice when svelte-check runs
580
+ // Account for possible @ts-check which would overwrite @ts-nocheck
581
+ if (code.original.startsWith('// @ts-check')) {
582
+ code.prependLeft('// @ts-check'.length, '\n// @ts-nocheck\n');
583
+ } else {
584
+ code.prepend('// @ts-nocheck\n');
585
+ }
586
+ }
587
+
569
588
  return {
570
589
  modified,
571
590
  code: code.toString(),
@@ -11,10 +11,11 @@ type OutputDataShape<T> = MaybeWithVoid<
11
11
  Record<string, any>
12
12
  >;
13
13
  type EnsureParentData<T> = NonNullable<T> extends never ? {} : T;
14
- type PageParentData = EnsureParentData<
15
- Omit<import('../../$types.js').LayoutData, keyof import('../$types.js').LayoutData> &
16
- import('../$types.js').LayoutData
17
- >;
14
+ type PageParentData = Omit<
15
+ EnsureParentData<import('../../$types.js').LayoutData>,
16
+ keyof import('../$types.js').LayoutData
17
+ > &
18
+ EnsureParentData<import('../$types.js').LayoutData>;
18
19
 
19
20
  export type PageServerData = null;
20
21
  export type PageLoad<
@@ -11,10 +11,11 @@ type OutputDataShape<T> = MaybeWithVoid<
11
11
  Record<string, any>
12
12
  >;
13
13
  type EnsureParentData<T> = NonNullable<T> extends never ? {} : T;
14
- type PageParentData = EnsureParentData<
15
- Omit<import('../../$types.js').LayoutData, keyof import('../$types.js').LayoutData> &
16
- import('../$types.js').LayoutData
17
- >;
14
+ type PageParentData = Omit<
15
+ EnsureParentData<import('../../$types.js').LayoutData>,
16
+ keyof import('../$types.js').LayoutData
17
+ > &
18
+ EnsureParentData<import('../$types.js').LayoutData>;
18
19
 
19
20
  export type PageServerData = null;
20
21
  export type PageLoad<
@@ -0,0 +1 @@
1
+ export { sequence } from './sequence.js';
File without changes
@@ -1,4 +1,4 @@
1
- import { HttpError, Redirect } from './private.js';
1
+ import { HttpError, Redirect } from '../runtime/control.js';
2
2
 
3
3
  /**
4
4
  * Creates an `HttpError` object with an HTTP status code and an optional message.
File without changes
File without changes
@@ -1,11 +1,11 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
- import { mkdirp, posixify } from '../../utils/filesystem.js';
3
+ import { mkdirp, posixify } from '../../../utils/filesystem.js';
4
4
  import { get_vite_config, merge_vite_configs, resolve_entry } from '../utils.js';
5
- import { load_template } from '../../core/config/index.js';
6
- import { runtime_directory } from '../../core/utils.js';
5
+ import { load_template } from '../../../core/config/index.js';
6
+ import { runtime_directory } from '../../../core/utils.js';
7
7
  import { create_build, find_deps, get_default_build_config, is_http_method } from './utils.js';
8
- import { s } from '../../utils/misc.js';
8
+ import { s } from '../../../utils/misc.js';
9
9
 
10
10
  /**
11
11
  * @param {{
@@ -1,6 +1,6 @@
1
1
  import fs from 'fs';
2
2
  import * as vite from 'vite';
3
- import { s } from '../../utils/misc.js';
3
+ import { s } from '../../../utils/misc.js';
4
4
  import { assets_base } from './utils.js';
5
5
 
6
6
  /**
File without changes
@@ -3,16 +3,16 @@ import colors from 'kleur';
3
3
  import path from 'path';
4
4
  import sirv from 'sirv';
5
5
  import { URL } from 'url';
6
- import { getRequest, setResponse } from '../../node/index.js';
7
- import { installPolyfills } from '../../node/polyfills.js';
8
- import { coalesce_to_error } from '../../utils/error.js';
9
- import { posixify } from '../../utils/filesystem.js';
10
- import { load_template } from '../../core/config/index.js';
11
- import { SVELTE_KIT_ASSETS } from '../../core/constants.js';
12
- import * as sync from '../../core/sync/sync.js';
13
- import { get_mime_lookup, runtime_base, runtime_prefix } from '../../core/utils.js';
6
+ import { getRequest, setResponse } from '../../../exports/node/index.js';
7
+ import { installPolyfills } from '../../../exports/node/polyfills.js';
8
+ import { coalesce_to_error } from '../../../utils/error.js';
9
+ import { posixify } from '../../../utils/filesystem.js';
10
+ import { load_template } from '../../../core/config/index.js';
11
+ import { SVELTE_KIT_ASSETS } from '../../../core/constants.js';
12
+ import * as sync from '../../../core/sync/sync.js';
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';
15
- import { compact } from '../../utils/array.js';
15
+ import { compact } from '../../../utils/array.js';
16
16
 
17
17
  // Vite doesn't expose this so we just copy the list for now
18
18
  // https://github.com/vitejs/vite/blob/3edd1af56e980aef56641a5a51cf2932bb580d41/packages/vite/src/node/plugins/css.ts#L96
@@ -4,19 +4,19 @@ import path from 'node:path';
4
4
  import colors from 'kleur';
5
5
  import { svelte } from '@sveltejs/vite-plugin-svelte';
6
6
  import * as vite from 'vite';
7
- import { mkdirp, posixify, rimraf } from '../utils/filesystem.js';
8
- import * as sync from '../core/sync/sync.js';
7
+ import { mkdirp, posixify, rimraf } from '../../utils/filesystem.js';
8
+ import * as sync from '../../core/sync/sync.js';
9
9
  import { build_server } from './build/build_server.js';
10
10
  import { build_service_worker } from './build/build_service_worker.js';
11
- import { load_config } from '../core/config/index.js';
11
+ import { load_config } from '../../core/config/index.js';
12
12
  import { dev } from './dev/index.js';
13
- import { generate_manifest } from '../core/generate_manifest/index.js';
14
- import { runtime_directory, logger } from '../core/utils.js';
13
+ import { generate_manifest } from '../../core/generate_manifest/index.js';
14
+ import { runtime_directory, logger } from '../../core/utils.js';
15
15
  import { find_deps, get_default_build_config } from './build/utils.js';
16
16
  import { preview } from './preview/index.js';
17
17
  import { get_aliases, resolve_entry, prevent_illegal_rollup_imports, get_env } from './utils.js';
18
18
  import { fileURLToPath } from 'node:url';
19
- import { create_static_module, create_dynamic_module } from '../core/env.js';
19
+ import { create_static_module, create_dynamic_module } from '../../core/env.js';
20
20
 
21
21
  const cwd = process.cwd();
22
22
 
@@ -405,7 +405,7 @@ function kit() {
405
405
  const results_path = `${svelte_config.kit.outDir}/generated/prerendered.json`;
406
406
 
407
407
  // do prerendering in a subprocess so any dangling stuff gets killed upon completion
408
- const script = fileURLToPath(new URL('../core/prerender/prerender.js', import.meta.url));
408
+ const script = fileURLToPath(new URL('../../core/prerender/prerender.js', import.meta.url));
409
409
 
410
410
  const child = fork(
411
411
  script,
@@ -465,7 +465,7 @@ function kit() {
465
465
  }
466
466
 
467
467
  if (svelte_config.kit.adapter) {
468
- const { adapt } = await import('../core/adapt/index.js');
468
+ const { adapt } = await import('../../core/adapt/index.js');
469
469
  await adapt(svelte_config, build_data, prerendered, { log });
470
470
  } else {
471
471
  console.log(colors.bold().yellow('\nNo adapter specified'));
@@ -2,9 +2,9 @@ import fs from 'fs';
2
2
  import { join } from 'path';
3
3
  import sirv from 'sirv';
4
4
  import { pathToFileURL } from 'url';
5
- import { getRequest, setResponse } from '../../node/index.js';
6
- import { installPolyfills } from '../../node/polyfills.js';
7
- import { SVELTE_KIT_ASSETS } from '../../core/constants.js';
5
+ import { getRequest, setResponse } from '../../../exports/node/index.js';
6
+ import { installPolyfills } from '../../../exports/node/polyfills.js';
7
+ import { SVELTE_KIT_ASSETS } from '../../../core/constants.js';
8
8
  import { loadEnv } from 'vite';
9
9
 
10
10
  /** @typedef {import('http').IncomingMessage} Req */
File without changes
@@ -1,8 +1,8 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { loadConfigFromFile, loadEnv, normalizePath } from 'vite';
4
- import { runtime_directory } from '../core/utils.js';
5
- import { posixify } from '../utils/filesystem.js';
4
+ import { runtime_directory } from '../../core/utils.js';
5
+ import { posixify } from '../../utils/filesystem.js';
6
6
 
7
7
  /**
8
8
  * @param {import('vite').ResolvedConfig} config
@@ -8,9 +8,9 @@ declare module '__GENERATED__/client-manifest.js' {
8
8
 
9
9
  /**
10
10
  * A map of `[routeId: string]: [leaf, layouts, errors]` tuples, which
11
- * is parsed into an array of routes on startup. The numbers refer to the
12
- * indices in `nodes`. The route layout and error nodes are not referenced,
13
- * they are always number 0 and 1 and always apply.
11
+ * 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.
13
+ * The route layout and error nodes are not referenced, they are always number 0 and 1 and always apply.
14
14
  */
15
15
  export const dictionary: Record<string, [leaf: number, layouts?: number[], errors?: number[]]>;
16
16
 
@@ -4,11 +4,11 @@ import { make_trackable, decode_params, normalize_path } from '../../utils/url.j
4
4
  import { find_anchor, get_base_uri, get_href, scroll_state } from './utils.js';
5
5
  import { lock_fetch, unlock_fetch, initial_fetch, native_fetch } from './fetcher.js';
6
6
  import { parse } from './parse.js';
7
- import { error } from '../../index/index.js';
7
+ import { error } from '../../exports/index.js';
8
8
 
9
9
  import Root from '__GENERATED__/root.svelte';
10
10
  import { nodes, dictionary, matchers } from '__GENERATED__/client-manifest.js';
11
- import { HttpError, Redirect } from '../../index/private.js';
11
+ import { HttpError, Redirect } from '../control.js';
12
12
  import { stores } from './singletons.js';
13
13
 
14
14
  const SCROLL_KEY = 'sveltekit:scroll';
@@ -424,21 +424,37 @@ export function create_client({ target, base, trailing_slash }) {
424
424
  };
425
425
 
426
426
  let data = {};
427
- let data_changed = false;
427
+ let data_changed = !page;
428
428
  for (let i = 0; i < filtered.length; i += 1) {
429
- data = { ...data, ...filtered[i].data };
429
+ const node = filtered[i];
430
+ data = { ...data, ...node.data };
431
+
430
432
  // Only set props if the node actually updated. This prevents needless rerenders.
431
- if (data_changed || !current.branch.some((node) => node === filtered[i])) {
433
+ if (data_changed || !current.branch.some((previous) => previous === node)) {
432
434
  result.props[`data_${i}`] = data;
433
- data_changed = true;
435
+ data_changed = data_changed || Object.keys(node.data ?? {}).length > 0;
434
436
  }
435
437
  }
438
+ if (!data_changed) {
439
+ // If nothing was added, and the object entries are the same length, this means
440
+ // that nothing was removed either and therefore the data is the same as the previous one.
441
+ // This would be more readable with a separate boolean but that would cost us some bytes.
442
+ data_changed = Object.keys(page.data).length !== Object.keys(data).length;
443
+ }
436
444
 
437
445
  const page_changed =
438
446
  !current.url || url.href !== current.url.href || current.error !== error || data_changed;
439
447
 
440
448
  if (page_changed) {
441
- result.props.page = { error, params, routeId, status, url, data };
449
+ result.props.page = {
450
+ error,
451
+ params,
452
+ routeId,
453
+ status,
454
+ url,
455
+ // The whole page store is updated, but this way the object reference stays the same
456
+ data: data_changed ? data : page.data
457
+ };
442
458
 
443
459
  // TODO remove this for 1.0
444
460
  /**
@@ -638,9 +654,10 @@ export function create_client({ target, base, trailing_slash }) {
638
654
 
639
655
  /**
640
656
  * @param {import('types').ServerDataNode | import('types').ServerDataSkippedNode | null} node
657
+ * @param {import('./types').DataNode | null} [previous]
641
658
  * @returns {import('./types').DataNode | null}
642
659
  */
643
- function create_data_node(node) {
660
+ function create_data_node(node, previous) {
644
661
  if (node?.type === 'data') {
645
662
  return {
646
663
  type: 'data',
@@ -652,6 +669,8 @@ export function create_client({ target, base, trailing_slash }) {
652
669
  url: !!node.uses.url
653
670
  }
654
671
  };
672
+ } else if (node?.type === 'skip') {
673
+ return previous ?? null;
655
674
  }
656
675
  return null;
657
676
  }
@@ -672,14 +691,13 @@ export function create_client({ target, base, trailing_slash }) {
672
691
  params: Object.keys(params).filter((key) => current.params[key] !== params[key])
673
692
  };
674
693
 
694
+ const loaders = [...layouts, leaf];
695
+
675
696
  // preload modules to avoid waterfall, but handle rejections
676
697
  // so they don't get reported to Sentry et al (we don't need
677
698
  // to act on the failures at this point)
678
- [...errors, ...layouts, leaf].forEach((loader) => loader?.().catch(() => {}));
679
-
680
- const loaders = [...layouts, leaf];
681
-
682
- // To avoid waterfalls when someone awaits a parent, compute as much as possible here already
699
+ errors.forEach((loader) => loader?.().catch(() => {}));
700
+ loaders.forEach((loader) => loader?.[1]().catch(() => {}));
683
701
 
684
702
  /** @type {import('types').ServerData | null} */
685
703
  let server_data = null;
@@ -687,15 +705,15 @@ export function create_client({ target, base, trailing_slash }) {
687
705
  const invalid_server_nodes = loaders.reduce((acc, loader, i) => {
688
706
  const previous = current.branch[i];
689
707
  const invalid =
690
- loader &&
691
- (previous?.loader !== loader ||
708
+ !!loader?.[0] &&
709
+ (previous?.loader !== loader[1] ||
692
710
  has_changed(changed, acc.some(Boolean), previous.server?.uses));
693
711
 
694
712
  acc.push(invalid);
695
713
  return acc;
696
714
  }, /** @type {boolean[]} */ ([]));
697
715
 
698
- if (route.uses_server_data && invalid_server_nodes.some(Boolean)) {
716
+ if (invalid_server_nodes.some(Boolean)) {
699
717
  try {
700
718
  const res = await native_fetch(
701
719
  `${url.pathname}${url.pathname.endsWith('/') ? '' : '/'}__data.json${url.search}`,
@@ -738,7 +756,7 @@ export function create_client({ target, base, trailing_slash }) {
738
756
  // re-use data from previous load if it's still valid
739
757
  const valid =
740
758
  can_reuse_server_data &&
741
- loader === previous?.loader &&
759
+ loader[1] === previous?.loader &&
742
760
  !has_changed(changed, parent_changed, previous.shared?.uses);
743
761
  if (valid) return previous;
744
762
 
@@ -754,7 +772,7 @@ export function create_client({ target, base, trailing_slash }) {
754
772
  }
755
773
 
756
774
  return load_node({
757
- loader,
775
+ loader: loader[1],
758
776
  url,
759
777
  params,
760
778
  routeId: route.id,
@@ -765,7 +783,7 @@ export function create_client({ target, base, trailing_slash }) {
765
783
  }
766
784
  return data;
767
785
  },
768
- server_data_node: create_data_node(server_data_node) ?? previous?.server ?? null
786
+ server_data_node: create_data_node(server_data_node, previous?.server)
769
787
  });
770
788
  });
771
789
 
@@ -798,11 +816,10 @@ export function create_client({ target, base, trailing_slash }) {
798
816
 
799
817
  let j = i;
800
818
  while (!branch[j]) j -= 1;
801
-
802
819
  try {
803
820
  error_loaded = {
804
- node: await errors[i](),
805
- loader: errors[i],
821
+ node: await /** @type {import('types').CSRPageNodeLoader } */ (errors[i])(),
822
+ loader: /** @type {import('types').CSRPageNodeLoader } */ (errors[i]),
806
823
  data: {},
807
824
  server: null,
808
825
  shared: null
@@ -1084,7 +1101,7 @@ export function create_client({ target, base, trailing_slash }) {
1084
1101
  : routes;
1085
1102
 
1086
1103
  const promises = matching.map((r) => {
1087
- return Promise.all([...r.layouts, r.leaf].map((load) => load?.()));
1104
+ return Promise.all([...r.layouts, r.leaf].map((load) => load?.[1]()));
1088
1105
  });
1089
1106
 
1090
1107
  await Promise.all(promises);
@@ -10,11 +10,6 @@ export function parse(nodes, dictionary, matchers) {
10
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
-
18
13
  const route = {
19
14
  id,
20
15
  /** @param {string} path */
@@ -23,9 +18,8 @@ export function parse(nodes, dictionary, matchers) {
23
18
  if (match) return exec(match, names, types, matchers);
24
19
  },
25
20
  errors: [1, ...(errors || [])].map((n) => nodes[n]),
26
- layouts: [0, ...(layouts || [])].map((n) => nodes[n]),
27
- leaf: nodes[leaf],
28
- uses_server_data
21
+ layouts: [0, ...(layouts || [])].map(create_loader),
22
+ leaf: create_loader(leaf)
29
23
  };
30
24
 
31
25
  // bit of a hack, but ensures that layout/error node lists are the same
@@ -38,4 +32,16 @@ export function parse(nodes, dictionary, matchers) {
38
32
 
39
33
  return route;
40
34
  });
35
+
36
+ /**
37
+ * @param {number} id
38
+ * @returns {[boolean, import('types').CSRPageNodeLoader]}
39
+ */
40
+ function create_loader(id) {
41
+ // whether or not the route uses the server data is
42
+ // encoded using the ones' complement, to save space
43
+ const uses_server_data = id < 0;
44
+ if (uses_server_data) id = ~id;
45
+ return [uses_server_data, nodes[id]];
46
+ }
41
47
  }
@@ -6,8 +6,8 @@ import {
6
6
  prefetch,
7
7
  prefetchRoutes
8
8
  } from '$app/navigation';
9
- import { CSRPageNode, CSRPageNodeLoader, CSRRoute, ServerErrorNode, Uses } from 'types';
10
- import { HttpError } from '../../index/private.js';
9
+ import { CSRPageNode, CSRPageNodeLoader, CSRRoute, Uses } from 'types';
10
+ import { HttpError } from '../control.js';
11
11
  import { SerializedHttpError } from '../server/page/types.js';
12
12
 
13
13
  export interface Client {
File without changes
@@ -1,4 +1,4 @@
1
- import { HttpError, Redirect } from '../../index/private.js';
1
+ import { HttpError, Redirect } from '../control.js';
2
2
  import { check_method_names, method_not_allowed } from './utils.js';
3
3
 
4
4
  /**
@@ -7,9 +7,9 @@ import { serialize_error, GENERIC_ERROR, error_to_pojo } from './utils.js';
7
7
  import { decode_params, disable_search, normalize_path } from '../../utils/url.js';
8
8
  import { exec } from '../../utils/routing.js';
9
9
  import { negotiate } from '../../utils/http.js';
10
- import { HttpError, Redirect } from '../../index/private.js';
10
+ import { HttpError, Redirect } from '../control.js';
11
11
  import { load_server_data } from './page/load_data.js';
12
- import { json } from '../../index/index.js';
12
+ import { json } from '../../exports/index.js';
13
13
  import { once } from '../../utils/functions.js';
14
14
 
15
15
  /* global __SVELTEKIT_ADAPTER_NAME__ */
@@ -280,10 +280,13 @@ export async function respond(request, options, state) {
280
280
  /** @type {Record<string, any>} */
281
281
  const data = {};
282
282
  for (let j = 0; j < i; j += 1) {
283
- const parent = /** @type {import('types').ServerDataNode} */ (
283
+ const parent = /** @type {import('types').ServerDataNode | null} */ (
284
284
  await functions[j]()
285
285
  );
286
- Object.assign(data, parent.data);
286
+
287
+ if (parent) {
288
+ Object.assign(data, parent.data);
289
+ }
287
290
  }
288
291
  return data;
289
292
  }
@@ -3,8 +3,8 @@ import { render_response } from './render.js';
3
3
  import { respond_with_error } from './respond_with_error.js';
4
4
  import { method_not_allowed, error_to_pojo, allowed_methods } from '../utils.js';
5
5
  import { create_fetch } from './fetch.js';
6
- import { HttpError, Redirect } from '../../../index/private.js';
7
- import { error, json } from '../../../index/index.js';
6
+ import { HttpError, Redirect } from '../../control.js';
7
+ import { error, json } from '../../../exports/index.js';
8
8
  import { compact } from '../../../utils/array.js';
9
9
  import { normalize_error } from '../../../utils/error.js';
10
10
  import { load_data, load_server_data } from './load_data.js';
@@ -6,7 +6,7 @@ import { render_json_payload_script } from '../../../utils/escape.js';
6
6
  import { s } from '../../../utils/misc.js';
7
7
  import { Csp } from './csp.js';
8
8
  import { serialize_error } from '../utils.js';
9
- import { HttpError } from '../../../index/private.js';
9
+ import { HttpError } from '../../control.js';
10
10
 
11
11
  // TODO rename this function/module
12
12
 
@@ -1,5 +1,5 @@
1
1
  import { ResponseHeaders, SSRNode, CspDirectives } from 'types';
2
- import { HttpError } from '../../../index/private';
2
+ import { HttpError } from '../../control.js';
3
3
 
4
4
  export interface Fetched {
5
5
  url: string;
@@ -1,4 +1,4 @@
1
- import { HttpError } from '../../index/private.js';
1
+ import { HttpError } from '../control.js';
2
2
 
3
3
  /** @param {any} body */
4
4
  export function is_pojo(body) {
@@ -1,4 +1,4 @@
1
- import { HttpError, Redirect } from '../index/private.js';
1
+ import { HttpError, Redirect } from '../runtime/control.js';
2
2
 
3
3
  /**
4
4
  * @param {unknown} err
package/types/index.d.ts CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  TrailingSlash
18
18
  } from './private.js';
19
19
  import { SSRNodeLoader, SSRRoute, ValidatedConfig } from './internal.js';
20
- import { HttpError, Redirect } from '../src/index/private.js';
20
+ import { HttpError, Redirect } from '../src/runtime/control.js';
21
21
 
22
22
  export interface Adapter {
23
23
  name: string;
@@ -71,13 +71,16 @@ export interface CSRPageNode {
71
71
 
72
72
  export type CSRPageNodeLoader = () => Promise<CSRPageNode>;
73
73
 
74
+ /**
75
+ * Definition of a client side route.
76
+ * The boolean in the tuples indicates whether the route has a server load.
77
+ */
74
78
  export type CSRRoute = {
75
79
  id: string;
76
80
  exec: (path: string) => undefined | Record<string, string>;
77
- errors: CSRPageNodeLoader[];
78
- layouts: CSRPageNodeLoader[];
79
- leaf: CSRPageNodeLoader;
80
- uses_server_data: boolean;
81
+ errors: Array<CSRPageNodeLoader | undefined>;
82
+ layouts: Array<[boolean, CSRPageNodeLoader] | undefined>;
83
+ leaf: [boolean, CSRPageNodeLoader];
81
84
  };
82
85
 
83
86
  export type GetParams = (match: RegExpExecArray) => Record<string, string>;
@@ -194,6 +197,9 @@ export type ServerData =
194
197
  }
195
198
  | {
196
199
  type: 'data';
200
+ /**
201
+ * If `null`, then there was no load function
202
+ */
197
203
  nodes: Array<ServerDataNode | ServerDataSkippedNode | ServerErrorNode | null>;
198
204
  };
199
205