@sveltejs/kit 3.0.0-next.13 → 3.0.0-next.14
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 +2 -2
- package/src/cli.js +2 -2
- package/src/core/adapt/builder.js +8 -5
- package/src/core/generate_manifest/index.js +6 -0
- package/src/core/postbuild/entities.js +8 -2
- package/src/core/postbuild/fallback.js +2 -1
- package/src/core/postbuild/prerender.js +12 -3
- package/src/core/sync/create_manifest_data/conflict.js +1 -1
- package/src/core/sync/create_manifest_data/index.js +33 -2
- package/src/core/sync/write_app_types.js +72 -27
- package/src/core/sync/write_tsconfig/index.js +2 -1
- package/src/core/sync/write_types/index.js +5 -2
- package/src/exports/node/index.js +2 -7
- package/src/exports/public.d.ts +3 -2
- package/src/exports/vite/index.js +45 -11
- package/src/exports/vite/utils.js +1 -7
- package/src/runtime/app/server/remote/query.js +0 -6
- package/src/runtime/client/client.js +148 -38
- package/src/runtime/client/fetcher.js +2 -13
- package/src/runtime/client/remote-functions/form.svelte.js +3 -7
- package/src/runtime/client/remote-functions/prerender.svelte.js +1 -1
- package/src/runtime/client/remote-functions/query/index.js +1 -1
- package/src/runtime/client/remote-functions/query-batch.svelte.js +1 -1
- package/src/runtime/client/remote-functions/query-live/proxy.js +0 -10
- package/src/runtime/client/remote-functions/shared.svelte.js +1 -1
- package/src/runtime/client/utils.js +1 -0
- package/src/runtime/form-utils.js +4 -6
- package/src/runtime/pathname.js +37 -0
- package/src/runtime/server/fetch.js +5 -8
- package/src/runtime/server/index.js +10 -24
- package/src/runtime/server/page/crypto.js +2 -2
- package/src/runtime/server/page/csp.js +2 -1
- package/src/runtime/server/page/load_data.js +2 -29
- package/src/runtime/server/page/render.js +19 -1
- package/src/runtime/server/page/serialize_data.js +2 -13
- package/src/runtime/server/page/server_routing.js +58 -9
- package/src/runtime/server/respond.js +20 -27
- package/src/runtime/server/state.js +43 -0
- package/src/runtime/shared.js +4 -2
- package/src/runtime/utils.js +3 -0
- package/src/types/ambient-private.d.ts +1 -1
- package/src/types/ambient.d.ts +58 -7
- package/src/types/global-private.d.ts +1 -1
- package/src/types/internal.d.ts +2 -1
- package/src/utils/hash.js +21 -0
- package/src/utils/http.js +8 -7
- package/src/utils/import.js +2 -1
- package/src/utils/params.js +1 -1
- package/src/utils/regex.js +9 -0
- package/src/utils/routing.js +52 -27
- package/src/utils/url.js +1 -0
- package/src/version.js +1 -1
- package/types/index.d.ts +74 -10
- package/types/index.d.ts.map +1 -1
- package/src/exports/node/polyfills.js +0 -30
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sveltejs/kit",
|
|
3
|
-
"version": "3.0.0-next.
|
|
3
|
+
"version": "3.0.0-next.14",
|
|
4
4
|
"description": "SvelteKit is the fastest way to build Svelte apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
},
|
|
128
128
|
"types": "types/index.d.ts",
|
|
129
129
|
"engines": {
|
|
130
|
-
"node": ">=22"
|
|
130
|
+
"node": ">=22.17"
|
|
131
131
|
},
|
|
132
132
|
"scripts": {
|
|
133
133
|
"lint": "prettier --config ../../.prettierrc --check .",
|
package/src/cli.js
CHANGED
|
@@ -75,10 +75,10 @@ if (!command) {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
if (command === 'sync') {
|
|
78
|
-
// create placeholder node_modules/$app/tsconfig
|
|
78
|
+
// create placeholder node_modules/$app/tsconfig.json if necessary, to squelch warnings.
|
|
79
79
|
// this isn't bulletproof — if someone has some esoteric config, it will continue
|
|
80
80
|
// to harmlessly warn — but we handle the 90% case and clean up after ourselves
|
|
81
|
-
const dir = 'node_modules/$app
|
|
81
|
+
const dir = 'node_modules/$app';
|
|
82
82
|
const base_tsconfig = `${dir}/tsconfig.json`;
|
|
83
83
|
const base_tsconfig_json = '{}';
|
|
84
84
|
|
|
@@ -109,16 +109,19 @@ export function create_builder({
|
|
|
109
109
|
|
|
110
110
|
async compress(directory) {
|
|
111
111
|
if (!existsSync(directory)) {
|
|
112
|
-
return;
|
|
112
|
+
return [];
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
const files = list_files(directory, (file) => extensions.includes(extname(file)))
|
|
116
|
-
(file) => resolve(directory, file)
|
|
117
|
-
);
|
|
115
|
+
const files = list_files(directory, (file) => extensions.includes(extname(file)));
|
|
118
116
|
|
|
119
117
|
await Promise.all(
|
|
120
|
-
files.flatMap((file) =>
|
|
118
|
+
files.flatMap((file) => {
|
|
119
|
+
const abs = resolve(directory, file);
|
|
120
|
+
return [compress_file(abs, 'gz'), compress_file(abs, 'br')];
|
|
121
|
+
})
|
|
121
122
|
);
|
|
123
|
+
|
|
124
|
+
return files;
|
|
122
125
|
},
|
|
123
126
|
|
|
124
127
|
findServerAssets(route_data) {
|
|
@@ -94,6 +94,12 @@ export function generate_manifest({
|
|
|
94
94
|
mime_types[ext] ??= mime_lookup(ext) || '';
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
// record extensions that only exist in prerendered output, e.g. a prerendered favicon.ico
|
|
98
|
+
for (const pathname of prerendered) {
|
|
99
|
+
const ext = path.extname(pathname);
|
|
100
|
+
if (ext) mime_types[ext] ??= mime_lookup(ext) || '';
|
|
101
|
+
}
|
|
102
|
+
|
|
97
103
|
// prettier-ignore
|
|
98
104
|
// String representation of
|
|
99
105
|
/** @template {import('@sveltejs/kit').SSRManifest} T */
|
|
@@ -2236,7 +2236,7 @@ const entities = {
|
|
|
2236
2236
|
'zwnj;': ''
|
|
2237
2237
|
};
|
|
2238
2238
|
|
|
2239
|
-
const numeric = /&#(x)?([0-9a-f]+);/
|
|
2239
|
+
const numeric = /&#(x)?([0-9a-f]+);/gi;
|
|
2240
2240
|
const named = new RegExp(
|
|
2241
2241
|
`&(${Object.keys(entities)
|
|
2242
2242
|
.sort((a, b) => b.length - a.length)
|
|
@@ -2247,6 +2247,12 @@ const named = new RegExp(
|
|
|
2247
2247
|
/** @param {string} str */
|
|
2248
2248
|
export function decode(str) {
|
|
2249
2249
|
return str
|
|
2250
|
-
.replace(numeric, (_match, hex, code) =>
|
|
2250
|
+
.replace(numeric, (_match, hex, code) => {
|
|
2251
|
+
const codepoint = hex ? parseInt(code, 16) : +code;
|
|
2252
|
+
// mirror the HTML parser, which replaces invalid numeric references with U+FFFD
|
|
2253
|
+
return Number.isInteger(codepoint) && codepoint <= 0x10ffff
|
|
2254
|
+
? String.fromCodePoint(codepoint)
|
|
2255
|
+
: '\ufffd';
|
|
2256
|
+
})
|
|
2251
2257
|
.replace(named, (_match, entity) => entities[entity]);
|
|
2252
2258
|
}
|
|
@@ -39,7 +39,8 @@ async function generate_fallback({ manifest_path, env, out_dir, origin, assets }
|
|
|
39
39
|
prerendering: {
|
|
40
40
|
fallback: true,
|
|
41
41
|
dependencies: new Map(),
|
|
42
|
-
remote_responses: new Map()
|
|
42
|
+
remote_responses: new Map(),
|
|
43
|
+
resolved_route_ids: new Set()
|
|
43
44
|
},
|
|
44
45
|
read: (file) => readFileSync(join(assets, file))
|
|
45
46
|
});
|
|
@@ -17,6 +17,7 @@ import { createReadableStream } from '@sveltejs/kit/node';
|
|
|
17
17
|
import generate_fallback from './fallback.js';
|
|
18
18
|
import { stringify_remote_arg } from '../../runtime/shared.js';
|
|
19
19
|
import { log_response } from '../../exports/vite/utils.js';
|
|
20
|
+
import { matches_content_type } from '../../utils/http.js';
|
|
20
21
|
|
|
21
22
|
export default forked(import.meta.url, prerender);
|
|
22
23
|
|
|
@@ -262,6 +263,9 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
262
263
|
/** @type {Map<string, Promise<any>>} */
|
|
263
264
|
const remote_responses = new Map();
|
|
264
265
|
|
|
266
|
+
/** @type {Set<string>} */
|
|
267
|
+
const resolved_route_ids = new Set();
|
|
268
|
+
|
|
265
269
|
/** @type {Map<string, Set<string>>} */
|
|
266
270
|
const expected_hashlinks = new Map();
|
|
267
271
|
|
|
@@ -307,7 +311,8 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
307
311
|
},
|
|
308
312
|
prerendering: {
|
|
309
313
|
dependencies,
|
|
310
|
-
remote_responses
|
|
314
|
+
remote_responses,
|
|
315
|
+
resolved_route_ids
|
|
311
316
|
},
|
|
312
317
|
read: (file) => {
|
|
313
318
|
// stuff we just wrote
|
|
@@ -387,7 +392,11 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
387
392
|
const headers = Object.fromEntries(response.headers);
|
|
388
393
|
|
|
389
394
|
// if it's a 200 HTML response, crawl it. Skip error responses, as we don't save those
|
|
390
|
-
if (
|
|
395
|
+
if (
|
|
396
|
+
response.ok &&
|
|
397
|
+
config.prerender.crawl &&
|
|
398
|
+
matches_content_type(headers['content-type'], 'text/html')
|
|
399
|
+
) {
|
|
391
400
|
const { ids, hrefs, invalid } = crawl(body.toString(), decoded);
|
|
392
401
|
|
|
393
402
|
for (const href of invalid) {
|
|
@@ -444,7 +453,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
444
453
|
const headers = Object.fromEntries(response.headers);
|
|
445
454
|
|
|
446
455
|
const type = headers['content-type'];
|
|
447
|
-
const is_html = response_type === REDIRECT || type
|
|
456
|
+
const is_html = response_type === REDIRECT || matches_content_type(type, 'text/html');
|
|
448
457
|
|
|
449
458
|
if (!is_html && response.status === 200 && decoded.slice(config.paths.base.length + 1) === '') {
|
|
450
459
|
throw new Error(
|
|
@@ -60,7 +60,7 @@ function normalize_route_id(id) {
|
|
|
60
60
|
.replace(/(?<=^|\/)\(.+?\)(?=$|\/)/g, '')
|
|
61
61
|
|
|
62
62
|
.replace(/\[[ux]\+([0-9a-f]+)\]/g, (_, x) =>
|
|
63
|
-
String.
|
|
63
|
+
String.fromCodePoint(parseInt(x, 16)).replace(/\//g, '%2f')
|
|
64
64
|
)
|
|
65
65
|
|
|
66
66
|
// replace `[param]` with `<*>`, `[param=x]` with `<x>`, and `[[param]]` with `<?*>`
|
|
@@ -41,6 +41,34 @@ export default function create_manifest_data({
|
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Whether this route has a `+page`. Independent of `is_endpoint_route` — a route can be both.
|
|
46
|
+
* @param {import('types').RouteData} route
|
|
47
|
+
* @returns {boolean}
|
|
48
|
+
*/
|
|
49
|
+
export function is_page_route(route) {
|
|
50
|
+
return !!route.page;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Whether this route has a `+server`. Independent of `is_page_route` — a route can be both.
|
|
55
|
+
* @param {import('types').RouteData} route
|
|
56
|
+
* @returns {boolean}
|
|
57
|
+
*/
|
|
58
|
+
export function is_endpoint_route(route) {
|
|
59
|
+
return !!route.endpoint;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Whether the router can match this route. `manifest_data.routes` also contains entries for
|
|
64
|
+
* directories with layouts or errors, which never reach `event.route.id`.
|
|
65
|
+
* @param {import('types').RouteData} route
|
|
66
|
+
* @returns {boolean}
|
|
67
|
+
*/
|
|
68
|
+
export function is_app_route(route) {
|
|
69
|
+
return is_page_route(route) || is_endpoint_route(route);
|
|
70
|
+
}
|
|
71
|
+
|
|
44
72
|
/**
|
|
45
73
|
* Returns a list of files in the `static` directory.
|
|
46
74
|
* @param {import('types').ValidatedConfig} config
|
|
@@ -85,7 +113,7 @@ function resolve_params(config, cwd) {
|
|
|
85
113
|
*/
|
|
86
114
|
function create_routes_and_nodes(cwd, config, fallback) {
|
|
87
115
|
/** @type {import('types').RouteData[]} */
|
|
88
|
-
|
|
116
|
+
let routes = [];
|
|
89
117
|
|
|
90
118
|
const routes_base = posixify(path.relative(cwd, config.kit.files.routes));
|
|
91
119
|
|
|
@@ -125,7 +153,7 @@ function create_routes_and_nodes(cwd, config, fallback) {
|
|
|
125
153
|
);
|
|
126
154
|
}
|
|
127
155
|
|
|
128
|
-
return String.
|
|
156
|
+
return String.fromCodePoint(parseInt(code, 16));
|
|
129
157
|
}
|
|
130
158
|
});
|
|
131
159
|
|
|
@@ -440,6 +468,9 @@ function create_routes_and_nodes(cwd, config, fallback) {
|
|
|
440
468
|
}
|
|
441
469
|
}
|
|
442
470
|
|
|
471
|
+
// remove route objects with no route file
|
|
472
|
+
routes = routes.filter((route) => route.endpoint || route.leaf || route.layout || route.error);
|
|
473
|
+
|
|
443
474
|
// add parents to error nodes so that we can compute which page options apply to them
|
|
444
475
|
for (const route of routes) {
|
|
445
476
|
if (!route.error) continue;
|
|
@@ -4,15 +4,42 @@ import { resolve_entry } from '../../utils/filesystem.js';
|
|
|
4
4
|
import { posixify } from '../../utils/os.js';
|
|
5
5
|
import { write_if_changed } from './utils.js';
|
|
6
6
|
import { s } from '../../utils/misc.js';
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
import {
|
|
8
|
+
decode_escape_sequence,
|
|
9
|
+
encode_pathname_chars,
|
|
10
|
+
get_route_segments,
|
|
11
|
+
segment_pattern
|
|
12
|
+
} from '../../utils/routing.js';
|
|
13
|
+
import { is_app_route, is_endpoint_route, is_page_route } from './create_manifest_data/index.js';
|
|
14
|
+
|
|
15
|
+
const optional_param_pattern = /^\[\[[\w-]+(?:=[\w-]+)?\]\]$/;
|
|
16
|
+
const rest_param_pattern = /^\[\.\.\.[\w-]+(?:=[\w-]+)?\]$/;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Convert a route ID to the pathnames it can match (relative to the base path), in which each
|
|
20
|
+
* param is replaced with `${string}` and each escape sequence is expanded. A param that fills an
|
|
21
|
+
* entire segment can be absent, so it contributes a pathname with the segment and one without,
|
|
22
|
+
* rather than one that absorbs the `/`
|
|
23
|
+
* @param {string} id
|
|
24
|
+
*/
|
|
25
|
+
const get_pathname_patterns = (id) => {
|
|
26
|
+
let pathnames = [''];
|
|
27
|
+
|
|
28
|
+
for (const segment of get_route_segments(id)) {
|
|
29
|
+
const omittable = optional_param_pattern.test(segment) || rest_param_pattern.test(segment);
|
|
30
|
+
const content = omittable
|
|
31
|
+
? '${string}'
|
|
32
|
+
: segment.replace(segment_pattern, (_, escape_type, escape_code) =>
|
|
33
|
+
escape_type ? encode_pathname_chars(decode_escape_sequence(escape_code)) : '${string}'
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
pathnames = pathnames.flatMap((pathname) => {
|
|
37
|
+
const joined = pathname === '' ? content : `${pathname}/${content}`;
|
|
38
|
+
return omittable ? [joined, pathname] : [joined];
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return [...new Set(pathnames)];
|
|
16
43
|
};
|
|
17
44
|
|
|
18
45
|
/**
|
|
@@ -142,6 +169,15 @@ function generate_app_types(manifest_data, config, dir) {
|
|
|
142
169
|
/** @type {Set<string>} */
|
|
143
170
|
const pathnames = new Set();
|
|
144
171
|
|
|
172
|
+
/** @type {string[]} */
|
|
173
|
+
const page_route_ids = [];
|
|
174
|
+
|
|
175
|
+
/** @type {string[]} */
|
|
176
|
+
const endpoint_route_ids = [];
|
|
177
|
+
|
|
178
|
+
/** @type {string[]} */
|
|
179
|
+
const app_route_ids = [];
|
|
180
|
+
|
|
145
181
|
/** @type {string[]} */
|
|
146
182
|
const dynamic_routes = [];
|
|
147
183
|
|
|
@@ -150,15 +186,17 @@ function generate_app_types(manifest_data, config, dir) {
|
|
|
150
186
|
|
|
151
187
|
/** @type {Map<string, Map<string, { optional: boolean, matchers: Set<string> | null }>>} */
|
|
152
188
|
const layout_params_by_route = new Map(
|
|
153
|
-
manifest_data.routes
|
|
154
|
-
route.
|
|
155
|
-
|
|
156
|
-
route.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
189
|
+
manifest_data.routes
|
|
190
|
+
.filter((route) => route.layout)
|
|
191
|
+
.map((route) => [
|
|
192
|
+
route.id,
|
|
193
|
+
new Map(
|
|
194
|
+
route.params.map((p) => [
|
|
195
|
+
p.name,
|
|
196
|
+
{ optional: p.optional, matchers: p.matcher ? new Set([p.matcher]) : null }
|
|
197
|
+
])
|
|
198
|
+
)
|
|
199
|
+
])
|
|
162
200
|
);
|
|
163
201
|
|
|
164
202
|
for (const route of manifest_data.routes) {
|
|
@@ -192,8 +230,11 @@ function generate_app_types(manifest_data, config, dir) {
|
|
|
192
230
|
}
|
|
193
231
|
|
|
194
232
|
for (const route of manifest_data.routes) {
|
|
195
|
-
const
|
|
196
|
-
|
|
233
|
+
const id = s(route.id);
|
|
234
|
+
|
|
235
|
+
if (is_page_route(route)) page_route_ids.push(id);
|
|
236
|
+
if (is_endpoint_route(route)) endpoint_route_ids.push(id);
|
|
237
|
+
if (is_app_route(route)) app_route_ids.push(id);
|
|
197
238
|
|
|
198
239
|
/** @type {(path: string) => string} */
|
|
199
240
|
let serialise = s;
|
|
@@ -203,16 +244,18 @@ function generate_app_types(manifest_data, config, dir) {
|
|
|
203
244
|
const type = get_matcher_type(p.matcher);
|
|
204
245
|
return `${/^\w+$/.test(p.name) ? p.name : `'${p.name}'`}${p.optional ? '?:' : ':'} ${type}${p.optional ? ' | undefined' : ''}`;
|
|
205
246
|
});
|
|
206
|
-
const route_type = `${s(route.id)}: { ${params.join('; ')} }`;
|
|
207
247
|
|
|
208
|
-
|
|
248
|
+
if (is_app_route(route)) {
|
|
249
|
+
dynamic_routes.push(`${s(route.id)}: { ${params.join('; ')} }`);
|
|
250
|
+
}
|
|
209
251
|
|
|
210
|
-
normalized_pathname = replace_required_params(replace_optional_params(pathname)).slice(1);
|
|
211
252
|
serialise = (p) => `\`${p}\` & {}`;
|
|
212
253
|
}
|
|
213
254
|
|
|
214
|
-
for (const
|
|
215
|
-
|
|
255
|
+
for (const pathname of get_pathname_patterns(route.id)) {
|
|
256
|
+
for (const p of get_pathnames_for_trailing_slash(pathname, route)) {
|
|
257
|
+
pathnames.add(serialise(p));
|
|
258
|
+
}
|
|
216
259
|
}
|
|
217
260
|
|
|
218
261
|
let layout_type = 'Record<string, never>';
|
|
@@ -229,7 +272,7 @@ function generate_app_types(manifest_data, config, dir) {
|
|
|
229
272
|
if (params.length > 0) layout_type = `{ ${params} }`;
|
|
230
273
|
}
|
|
231
274
|
|
|
232
|
-
layouts.push(`${s(route.id)}: ${layout_type}`);
|
|
275
|
+
if (route.layout) layouts.push(`${s(route.id)}: ${layout_type}`);
|
|
233
276
|
}
|
|
234
277
|
|
|
235
278
|
const assets = manifest_data.assets.map((asset) => s(asset.file));
|
|
@@ -237,7 +280,9 @@ function generate_app_types(manifest_data, config, dir) {
|
|
|
237
280
|
return [
|
|
238
281
|
'declare module "$app/types" {',
|
|
239
282
|
'\texport interface AppTypes {',
|
|
240
|
-
`\t\
|
|
283
|
+
`\t\tPageRouteId(): ${page_route_ids.join(' | ') || 'never'};`,
|
|
284
|
+
`\t\tEndpointRouteId(): ${endpoint_route_ids.join(' | ') || 'never'};`,
|
|
285
|
+
`\t\tRouteId(): ${app_route_ids.join(' | ') || 'never'};`,
|
|
241
286
|
`\t\tRouteParams(): {\n\t\t\t${dynamic_routes.join(';\n\t\t\t')}\n\t\t};`,
|
|
242
287
|
`\t\tLayoutParams(): {\n\t\t\t${layouts.join(';\n\t\t\t')}\n\t\t};`,
|
|
243
288
|
`\t\tPath(): ${Array.from(pathnames).join(' | ')};`,
|
|
@@ -85,7 +85,8 @@ export function write_tsconfig(kit, root) {
|
|
|
85
85
|
* @param {ValidatedKitConfig['typescript']['config']} [transform] TODO get rid of this
|
|
86
86
|
*/
|
|
87
87
|
function write_parent_tsconfig(root, dir, id, config, example, transform) {
|
|
88
|
-
|
|
88
|
+
// simplified tsconfig resolvers (e.g. Playwright's) only find `${id}.json`, not `${id}/tsconfig.json`
|
|
89
|
+
const out_file = path.join(root, `node_modules/${id}.json`);
|
|
89
90
|
|
|
90
91
|
let normalized = normalize_config(out_file, config);
|
|
91
92
|
normalized = transform?.(normalized) ?? normalized;
|
|
@@ -5,6 +5,7 @@ import { rimraf, walk, resolve_entry } from '../../../utils/filesystem.js';
|
|
|
5
5
|
import { compact } from '../../../utils/array.js';
|
|
6
6
|
import { posixify } from '../../../utils/os.js';
|
|
7
7
|
import { ts } from '../ts.js';
|
|
8
|
+
import { is_page_route } from '../create_manifest_data/index.js';
|
|
8
9
|
const remove_relative_parent_traversals = (/** @type {string} */ path) =>
|
|
9
10
|
path.replace(/\.\.\//g, '');
|
|
10
11
|
const is_whitespace = (/** @type {string} */ char) => /\s/.test(char);
|
|
@@ -278,7 +279,9 @@ function update_types(config, routes, route, root, to_delete = new Set()) {
|
|
|
278
279
|
let all_pages_have_load = true;
|
|
279
280
|
/** @type {import('types').RouteParam[]} */
|
|
280
281
|
const layout_params = [];
|
|
281
|
-
|
|
282
|
+
// a layout can live in a directory that has no `+page` of its own, in which case its own id
|
|
283
|
+
// is never the matched route — a request to a colocated `+server` doesn't execute layouts
|
|
284
|
+
const ids = is_page_route(route) ? ['RouteId'] : [];
|
|
282
285
|
|
|
283
286
|
route.layout.child_pages?.forEach((page) => {
|
|
284
287
|
const leaf = routes.get(page);
|
|
@@ -312,7 +315,7 @@ function update_types(config, routes, route, root, to_delete = new Set()) {
|
|
|
312
315
|
ids.push('null');
|
|
313
316
|
}
|
|
314
317
|
|
|
315
|
-
declarations.push(`type LayoutRouteId = ${ids.join(' | ')}`);
|
|
318
|
+
declarations.push(`type LayoutRouteId = ${ids.join(' | ') || 'never'}`);
|
|
316
319
|
|
|
317
320
|
declarations.push(
|
|
318
321
|
'type LayoutParams = RouteParams & ' + generate_params_type(layout_params, outdir, config)
|
|
@@ -137,14 +137,9 @@ export function getRequest({ request, base, bodySizeLimit }) {
|
|
|
137
137
|
}
|
|
138
138
|
|
|
139
139
|
const controller = new AbortController();
|
|
140
|
-
|
|
141
|
-
// see https://github.com/nodejs/node/blob/5cf3c3e24c7257a0c6192ed8ef71efec8ddac22b/lib/internal/streams/readable.js#L1443-L1453
|
|
142
|
-
let errored = false;
|
|
143
|
-
let end_emitted = false;
|
|
144
|
-
request.once('error', () => (errored = true));
|
|
145
|
-
request.once('end', () => (end_emitted = true));
|
|
140
|
+
|
|
146
141
|
request.once('close', () => {
|
|
147
|
-
if (
|
|
142
|
+
if (request.readableAborted) {
|
|
148
143
|
controller.abort();
|
|
149
144
|
}
|
|
150
145
|
});
|
package/src/exports/public.d.ts
CHANGED
|
@@ -253,8 +253,9 @@ export interface Builder {
|
|
|
253
253
|
/**
|
|
254
254
|
* Compress files in `directory` with gzip and brotli, where appropriate. Generates `.gz` and `.br` files alongside the originals.
|
|
255
255
|
* @param {string} directory The directory containing the files to be compressed
|
|
256
|
+
* @returns an array of the files in `directory` that were compressed
|
|
256
257
|
*/
|
|
257
|
-
compress: (directory: string) => Promise<
|
|
258
|
+
compress: (directory: string) => Promise<string[]>;
|
|
258
259
|
}
|
|
259
260
|
|
|
260
261
|
/**
|
|
@@ -862,7 +863,7 @@ export interface KitConfig {
|
|
|
862
863
|
* A function that allows you to edit the generated `tsconfig.json`. You can mutate the config (recommended) or return a new one.
|
|
863
864
|
* This is useful for extending a shared `tsconfig.json` in a monorepo root, for example.
|
|
864
865
|
*
|
|
865
|
-
* Note that any paths configured here should be relative to the generated config file, which is written to `node_modules/$app/tsconfig
|
|
866
|
+
* Note that any paths configured here should be relative to the generated config file, which is written to `node_modules/$app/tsconfig.json`.
|
|
866
867
|
*
|
|
867
868
|
* @default (config) => config
|
|
868
869
|
* @since 1.3.0
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @import { EnvVarConfig, KitConfig } from '@sveltejs/kit' */
|
|
2
2
|
/** @import { Options, SvelteConfig } from '@sveltejs/vite-plugin-svelte' */
|
|
3
3
|
/** @import { PreprocessorGroup } from 'svelte/compiler' */
|
|
4
|
-
/** @import { BuildData, ManifestData, Prerendered, RemoteChunk, RemoteInternals, ServerMetadata, ValidatedConfig, ValidatedKitConfig } from 'types' */
|
|
4
|
+
/** @import { Asset, BuildData, ManifestData, Prerendered, RemoteChunk, RemoteInternals, RouteData, ServerMetadata, ValidatedConfig, ValidatedKitConfig } from 'types' */
|
|
5
5
|
/** @import { Manifest, Plugin, ResolvedConfig, Rolldown, UserConfig, ViteDevServer } from 'vite' */
|
|
6
6
|
import fs from 'node:fs';
|
|
7
7
|
import path from 'node:path';
|
|
@@ -46,6 +46,11 @@ import analyse from '../../core/postbuild/analyse.js';
|
|
|
46
46
|
import { s } from '../../utils/misc.js';
|
|
47
47
|
import { hash } from '../../utils/hash.js';
|
|
48
48
|
import { dedent } from '../../core/sync/utils.js';
|
|
49
|
+
import {
|
|
50
|
+
is_app_route,
|
|
51
|
+
is_endpoint_route,
|
|
52
|
+
is_page_route
|
|
53
|
+
} from '../../core/sync/create_manifest_data/index.js';
|
|
49
54
|
import { get_import_aliases, get_hash_import_keys } from '../../utils/imports.js';
|
|
50
55
|
import {
|
|
51
56
|
app_env_private,
|
|
@@ -1121,7 +1126,7 @@ function kit({ svelte_config }) {
|
|
|
1121
1126
|
];
|
|
1122
1127
|
|
|
1123
1128
|
export const assets = [
|
|
1124
|
-
${manifest_data.assets
|
|
1129
|
+
${stringify_assets(manifest_data.assets)}
|
|
1125
1130
|
];
|
|
1126
1131
|
|
|
1127
1132
|
export const prerendered = [
|
|
@@ -1129,7 +1134,7 @@ function kit({ svelte_config }) {
|
|
|
1129
1134
|
];
|
|
1130
1135
|
|
|
1131
1136
|
export const routes = [
|
|
1132
|
-
${manifest_data.routes
|
|
1137
|
+
${stringify_routes(manifest_data.routes)}
|
|
1133
1138
|
];
|
|
1134
1139
|
`;
|
|
1135
1140
|
}
|
|
@@ -1570,7 +1575,7 @@ function kit({ svelte_config }) {
|
|
|
1570
1575
|
// the client build and after prerendering respectively.
|
|
1571
1576
|
replace_manifest_placeholder_variables(server_chunks, `${out}/server`, {
|
|
1572
1577
|
assets: manifest_data.assets.map((asset) => ({ path: asset.file })),
|
|
1573
|
-
routes: manifest_data.routes
|
|
1578
|
+
routes: get_manifest_routes(manifest_data.routes)
|
|
1574
1579
|
});
|
|
1575
1580
|
|
|
1576
1581
|
const verbose = builder.config.logLevel === 'info';
|
|
@@ -1732,7 +1737,7 @@ function kit({ svelte_config }) {
|
|
|
1732
1737
|
replace_manifest_placeholder_variables(client_chunks, `${out}/client`, {
|
|
1733
1738
|
immutable,
|
|
1734
1739
|
assets: manifest_data.assets.map((asset) => ({ path: asset.file })),
|
|
1735
|
-
routes: manifest_data.routes
|
|
1740
|
+
routes: get_manifest_routes(manifest_data.routes)
|
|
1736
1741
|
});
|
|
1737
1742
|
|
|
1738
1743
|
// Now that the client build is done, replace the `build` sentinel
|
|
@@ -2112,6 +2117,38 @@ function comparable(value) {
|
|
|
2112
2117
|
return process.platform === 'win32' ? normalized.toLowerCase() : normalized;
|
|
2113
2118
|
}
|
|
2114
2119
|
|
|
2120
|
+
/**
|
|
2121
|
+
* @param {Asset[] | undefined} assets
|
|
2122
|
+
* @returns {string}
|
|
2123
|
+
*/
|
|
2124
|
+
function stringify_assets(assets) {
|
|
2125
|
+
return assets?.map((asset) => s({ path: asset.file })).join(',\n') ?? '';
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2128
|
+
/**
|
|
2129
|
+
* @param {RouteData[] | undefined} routes
|
|
2130
|
+
* @returns {Array<{ id: string; page: boolean; endpoint: boolean }>}
|
|
2131
|
+
*/
|
|
2132
|
+
function get_manifest_routes(routes) {
|
|
2133
|
+
return (
|
|
2134
|
+
routes?.filter(is_app_route).map((route) => ({
|
|
2135
|
+
id: route.id,
|
|
2136
|
+
page: is_page_route(route),
|
|
2137
|
+
endpoint: is_endpoint_route(route)
|
|
2138
|
+
})) ?? []
|
|
2139
|
+
);
|
|
2140
|
+
}
|
|
2141
|
+
|
|
2142
|
+
/**
|
|
2143
|
+
* @param {RouteData[] | undefined} routes
|
|
2144
|
+
* @returns {string}
|
|
2145
|
+
*/
|
|
2146
|
+
function stringify_routes(routes) {
|
|
2147
|
+
return get_manifest_routes(routes)
|
|
2148
|
+
.map((route) => s(route))
|
|
2149
|
+
.join(',\n');
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2115
2152
|
/**
|
|
2116
2153
|
* Creates the `$app/manifest` data module. During development, real values
|
|
2117
2154
|
* are emitted for `assets` and `routes` (the only data known at that point).
|
|
@@ -2144,20 +2181,17 @@ const create_manifest_data_module = (is_build, manifest_data) => {
|
|
|
2144
2181
|
// In dev, `manifest_data` may not be set yet on the very first load,
|
|
2145
2182
|
// but `configureServer` (which calls `sync.create`) runs before any
|
|
2146
2183
|
// module is served, so it will be set by the time this is called.
|
|
2147
|
-
const routes = manifest_data?.routes.map((route) => s({ id: route.id })).join(',\n') ?? '';
|
|
2148
|
-
const assets = manifest_data?.assets.map((asset) => s({ path: asset.file })).join(',\n') ?? '';
|
|
2149
|
-
|
|
2150
2184
|
return dedent`
|
|
2151
2185
|
// empty during dev
|
|
2152
2186
|
export const immutable = [];
|
|
2153
2187
|
export const prerendered = [];
|
|
2154
2188
|
|
|
2155
2189
|
export const assets = [
|
|
2156
|
-
${assets}
|
|
2190
|
+
${stringify_assets(manifest_data?.assets)}
|
|
2157
2191
|
];
|
|
2158
2192
|
|
|
2159
2193
|
export const routes = [
|
|
2160
|
-
${routes}
|
|
2194
|
+
${stringify_routes(manifest_data?.routes)}
|
|
2161
2195
|
];
|
|
2162
2196
|
`;
|
|
2163
2197
|
};
|
|
@@ -2173,7 +2207,7 @@ const create_manifest_data_module = (is_build, manifest_data) => {
|
|
|
2173
2207
|
* immutable?: Array<{ path: string }>;
|
|
2174
2208
|
* assets?: Array<{ path: string }>;
|
|
2175
2209
|
* prerendered?: Array<{ path: string }>;
|
|
2176
|
-
* routes?: Array<{ id: string }>;
|
|
2210
|
+
* routes?: Array<{ id: string; page: boolean; endpoint: boolean }>;
|
|
2177
2211
|
* }} values
|
|
2178
2212
|
*/
|
|
2179
2213
|
const replace_manifest_placeholder_variables = (chunks, output_dir, values) => {
|
|
@@ -2,6 +2,7 @@ import path from 'node:path';
|
|
|
2
2
|
import { posixify } from '../../utils/os.js';
|
|
3
3
|
import { negotiate } from '../../utils/http.js';
|
|
4
4
|
import { escape_html } from '../../utils/escape.js';
|
|
5
|
+
import { escape_for_regexp } from '../../utils/regex.js';
|
|
5
6
|
import { stackless } from '../../utils/error.js';
|
|
6
7
|
import { dedent } from '../../core/sync/utils.js';
|
|
7
8
|
import { app_server, app_env_private, sveltekit_env_private } from './module_ids.js';
|
|
@@ -44,13 +45,6 @@ export function get_config_aliases(config, root) {
|
|
|
44
45
|
return alias;
|
|
45
46
|
}
|
|
46
47
|
|
|
47
|
-
/**
|
|
48
|
-
* @param {string} str
|
|
49
|
-
*/
|
|
50
|
-
function escape_for_regexp(str) {
|
|
51
|
-
return str.replace(/[.*+?^${}()|[\]\\]/g, (match) => '\\' + match);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
48
|
/**
|
|
55
49
|
* Silently respond with 404 for Chrome DevTools workspaces request.
|
|
56
50
|
* Chrome always requests this at the root, regardless of base path.
|
|
@@ -575,12 +575,6 @@ function create_live_query_resource(__, payload, event, state, get_generator) {
|
|
|
575
575
|
|
|
576
576
|
return Promise.resolve();
|
|
577
577
|
},
|
|
578
|
-
/** @ts-expect-error This method no longer exists */
|
|
579
|
-
run() {
|
|
580
|
-
throw new Error(
|
|
581
|
-
'`.run()` has been removed from live queries. Use `for await (const value of liveQuery())` instead.'
|
|
582
|
-
);
|
|
583
|
-
},
|
|
584
578
|
/** @type {Promise<any>['then']} */
|
|
585
579
|
then(onfulfilled, onrejected) {
|
|
586
580
|
return get_promise().then(onfulfilled, onrejected);
|