@sveltejs/kit 3.0.0-next.23 → 3.0.0-next.24
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 +40 -5
- package/src/cli.js +3 -3
- package/src/constants.js +13 -1
- package/src/core/adapt/builder.js +2 -3
- package/src/core/env.js +139 -181
- package/src/core/postbuild/analyse.js +9 -4
- package/src/core/postbuild/prerender.js +3 -4
- package/src/core/sync/create_manifest_data/index.js +29 -33
- package/src/core/sync/sync.js +23 -40
- package/src/core/sync/write_app_manifest.js +83 -0
- package/src/core/sync/write_client_manifest.js +6 -4
- package/src/core/sync/write_server.js +10 -6
- package/src/core/sync/write_types/index.js +2 -2
- package/src/core/utils.js +0 -28
- package/src/exports/hooks/public.d.ts +9 -1
- package/src/exports/node/index.js +77 -5
- package/src/exports/vite/build/build_server.js +3 -3
- package/src/exports/vite/build/utils.js +48 -4
- package/src/exports/vite/dev/index.js +11 -22
- package/src/exports/vite/index.js +62 -345
- package/src/exports/vite/module_ids.js +1 -11
- package/src/exports/vite/plugins/env-vars.js +117 -0
- package/src/exports/vite/preview/index.js +6 -4
- package/src/exports/vite/utils.js +2 -4
- package/src/runtime/app/env/{types.d.ts → client.js} +9 -4
- package/src/runtime/app/env/index.js +1 -2
- package/src/runtime/app/env/private/index.js +1 -0
- package/src/runtime/app/env/public/client.js +1 -1
- package/src/runtime/app/env/public/server.js +1 -1
- package/src/runtime/app/env/{internal.js → server.js} +4 -4
- package/src/runtime/app/forms/client.js +263 -0
- package/src/runtime/app/forms/index.js +1 -263
- package/src/runtime/app/forms/public.d.ts +1 -1
- package/src/runtime/app/forms/server.js +6 -0
- package/src/runtime/app/forms/shared.js +34 -0
- package/src/runtime/app/manifest/index.js +1 -1
- package/src/runtime/app/navigation/client.js +15 -0
- package/src/runtime/app/navigation/index.js +1 -15
- package/src/runtime/app/navigation/public.d.ts +1 -1
- package/src/runtime/app/navigation/server.js +15 -0
- package/src/runtime/app/paths/server.js +1 -1
- package/src/runtime/app/server/remote/form.js +11 -1
- package/src/runtime/app/server/remote/prerender.js +1 -2
- package/src/runtime/app/server/remote/query.js +1 -1
- package/src/runtime/app/state/client.svelte.js +207 -0
- package/src/runtime/app/state/index.js +1 -66
- package/src/runtime/app/state/public.d.ts +1 -1
- package/src/runtime/client/bundle.js +1 -1
- package/src/runtime/client/client.js +206 -274
- package/src/runtime/client/fetcher.js +18 -8
- package/src/runtime/client/remote-functions/form.svelte.js +9 -6
- package/src/runtime/client/remote-functions/prerender.svelte.js +1 -1
- package/src/runtime/client/remote-functions/query-live/iterator.js +1 -1
- package/src/runtime/client/remote-functions/shared.svelte.js +2 -2
- package/src/runtime/client/snapshots.js +1 -3
- package/src/runtime/client/stream.js +27 -20
- package/src/runtime/client/utils.js +7 -3
- package/src/runtime/components/root.svelte +5 -5
- package/src/runtime/env/dynamic/private.js +1 -1
- package/src/runtime/env/static/private.js +1 -1
- package/src/runtime/error-chain.js +54 -0
- package/src/runtime/form-utils.js +53 -77
- package/src/runtime/invalid-import.js +1 -0
- package/src/runtime/props.svelte.js +1 -1
- package/src/runtime/server/data/index.js +1 -1
- package/src/runtime/server/endpoint.js +8 -3
- package/src/runtime/server/env_module.js +1 -1
- package/src/runtime/server/errors.js +2 -2
- package/src/runtime/server/index.js +2 -2
- package/src/runtime/server/page/actions.js +77 -122
- package/src/runtime/server/page/index.js +37 -69
- package/src/runtime/server/page/render.js +18 -23
- package/src/runtime/server/remote-functions.js +14 -42
- package/src/runtime/server/respond.js +23 -3
- package/src/telemetry.js +1 -33
- package/src/types/ambient-private.d.ts +9 -17
- package/src/types/internal.d.ts +20 -4
- package/src/types/private.d.ts +1 -1
- package/src/utils/exports.js +1 -0
- package/src/utils/filesystem.js +9 -21
- package/src/utils/functions.js +10 -0
- package/src/utils/routing.js +0 -11
- package/src/utils/url.js +0 -11
- package/src/version.js +1 -1
- package/types/index.d.ts +34 -28
- package/types/index.d.ts.map +7 -5
- package/src/runtime/app/env/private.js +0 -1
- package/src/runtime/app/env/standard-schema.d.ts +0 -0
- package/src/runtime/app/state/client.js +0 -63
- package/src/runtime/client/state.svelte.js +0 -98
- package/src/runtime/server/ambient.d.ts +0 -4
- package/src/utils/path.js +0 -23
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
/** @import { ValidatedConfig } from 'types' */
|
|
1
2
|
import { lookup } from '../../../utils/mime.js';
|
|
2
3
|
import fs from 'node:fs';
|
|
3
4
|
import path from 'node:path';
|
|
4
5
|
import { styleText } from 'node:util';
|
|
5
|
-
import { resolve_entry } from '../../../utils/filesystem.js';
|
|
6
|
+
import { resolve_entry, walk } from '../../../utils/filesystem.js';
|
|
6
7
|
import { posixify } from '../../../utils/os.js';
|
|
7
8
|
import { parse_route_id } from '../../../utils/routing.js';
|
|
8
|
-
import {
|
|
9
|
+
import { runtime_directory } from '../../utils.js';
|
|
9
10
|
import { prevent_conflicts } from './conflict.js';
|
|
10
11
|
import { sort_routes } from './sort.js';
|
|
11
12
|
import {
|
|
@@ -13,24 +14,27 @@ import {
|
|
|
13
14
|
get_page_options
|
|
14
15
|
} from '../../../exports/vite/static_analysis/index.js';
|
|
15
16
|
|
|
17
|
+
const component_name_pattern = /^\+(?:(page(?:@(.*))?)|(layout(?:@(.*))?)|(error))$/;
|
|
18
|
+
|
|
19
|
+
const module_name_pattern =
|
|
20
|
+
/^\+(?:(server)|(page(?:(@[a-zA-Z0-9_-]*))?(\.server)?)|(layout(?:(@[a-zA-Z0-9_-]*))?(\.server)?))$/;
|
|
21
|
+
|
|
16
22
|
/**
|
|
17
23
|
* Generates the manifest data used for the client-side manifest and types generation.
|
|
18
|
-
* @param {
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* cwd: string;
|
|
22
|
-
* }} opts
|
|
24
|
+
* @param {ValidatedConfig} config
|
|
25
|
+
* @param {string} root
|
|
26
|
+
* @param {string} [fallback] Where to look for fallback components
|
|
23
27
|
* @returns {import('types').ManifestData}
|
|
24
28
|
*/
|
|
25
|
-
export default function create_manifest_data(
|
|
29
|
+
export default function create_manifest_data(
|
|
26
30
|
config,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
31
|
+
root,
|
|
32
|
+
fallback = `${runtime_directory}/components`
|
|
33
|
+
) {
|
|
30
34
|
const assets = create_assets(config);
|
|
31
|
-
const hooks = create_hooks(config,
|
|
32
|
-
const params = resolve_params(config,
|
|
33
|
-
const { nodes, routes } = create_routes_and_nodes(
|
|
35
|
+
const hooks = create_hooks(config, root);
|
|
36
|
+
const params = resolve_params(config, root);
|
|
37
|
+
const { nodes, routes } = create_routes_and_nodes(root, config, fallback);
|
|
34
38
|
|
|
35
39
|
return {
|
|
36
40
|
assets,
|
|
@@ -74,7 +78,9 @@ export function is_app_route(route) {
|
|
|
74
78
|
* @param {import('types').ValidatedConfig} config
|
|
75
79
|
*/
|
|
76
80
|
export function create_assets(config) {
|
|
77
|
-
|
|
81
|
+
if (!fs.existsSync(config.files.assets)) return [];
|
|
82
|
+
|
|
83
|
+
return [...walk(config.files.assets)].map((file) => ({
|
|
78
84
|
file,
|
|
79
85
|
size: fs.statSync(path.resolve(config.files.assets, file)).size,
|
|
80
86
|
type: lookup(file) || null
|
|
@@ -232,13 +238,12 @@ function create_routes_and_nodes(cwd, config, fallback) {
|
|
|
232
238
|
|
|
233
239
|
if (!file.name.startsWith('+')) {
|
|
234
240
|
const name = file.name.slice(0, -ext.length);
|
|
241
|
+
const pattern = config.extensions.includes(ext)
|
|
242
|
+
? component_name_pattern
|
|
243
|
+
: module_name_pattern;
|
|
244
|
+
|
|
235
245
|
// check if it is a valid route filename but missing the + prefix
|
|
236
|
-
|
|
237
|
-
/^(?:(page(?:@(.*))?)|(layout(?:@(.*))?)|(error))$/.test(name) ||
|
|
238
|
-
/^(?:(server)|(page(?:(@[a-zA-Z0-9_-]*))?(\.server)?)|(layout(?:(@[a-zA-Z0-9_-]*))?(\.server)?))$/.test(
|
|
239
|
-
name
|
|
240
|
-
);
|
|
241
|
-
if (typo) {
|
|
246
|
+
if (pattern.test(`+${name}`)) {
|
|
242
247
|
console.log(
|
|
243
248
|
styleText(
|
|
244
249
|
['bold', 'yellow'],
|
|
@@ -265,13 +270,7 @@ function create_routes_and_nodes(cwd, config, fallback) {
|
|
|
265
270
|
const ext = valid_extensions.find((ext) => name.endsWith(ext));
|
|
266
271
|
if (ext) name = name.slice(0, -ext.length);
|
|
267
272
|
|
|
268
|
-
|
|
269
|
-
/^\+(?:(page(?:@(.*))?)|(layout(?:@(.*))?)|(error))$/.test(name) ||
|
|
270
|
-
/^\+(?:(server)|(page(?:(@[a-zA-Z0-9_-]*))?(\.server)?)|(layout(?:(@[a-zA-Z0-9_-]*))?(\.server)?))$/.test(
|
|
271
|
-
name
|
|
272
|
-
);
|
|
273
|
-
|
|
274
|
-
if (valid) continue;
|
|
273
|
+
if (component_name_pattern.test(name) || module_name_pattern.test(name)) continue;
|
|
275
274
|
}
|
|
276
275
|
|
|
277
276
|
const project_relative = posixify(path.relative(cwd, path.join(dir, file.name)));
|
|
@@ -535,8 +534,7 @@ function analyze(project_relative, file, component_extensions, module_extensions
|
|
|
535
534
|
const component_extension = component_extensions.find((ext) => file.endsWith(ext));
|
|
536
535
|
if (component_extension) {
|
|
537
536
|
const name = file.slice(0, -component_extension.length);
|
|
538
|
-
const
|
|
539
|
-
const match = pattern.exec(name);
|
|
537
|
+
const match = component_name_pattern.exec(name);
|
|
540
538
|
if (!match) {
|
|
541
539
|
throw new Error(`Files prefixed with + are reserved (saw ${project_relative})`);
|
|
542
540
|
}
|
|
@@ -553,9 +551,7 @@ function analyze(project_relative, file, component_extensions, module_extensions
|
|
|
553
551
|
const module_extension = module_extensions.find((ext) => file.endsWith(ext));
|
|
554
552
|
if (module_extension) {
|
|
555
553
|
const name = file.slice(0, -module_extension.length);
|
|
556
|
-
const
|
|
557
|
-
/^\+(?:(server)|(page(?:(@[a-zA-Z0-9_-]*))?(\.server)?)|(layout(?:(@[a-zA-Z0-9_-]*))?(\.server)?))$/;
|
|
558
|
-
const match = pattern.exec(name);
|
|
554
|
+
const match = module_name_pattern.exec(name);
|
|
559
555
|
if (!match) {
|
|
560
556
|
throw new Error(`Files prefixed with + are reserved (saw ${project_relative})`);
|
|
561
557
|
} else if (match[3] || match[6]) {
|
package/src/core/sync/sync.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** @import { ValidatedConfig, ManifestData } from 'types' */
|
|
1
2
|
import path from 'node:path';
|
|
2
3
|
import create_manifest_data from './create_manifest_data/index.js';
|
|
3
4
|
import { write_client_manifest } from './write_client_manifest.js';
|
|
@@ -11,39 +12,30 @@ import {
|
|
|
11
12
|
} from '../../exports/vite/static_analysis/index.js';
|
|
12
13
|
import { load_explicit_env } from '../env.js';
|
|
13
14
|
import { write_env } from './write_env.js';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Initialize SvelteKit's generated files that only depend on the config and mode.
|
|
17
|
-
* @param {import('types').ValidatedConfig} config
|
|
18
|
-
* @param {string} root The project root directory
|
|
19
|
-
*/
|
|
20
|
-
export function init(config, root) {
|
|
21
|
-
write_tsconfig(config, root);
|
|
22
|
-
}
|
|
15
|
+
import { write_app_manifest } from './write_app_manifest.js';
|
|
23
16
|
|
|
24
17
|
/**
|
|
25
18
|
* Update SvelteKit's generated files
|
|
26
|
-
* @param {
|
|
19
|
+
* @param {ValidatedConfig} config
|
|
27
20
|
* @param {string} root The project root directory
|
|
21
|
+
* @param {ManifestData} manifest_data
|
|
22
|
+
* @param {boolean} is_build
|
|
28
23
|
*/
|
|
29
|
-
export function create(config, root) {
|
|
30
|
-
const
|
|
24
|
+
export function create(config, root, manifest_data, is_build) {
|
|
25
|
+
const output = path.join(config.outDir, `generated/${is_build ? 'build' : 'dev'}`);
|
|
31
26
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
write_client_manifest(config, manifest_data, `${output}/client`);
|
|
27
|
+
write_app_manifest(output, manifest_data, is_build);
|
|
28
|
+
write_client_manifest(config, manifest_data, `${output}/client`, root);
|
|
35
29
|
write_server(config, output, root);
|
|
36
30
|
write_all_types(config, manifest_data, root);
|
|
37
31
|
write_app_types(config, manifest_data, root);
|
|
38
|
-
|
|
39
|
-
return { manifest_data };
|
|
40
32
|
}
|
|
41
33
|
|
|
42
34
|
/**
|
|
43
35
|
* Update SvelteKit's generated files in response to a single file content update.
|
|
44
36
|
* Do not call this when the file in question was created/deleted.
|
|
45
37
|
*
|
|
46
|
-
* @param {
|
|
38
|
+
* @param {ValidatedConfig} config
|
|
47
39
|
* @param {import('types').ManifestData} manifest_data
|
|
48
40
|
* @param {string} file
|
|
49
41
|
* @param {string} root The project root directory
|
|
@@ -79,48 +71,39 @@ export function update(config, manifest_data, file, root) {
|
|
|
79
71
|
}
|
|
80
72
|
|
|
81
73
|
/**
|
|
82
|
-
* Run
|
|
83
|
-
* @param {
|
|
74
|
+
* Run write_tsconfig and sync.create in series during build
|
|
75
|
+
* @param {ValidatedConfig} config
|
|
84
76
|
* @param {string} root The project root directory
|
|
77
|
+
* @param {ManifestData} manifest_data
|
|
85
78
|
*/
|
|
86
|
-
export function all(config, root) {
|
|
87
|
-
|
|
88
|
-
|
|
79
|
+
export function all(config, root, manifest_data) {
|
|
80
|
+
write_tsconfig(config, root);
|
|
81
|
+
create(config, root, manifest_data, true);
|
|
89
82
|
}
|
|
90
83
|
|
|
91
84
|
/**
|
|
92
85
|
* Run sync.init and then generate all type files.
|
|
93
|
-
* @param {
|
|
86
|
+
* @param {ValidatedConfig} config
|
|
94
87
|
* @param {string} root
|
|
95
88
|
*/
|
|
96
89
|
export function all_types(config, root) {
|
|
97
|
-
|
|
98
|
-
const manifest_data = create_manifest_data(
|
|
90
|
+
write_tsconfig(config, root);
|
|
91
|
+
const manifest_data = create_manifest_data(config, root);
|
|
99
92
|
write_all_types(config, manifest_data, root);
|
|
100
93
|
write_app_types(config, manifest_data, root);
|
|
101
94
|
}
|
|
102
95
|
|
|
103
96
|
/**
|
|
104
97
|
* Generate modules and types for explicit env vars
|
|
105
|
-
* @param {
|
|
106
|
-
* @param {import('types').ValidatedConfig} kit
|
|
98
|
+
* @param {ValidatedConfig} kit
|
|
107
99
|
* @param {string | null} entry
|
|
108
100
|
* @param {string} root The Vite root
|
|
109
101
|
* @param {string} mode The Vite mode
|
|
110
102
|
*/
|
|
111
|
-
export async function env(
|
|
112
|
-
const env_config = await load_explicit_env(
|
|
103
|
+
export async function env(kit, entry, root, mode) {
|
|
104
|
+
const env_config = await load_explicit_env(kit, entry, root, mode);
|
|
113
105
|
|
|
114
|
-
write_env(entry, env_config, root);
|
|
106
|
+
write_env(entry, env_config.variables, root);
|
|
115
107
|
|
|
116
108
|
return env_config;
|
|
117
109
|
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Regenerate __SERVER__/internal.js in response to src/{app.html,error.html,service-worker.js} changing
|
|
121
|
-
* @param {import('types').ValidatedConfig} config
|
|
122
|
-
* @param {string} root The project root directory
|
|
123
|
-
*/
|
|
124
|
-
export function server(config, root) {
|
|
125
|
-
write_server(config, path.join(config.outDir, 'generated'), root);
|
|
126
|
-
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/** @import { Asset, ManifestData, RouteData } from 'types' */
|
|
2
|
+
|
|
3
|
+
import { s } from '../../utils/misc.js';
|
|
4
|
+
import { is_app_route, is_endpoint_route, is_page_route } from './create_manifest_data/index.js';
|
|
5
|
+
import { dedent, write_if_changed } from './utils.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates the `$app/manifest` data module. During development, real values
|
|
9
|
+
* are emitted for `assets` and `routes` (the only data known at that point).
|
|
10
|
+
*
|
|
11
|
+
* During build, bare identifier placeholders (fake globals) are emitted.
|
|
12
|
+
* The bundler leaves these as unresolved global references in the output,
|
|
13
|
+
* which are then replaced with real values by scanning the output chunks
|
|
14
|
+
* after each build completes. This avoids the content-hash feedback loop:
|
|
15
|
+
* the manifest data lives in its own chunk with a fixed filename, so
|
|
16
|
+
* importers' hashes are stable regardless of the manifest content.
|
|
17
|
+
*
|
|
18
|
+
* @param {string} out
|
|
19
|
+
* @param {ManifestData | undefined} manifest_data
|
|
20
|
+
* @param {boolean} is_build
|
|
21
|
+
*/
|
|
22
|
+
export function write_app_manifest(out, manifest_data, is_build) {
|
|
23
|
+
const code = is_build
|
|
24
|
+
? // Bare identifiers (fake globals) — the bundler leaves these as
|
|
25
|
+
// unresolved global references in the output. They are replaced
|
|
26
|
+
// with real values by `replace_manifest_placeholder_variables`
|
|
27
|
+
// after each build completes.
|
|
28
|
+
dedent`
|
|
29
|
+
export const immutable = __SVELTEKIT_MANIFEST_IMMUTABLE__;
|
|
30
|
+
export const assets = __SVELTEKIT_MANIFEST_ASSETS__;
|
|
31
|
+
export const prerendered = __SVELTEKIT_MANIFEST_PRERENDERED__;
|
|
32
|
+
export const routes = __SVELTEKIT_MANIFEST_ROUTES__;
|
|
33
|
+
`
|
|
34
|
+
: // In dev, an empty manifest is written before dependency scanning starts.
|
|
35
|
+
// `configureServer` replaces it with the full manifest before modules are served.
|
|
36
|
+
dedent`
|
|
37
|
+
// empty during dev
|
|
38
|
+
export const immutable = [];
|
|
39
|
+
export const prerendered = [];
|
|
40
|
+
|
|
41
|
+
export const assets = [
|
|
42
|
+
${stringify_assets(manifest_data?.assets)}
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
export const routes = [
|
|
46
|
+
${stringify_routes(manifest_data?.routes)}
|
|
47
|
+
];
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
write_if_changed(`${out}/app-manifest.js`, code);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @param {Asset[] | undefined} assets
|
|
55
|
+
* @returns {string}
|
|
56
|
+
*/
|
|
57
|
+
function stringify_assets(assets) {
|
|
58
|
+
return assets?.map((asset) => s({ path: asset.file })).join(',\n') ?? '';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* @param {RouteData[] | undefined} routes
|
|
63
|
+
* @returns {Array<{ id: string; page: boolean; endpoint: boolean }>}
|
|
64
|
+
*/
|
|
65
|
+
export function get_manifest_routes(routes) {
|
|
66
|
+
return (
|
|
67
|
+
routes?.filter(is_app_route).map((route) => ({
|
|
68
|
+
id: route.id,
|
|
69
|
+
page: is_page_route(route),
|
|
70
|
+
endpoint: is_endpoint_route(route)
|
|
71
|
+
})) ?? []
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* @param {RouteData[] | undefined} routes
|
|
77
|
+
* @returns {string}
|
|
78
|
+
*/
|
|
79
|
+
function stringify_routes(routes) {
|
|
80
|
+
return get_manifest_routes(routes)
|
|
81
|
+
.map((route) => s(route))
|
|
82
|
+
.join(',\n');
|
|
83
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
1
2
|
import { check_spelling, dedent, write_if_changed } from './utils.js';
|
|
2
3
|
import { relative_path, resolve_entry } from '../../utils/filesystem.js';
|
|
3
4
|
import { s } from '../../utils/misc.js';
|
|
@@ -8,9 +9,10 @@ import { s } from '../../utils/misc.js';
|
|
|
8
9
|
* @param {import('types').ValidatedConfig} kit
|
|
9
10
|
* @param {import('types').ManifestData} manifest_data
|
|
10
11
|
* @param {string} output
|
|
12
|
+
* @param {string} root The project root directory
|
|
11
13
|
* @param {import('types').ServerMetadata['nodes']} [metadata] If this is omitted, we have to assume that all routes with a `+layout/page.server.js` file have a server load function
|
|
12
14
|
*/
|
|
13
|
-
export function write_client_manifest(kit, manifest_data, output, metadata) {
|
|
15
|
+
export function write_client_manifest(kit, manifest_data, output, root, metadata) {
|
|
14
16
|
const client_routing = kit.router.resolution === 'client';
|
|
15
17
|
|
|
16
18
|
/**
|
|
@@ -22,7 +24,7 @@ export function write_client_manifest(kit, manifest_data, output, metadata) {
|
|
|
22
24
|
|
|
23
25
|
if (node.universal) {
|
|
24
26
|
declarations.push(
|
|
25
|
-
`import * as universal from ${s(relative_path(`${output}/nodes`, node.universal))};`,
|
|
27
|
+
`import * as universal from ${s(relative_path(`${output}/nodes`, path.resolve(root, node.universal)))};`,
|
|
26
28
|
'export { universal };'
|
|
27
29
|
);
|
|
28
30
|
}
|
|
@@ -30,7 +32,7 @@ export function write_client_manifest(kit, manifest_data, output, metadata) {
|
|
|
30
32
|
if (node.component) {
|
|
31
33
|
declarations.push(
|
|
32
34
|
`export { default as component } from ${s(
|
|
33
|
-
relative_path(`${output}/nodes`, node.component)
|
|
35
|
+
relative_path(`${output}/nodes`, path.resolve(root, node.component))
|
|
34
36
|
)};`
|
|
35
37
|
);
|
|
36
38
|
}
|
|
@@ -180,7 +182,7 @@ export function write_client_manifest(kit, manifest_data, output, metadata) {
|
|
|
180
182
|
const module =
|
|
181
183
|
!manifest_data.params || !uses_matchers
|
|
182
184
|
? 'export const matchers = {};'
|
|
183
|
-
: `import { params as matchers } from ${s(relative_path(output, manifest_data.params))};\n\nexport { matchers };`;
|
|
185
|
+
: `import { params as matchers } from ${s(relative_path(output, path.resolve(root, manifest_data.params)))};\n\nexport { matchers };`;
|
|
184
186
|
|
|
185
187
|
write_if_changed(`${output}/matchers.js`, module);
|
|
186
188
|
}
|
|
@@ -6,6 +6,7 @@ import { s } from '../../utils/misc.js';
|
|
|
6
6
|
import { load_error_page, load_template } from '../config/index.js';
|
|
7
7
|
import { check_spelling, write_if_changed } from './utils.js';
|
|
8
8
|
import { escape_html } from '../../utils/escape.js';
|
|
9
|
+
import { runtime_directory } from '../utils.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* @param {{
|
|
@@ -14,6 +15,7 @@ import { escape_html } from '../../utils/escape.js';
|
|
|
14
15
|
* config: import('types').ValidatedConfig;
|
|
15
16
|
* has_service_worker: boolean;
|
|
16
17
|
* template: string;
|
|
18
|
+
* runtime_directory: string;
|
|
17
19
|
* }} opts
|
|
18
20
|
*/
|
|
19
21
|
const server_template = ({
|
|
@@ -21,12 +23,13 @@ const server_template = ({
|
|
|
21
23
|
server_hooks,
|
|
22
24
|
universal_hooks,
|
|
23
25
|
has_service_worker,
|
|
24
|
-
template
|
|
26
|
+
template,
|
|
27
|
+
runtime_directory
|
|
25
28
|
}) => `
|
|
26
|
-
import { set_building, set_prerendering } from '$app/env/
|
|
29
|
+
import { set_building, set_prerendering } from '$app/env/server';
|
|
27
30
|
import { set_assets } from '$app/paths/internal/server';
|
|
28
|
-
import { set_fix_stack_trace, set_manifest, set_read_implementation, log_response } from '
|
|
29
|
-
import error from '
|
|
31
|
+
import { set_fix_stack_trace, set_manifest, set_read_implementation, log_response } from '${runtime_directory}/server/internal.js';
|
|
32
|
+
import error from './shared/error-template.js';
|
|
30
33
|
|
|
31
34
|
export const options = {
|
|
32
35
|
app_template_contains_nonce: ${template.includes('%sveltekit.nonce%')},
|
|
@@ -103,7 +106,7 @@ export function write_server(config, output, root) {
|
|
|
103
106
|
|
|
104
107
|
/** @param {string} file */
|
|
105
108
|
function relative(file) {
|
|
106
|
-
return posixify(path.relative(
|
|
109
|
+
return posixify(path.relative(output, file));
|
|
107
110
|
}
|
|
108
111
|
|
|
109
112
|
write_if_changed(
|
|
@@ -116,9 +119,10 @@ export function write_server(config, output, root) {
|
|
|
116
119
|
// Contains the stringified version of
|
|
117
120
|
/** @type {import('types').SSROptions} */
|
|
118
121
|
write_if_changed(
|
|
119
|
-
`${output}/server
|
|
122
|
+
`${output}/server.js`,
|
|
120
123
|
server_template({
|
|
121
124
|
config,
|
|
125
|
+
runtime_directory: relative(runtime_directory),
|
|
122
126
|
server_hooks: server_hooks_file ? relative(server_hooks_file) : null,
|
|
123
127
|
universal_hooks: universal_hooks_file ? relative(universal_hooks_file) : null,
|
|
124
128
|
has_service_worker:
|
|
@@ -42,12 +42,12 @@ export function write_all_types(config, manifest_data, root) {
|
|
|
42
42
|
posixify(path.relative(root, config.files.routes))
|
|
43
43
|
);
|
|
44
44
|
const expected_directories = new Set(
|
|
45
|
-
manifest_data.routes.map((route) => path.join(routes_dir, route.id))
|
|
45
|
+
manifest_data.routes.map((route) => path.posix.join(routes_dir, route.id))
|
|
46
46
|
);
|
|
47
47
|
|
|
48
48
|
if (fs.existsSync(types_dir)) {
|
|
49
49
|
for (const file of walk(types_dir)) {
|
|
50
|
-
const dir = path.dirname(file);
|
|
50
|
+
const dir = path.posix.dirname(file);
|
|
51
51
|
if (!expected_directories.has(dir)) {
|
|
52
52
|
fs.rmSync(path.join(types_dir, file), { force: true, recursive: true });
|
|
53
53
|
}
|
package/src/core/utils.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
1
|
import path from 'node:path';
|
|
3
2
|
import { fileURLToPath } from 'node:url';
|
|
4
3
|
import { styleText } from 'node:util';
|
|
@@ -85,30 +84,3 @@ export function get_mime_lookup(manifest_data) {
|
|
|
85
84
|
|
|
86
85
|
return mime;
|
|
87
86
|
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* @param {string} dir
|
|
91
|
-
* @param {(file: string) => boolean} [filter]
|
|
92
|
-
*/
|
|
93
|
-
export function list_files(dir, filter) {
|
|
94
|
-
/** @type {string[]} */
|
|
95
|
-
const files = [];
|
|
96
|
-
|
|
97
|
-
/** @param {string} current */
|
|
98
|
-
function walk(current) {
|
|
99
|
-
for (const file of fs.readdirSync(path.resolve(dir, current))) {
|
|
100
|
-
const child = path.posix.join(current, file);
|
|
101
|
-
if (fs.statSync(path.resolve(dir, child)).isDirectory()) {
|
|
102
|
-
walk(child);
|
|
103
|
-
} else {
|
|
104
|
-
if (!filter || filter(child)) {
|
|
105
|
-
files.push(child);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (fs.existsSync(dir)) walk('');
|
|
112
|
-
|
|
113
|
-
return files;
|
|
114
|
-
}
|
|
@@ -170,9 +170,17 @@ export interface ResolveOptions {
|
|
|
170
170
|
* `<head>` tag; if `output.linkHeaderPreload` is enabled, dynamically rendered pages use the
|
|
171
171
|
* [`Link` response header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Link) instead.
|
|
172
172
|
* By default, `js` and `css` files will be preloaded.
|
|
173
|
+
*
|
|
174
|
+
* For `font` files, `input` also has a `filename` property, the source file's pathname relative
|
|
175
|
+
* to the project root, so that a filter can match on it instead of the hashed path. `js` and
|
|
176
|
+
* `css` files are bundled and have no single source file name.
|
|
173
177
|
* @param input the type of the file and its path
|
|
174
178
|
*/
|
|
175
|
-
preload?: (
|
|
179
|
+
preload?: (
|
|
180
|
+
input:
|
|
181
|
+
| { type: 'css' | 'js' | 'asset'; path: string }
|
|
182
|
+
| { type: 'font'; path: string; filename: string }
|
|
183
|
+
) => boolean;
|
|
176
184
|
}
|
|
177
185
|
|
|
178
186
|
type AppErrorWithOptionalDefaults = Omit<App.Error, 'status' | 'message'> & {
|
|
@@ -116,12 +116,13 @@ function get_raw_body(req, body_size_limit) {
|
|
|
116
116
|
/**
|
|
117
117
|
* @param {{
|
|
118
118
|
* request: import('http').IncomingMessage;
|
|
119
|
+
* response?: import('http').ServerResponse;
|
|
119
120
|
* base: string;
|
|
120
121
|
* bodySizeLimit?: number;
|
|
121
122
|
* }} options
|
|
122
123
|
* @returns {Request}
|
|
123
124
|
*/
|
|
124
|
-
export function getRequest({ request, base, bodySizeLimit }) {
|
|
125
|
+
export function getRequest({ request, response, base, bodySizeLimit }) {
|
|
125
126
|
let headers = /** @type {Record<string, string>} */ (request.headers);
|
|
126
127
|
if (request.httpVersionMajor >= 2) {
|
|
127
128
|
// the Request constructor rejects headers with ':' in the name
|
|
@@ -144,6 +145,15 @@ export function getRequest({ request, base, bodySizeLimit }) {
|
|
|
144
145
|
}
|
|
145
146
|
});
|
|
146
147
|
|
|
148
|
+
// `readableAborted` stays false once the request has been fully read (or drained),
|
|
149
|
+
// so a client disconnect must also be detected on the response side. `writableEnded`
|
|
150
|
+
// rather than `writableFinished` because HTTP/2 marks cancelled streams as finished
|
|
151
|
+
response?.once('close', () => {
|
|
152
|
+
if (!response.writableEnded) {
|
|
153
|
+
controller.abort();
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
147
157
|
return new Request(base + request.url, {
|
|
148
158
|
// @ts-expect-error
|
|
149
159
|
duplex: 'half',
|
|
@@ -214,14 +224,14 @@ export function setResponse(res, response) {
|
|
|
214
224
|
}
|
|
215
225
|
}
|
|
216
226
|
|
|
217
|
-
res.writeHead(response.status);
|
|
218
|
-
|
|
219
227
|
if (!response.body) {
|
|
228
|
+
res.writeHead(response.status);
|
|
220
229
|
res.end();
|
|
221
230
|
return;
|
|
222
231
|
}
|
|
223
232
|
|
|
224
233
|
if (response.body.locked) {
|
|
234
|
+
res.writeHead(response.status);
|
|
225
235
|
res.end(
|
|
226
236
|
'Fatal error: Response body is locked. ' +
|
|
227
237
|
"This can happen when the response was already read (for example through 'response.json()' or 'response.text()')."
|
|
@@ -249,11 +259,73 @@ export function setResponse(res, response) {
|
|
|
249
259
|
res.on('close', cancel);
|
|
250
260
|
res.on('error', cancel);
|
|
251
261
|
|
|
252
|
-
|
|
262
|
+
/** @type {Uint8Array<ArrayBuffer>[]} */
|
|
263
|
+
const buffered = [];
|
|
264
|
+
|
|
265
|
+
/** @type {ReturnType<typeof reader.read> | null} */
|
|
266
|
+
let pending = null;
|
|
267
|
+
|
|
268
|
+
void probe();
|
|
269
|
+
|
|
270
|
+
// a fixed body (a string, buffer or blob, however constructed) settles all its
|
|
271
|
+
// reads before the next macrotask, so it can be measured and sent with a
|
|
272
|
+
// `content-length`; a genuine stream leaves a read pending and only has its
|
|
273
|
+
// headers delayed by a single tick
|
|
274
|
+
async function probe() {
|
|
275
|
+
try {
|
|
276
|
+
/** @type {Promise<undefined>} */
|
|
277
|
+
const deadline = new Promise((fulfil) => setImmediate(() => fulfil(undefined)));
|
|
278
|
+
|
|
279
|
+
while (buffered.length < 2) {
|
|
280
|
+
pending = reader.read();
|
|
281
|
+
const result = await Promise.race([pending, deadline]);
|
|
282
|
+
|
|
283
|
+
if (!result) break; // deadline hit — treat the body as a stream
|
|
284
|
+
|
|
285
|
+
pending = null;
|
|
286
|
+
|
|
287
|
+
if (result.done) {
|
|
288
|
+
// a `content-length` next to a `transfer-encoding` would be invalid
|
|
289
|
+
if (!res.hasHeader('content-length') && !res.hasHeader('transfer-encoding')) {
|
|
290
|
+
res.setHeader(
|
|
291
|
+
'content-length',
|
|
292
|
+
buffered.reduce((total, chunk) => total + chunk.byteLength, 0)
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
break;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
buffered.push(result.value);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if (res.destroyed) return;
|
|
302
|
+
|
|
303
|
+
res.writeHead(response.status);
|
|
304
|
+
await next();
|
|
305
|
+
} catch (error) {
|
|
306
|
+
if (!res.headersSent) res.writeHead(response.status);
|
|
307
|
+
cancel(error instanceof Error ? error : new Error(String(error)));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
253
311
|
async function next() {
|
|
254
312
|
try {
|
|
255
313
|
for (;;) {
|
|
256
|
-
|
|
314
|
+
/** @type {Awaited<ReturnType<typeof reader.read>>} */
|
|
315
|
+
let result;
|
|
316
|
+
if (buffered.length > 0) {
|
|
317
|
+
result = {
|
|
318
|
+
done: false,
|
|
319
|
+
value: /** @type {Uint8Array<ArrayBuffer>} */ (buffered.shift())
|
|
320
|
+
};
|
|
321
|
+
} else if (pending) {
|
|
322
|
+
result = await pending;
|
|
323
|
+
pending = null;
|
|
324
|
+
} else {
|
|
325
|
+
result = await reader.read();
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const { done, value } = result;
|
|
257
329
|
|
|
258
330
|
if (done) break;
|
|
259
331
|
|
|
@@ -128,7 +128,7 @@ export function build_server_nodes(
|
|
|
128
128
|
/** @type {string[]} */
|
|
129
129
|
let stylesheets = [];
|
|
130
130
|
|
|
131
|
-
/** @type {
|
|
131
|
+
/** @type {import('types').FontDependency[]} */
|
|
132
132
|
let fonts = [];
|
|
133
133
|
|
|
134
134
|
/** @type {Set<string>} */
|
|
@@ -187,7 +187,7 @@ export function build_server_nodes(
|
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
if (client_manifest) {
|
|
190
|
-
const entry_path = `${out_dir}/generated/client-optimized/nodes/${i}.js`;
|
|
190
|
+
const entry_path = `${out_dir}/generated/build/client-optimized/nodes/${i}.js`;
|
|
191
191
|
const entry = find_deps(client_manifest, entry_path, true, root);
|
|
192
192
|
|
|
193
193
|
// Eagerly load client stylesheets and fonts imported by the SSR-ed page to avoid FOUC.
|
|
@@ -212,7 +212,7 @@ export function build_server_nodes(
|
|
|
212
212
|
|
|
213
213
|
imported = entry.imports;
|
|
214
214
|
stylesheets = Array.from(eager_css);
|
|
215
|
-
fonts = filter_fonts(Array.from(eager_assets));
|
|
215
|
+
fonts = filter_fonts(Array.from(eager_assets), client_manifest, root);
|
|
216
216
|
} else {
|
|
217
217
|
for (const entry of [component, universal]) {
|
|
218
218
|
if (!entry) continue;
|