@sveltejs/kit 3.0.0-next.13 → 3.0.0-next.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -4
- package/src/cli.js +8 -5
- package/src/core/adapt/builder.js +20 -10
- package/src/core/config/index.js +4 -5
- package/src/core/env.js +3 -3
- 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 +18 -13
- 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/sync.js +3 -2
- package/src/core/sync/utils.js +2 -2
- package/src/core/sync/write_app_types.js +72 -27
- package/src/core/sync/write_tsconfig/index.js +73 -54
- package/src/core/sync/write_tsconfig/utils.js +0 -61
- package/src/core/sync/write_tsconfig/validate.js +128 -0
- package/src/core/sync/write_types/index.js +7 -4
- package/src/exports/node/index.js +2 -7
- package/src/exports/public.d.ts +25 -18
- package/src/exports/vite/build/build_server.js +2 -3
- package/src/exports/vite/dev/index.js +44 -36
- package/src/exports/vite/index.js +91 -16
- package/src/exports/vite/utils.js +62 -15
- package/src/runner.js +4 -2
- package/src/runtime/app/forms.js +4 -7
- package/src/runtime/app/internal/transport.js +53 -0
- package/src/runtime/app/paths/client.js +2 -2
- package/src/runtime/app/paths/internal/client.js +2 -2
- package/src/runtime/app/server/remote/prerender.js +6 -10
- package/src/runtime/app/server/remote/query.js +3 -9
- package/src/runtime/app/server/remote/requested.js +2 -2
- package/src/runtime/app/server/remote/shared.js +1 -16
- package/src/runtime/client/client.js +177 -63
- package/src/runtime/client/fetcher.js +2 -13
- package/src/runtime/client/parse.js +1 -1
- package/src/runtime/client/remote-functions/command.svelte.js +1 -2
- package/src/runtime/client/remote-functions/form.svelte.js +3 -7
- package/src/runtime/client/remote-functions/prerender.svelte.js +2 -2
- package/src/runtime/client/remote-functions/query/index.js +1 -1
- package/src/runtime/client/remote-functions/query/proxy.js +2 -2
- package/src/runtime/client/remote-functions/query-batch.svelte.js +1 -1
- package/src/runtime/client/remote-functions/query-live/proxy.js +2 -12
- 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 +44 -1
- package/src/runtime/server/data/index.js +5 -8
- package/src/runtime/server/dev.js +22 -0
- package/src/runtime/server/endpoint.js +3 -4
- package/src/runtime/server/fetch.js +25 -30
- package/src/runtime/server/index.js +64 -46
- package/src/runtime/server/internal.js +12 -5
- package/src/runtime/server/page/actions.js +18 -43
- package/src/runtime/server/page/crypto.js +2 -2
- package/src/runtime/server/page/csp.js +2 -1
- package/src/runtime/server/page/data_serializer.js +12 -13
- package/src/runtime/server/page/index.js +16 -32
- package/src/runtime/server/page/load_data.js +28 -44
- package/src/runtime/server/page/render.js +28 -12
- package/src/runtime/server/page/respond_with_error.js +8 -20
- package/src/runtime/server/page/serialize_data.js +2 -13
- package/src/runtime/server/page/server_routing.js +58 -9
- package/src/runtime/server/remote-functions.js +11 -15
- package/src/runtime/server/respond.js +44 -56
- package/src/runtime/server/state.js +60 -0
- package/src/runtime/server/utils.js +0 -20
- package/src/runtime/shared.js +20 -40
- 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 +47 -53
- package/src/utils/filesystem.js +1 -23
- 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 +98 -28
- package/types/index.d.ts.map +1 -1
- package/src/exports/node/polyfills.js +0 -30
- package/src/runtime/server/app.js +0 -9
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.16",
|
|
4
4
|
"description": "SvelteKit is the fastest way to build Svelte apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -30,12 +30,12 @@
|
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"@opentelemetry/api": "^1.9.0",
|
|
33
|
-
"@playwright/test": "
|
|
33
|
+
"@playwright/test": "^1.62.0",
|
|
34
34
|
"@sveltejs/vite-plugin-svelte": "^7.0.0",
|
|
35
35
|
"@types/connect": "^3.4.38",
|
|
36
36
|
"@types/node": "^22.19.19",
|
|
37
37
|
"dts-buddy": "^0.8.3",
|
|
38
|
-
"jsdom": "^
|
|
38
|
+
"jsdom": "^30.0.0",
|
|
39
39
|
"rolldown": "^1.2.0",
|
|
40
40
|
"svelte": "^5.56.3",
|
|
41
41
|
"svelte-preprocess": "^6.0.5",
|
|
@@ -71,6 +71,9 @@
|
|
|
71
71
|
"svelte-kit.js"
|
|
72
72
|
],
|
|
73
73
|
"imports": {
|
|
74
|
+
"#app/internal/transport": {
|
|
75
|
+
"default": "./src/runtime/app/internal/transport.js"
|
|
76
|
+
},
|
|
74
77
|
"#app/paths": {
|
|
75
78
|
"workerd": "./src/runtime/app/paths/server.js",
|
|
76
79
|
"browser": "./src/runtime/app/paths/client.js",
|
|
@@ -127,7 +130,7 @@
|
|
|
127
130
|
},
|
|
128
131
|
"types": "types/index.d.ts",
|
|
129
132
|
"engines": {
|
|
130
|
-
"node": ">=22"
|
|
133
|
+
"node": ">=22.17"
|
|
131
134
|
},
|
|
132
135
|
"scripts": {
|
|
133
136
|
"lint": "prettier --config ../../.prettierrc --check .",
|
package/src/cli.js
CHANGED
|
@@ -2,8 +2,9 @@ import fs from 'node:fs';
|
|
|
2
2
|
import process from 'node:process';
|
|
3
3
|
import { parseArgs, styleText } from 'node:util';
|
|
4
4
|
import { extract_svelte_config, load_vite_config } from './core/config/index.js';
|
|
5
|
-
import { coalesce_to_error } from './utils/error.js';
|
|
6
5
|
import { resolve_explicit_env_entry } from './core/env.js';
|
|
6
|
+
import { coalesce_to_error } from './utils/error.js';
|
|
7
|
+
import { import_peer } from './utils/import.js';
|
|
7
8
|
|
|
8
9
|
/** @param {unknown} e */
|
|
9
10
|
function handle_error(e) {
|
|
@@ -75,10 +76,10 @@ if (!command) {
|
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
if (command === 'sync') {
|
|
78
|
-
// create placeholder node_modules/$app/tsconfig
|
|
79
|
+
// create placeholder node_modules/$app/tsconfig.json if necessary, to squelch warnings.
|
|
79
80
|
// this isn't bulletproof — if someone has some esoteric config, it will continue
|
|
80
81
|
// to harmlessly warn — but we handle the 90% case and clean up after ourselves
|
|
81
|
-
const dir = 'node_modules/$app
|
|
82
|
+
const dir = 'node_modules/$app';
|
|
82
83
|
const base_tsconfig = `${dir}/tsconfig.json`;
|
|
83
84
|
const base_tsconfig_json = '{}';
|
|
84
85
|
|
|
@@ -96,14 +97,16 @@ if (command === 'sync') {
|
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
try {
|
|
99
|
-
const
|
|
100
|
+
const vite = /** @type {import('vite')} */ (await import_peer('vite', process.cwd()));
|
|
101
|
+
|
|
102
|
+
const vite_config = await load_vite_config(values.config, vite);
|
|
100
103
|
const sveltekit_config = extract_svelte_config(vite_config);
|
|
101
104
|
|
|
102
105
|
const sync = await import('./core/sync/sync.js');
|
|
103
106
|
sync.all_types(sveltekit_config, vite_config.root);
|
|
104
107
|
|
|
105
108
|
const explicit_env_entry = resolve_explicit_env_entry(sveltekit_config.kit);
|
|
106
|
-
await sync.env(sveltekit_config.kit, explicit_env_entry, vite_config.root, values.mode);
|
|
109
|
+
await sync.env(vite, sveltekit_config.kit, explicit_env_entry, vite_config.root, values.mode);
|
|
107
110
|
} catch (error) {
|
|
108
111
|
handle_error(error);
|
|
109
112
|
} finally {
|
|
@@ -5,12 +5,19 @@
|
|
|
5
5
|
/** @import { RouteData, ValidatedConfig, BuildData, ServerMetadata, ServerMetadataRoute, Prerendered, PrerenderMap, Logger, RemoteChunk } from 'types' */
|
|
6
6
|
import { loadEnv } from 'vite';
|
|
7
7
|
import * as devalue from 'devalue';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
createReadStream,
|
|
10
|
+
createWriteStream,
|
|
11
|
+
existsSync,
|
|
12
|
+
mkdirSync,
|
|
13
|
+
rmSync,
|
|
14
|
+
statSync
|
|
15
|
+
} from 'node:fs';
|
|
9
16
|
import { extname, resolve, join, dirname, relative } from 'node:path';
|
|
10
17
|
import { pipeline } from 'node:stream';
|
|
11
18
|
import { promisify } from 'node:util';
|
|
12
19
|
import zlib from 'node:zlib';
|
|
13
|
-
import { copy
|
|
20
|
+
import { copy } from '../../utils/filesystem.js';
|
|
14
21
|
import { posixify } from '../../utils/os.js';
|
|
15
22
|
import { generate_manifest } from '../generate_manifest/index.js';
|
|
16
23
|
import { get_route_segments } from '../../utils/routing.js';
|
|
@@ -99,8 +106,8 @@ export function create_builder({
|
|
|
99
106
|
|
|
100
107
|
return {
|
|
101
108
|
log,
|
|
102
|
-
rimraf,
|
|
103
|
-
mkdirp,
|
|
109
|
+
rimraf: (dir) => rmSync(dir, { force: true, recursive: true }),
|
|
110
|
+
mkdirp: (dir) => mkdirSync(dir, { recursive: true }),
|
|
104
111
|
copy,
|
|
105
112
|
|
|
106
113
|
config,
|
|
@@ -109,16 +116,19 @@ export function create_builder({
|
|
|
109
116
|
|
|
110
117
|
async compress(directory) {
|
|
111
118
|
if (!existsSync(directory)) {
|
|
112
|
-
return;
|
|
119
|
+
return [];
|
|
113
120
|
}
|
|
114
121
|
|
|
115
|
-
const files = list_files(directory, (file) => extensions.includes(extname(file)))
|
|
116
|
-
(file) => resolve(directory, file)
|
|
117
|
-
);
|
|
122
|
+
const files = list_files(directory, (file) => extensions.includes(extname(file)));
|
|
118
123
|
|
|
119
124
|
await Promise.all(
|
|
120
|
-
files.flatMap((file) =>
|
|
125
|
+
files.flatMap((file) => {
|
|
126
|
+
const abs = resolve(directory, file);
|
|
127
|
+
return [compress_file(abs, 'gz'), compress_file(abs, 'br')];
|
|
128
|
+
})
|
|
121
129
|
);
|
|
130
|
+
|
|
131
|
+
return files;
|
|
122
132
|
},
|
|
123
133
|
|
|
124
134
|
findServerAssets(route_data) {
|
|
@@ -268,7 +278,7 @@ export function create_builder({
|
|
|
268
278
|
exports: module.exports
|
|
269
279
|
});
|
|
270
280
|
|
|
271
|
-
|
|
281
|
+
rmSync(entrypoint, { force: true, recursive: true });
|
|
272
282
|
write(entrypoint, facade);
|
|
273
283
|
}
|
|
274
284
|
};
|
package/src/core/config/index.js
CHANGED
|
@@ -120,13 +120,12 @@ export function load_error_page(config) {
|
|
|
120
120
|
|
|
121
121
|
/**
|
|
122
122
|
* @param {string} [config]
|
|
123
|
+
* @param {typeof import('vite')} [vite]
|
|
123
124
|
*/
|
|
124
|
-
export async function load_vite_config(config) {
|
|
125
|
-
|
|
126
|
-
await import_peer('vite', process.cwd())
|
|
127
|
-
);
|
|
125
|
+
export async function load_vite_config(config, vite) {
|
|
126
|
+
vite ??= /** @type {import('vite')} */ (await import_peer('vite', process.cwd()));
|
|
128
127
|
|
|
129
|
-
return resolveConfig({ configFile: config }, 'build', process.env.MODE ?? 'production');
|
|
128
|
+
return vite.resolveConfig({ configFile: config }, 'build', process.env.MODE ?? 'production');
|
|
130
129
|
}
|
|
131
130
|
|
|
132
131
|
/**
|
package/src/core/env.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
/** @import { EnvVarConfig } from '@sveltejs/kit' */
|
|
3
3
|
/** @import { ValidatedKitConfig } from 'types' */
|
|
4
4
|
import path from 'node:path';
|
|
5
|
-
import * as vite from 'vite';
|
|
6
5
|
import * as devalue from 'devalue';
|
|
7
6
|
import { GENERATED_COMMENT } from '../constants.js';
|
|
8
7
|
import { dedent } from './sync/utils.js';
|
|
@@ -25,13 +24,14 @@ export function resolve_explicit_env_entry(config) {
|
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
/**
|
|
27
|
+
* @param {typeof import('vite')} vite
|
|
28
28
|
* @param {ValidatedKitConfig} kit
|
|
29
29
|
* @param {string | null} file
|
|
30
30
|
* @param {string} root
|
|
31
31
|
* @param {string} mode
|
|
32
32
|
* @returns {Promise<Record<string, EnvVarConfig<any>> | null>}
|
|
33
33
|
*/
|
|
34
|
-
export async function load_explicit_env(kit, file, root, mode) {
|
|
34
|
+
export async function load_explicit_env(vite, kit, file, root, mode) {
|
|
35
35
|
if (!file) return null;
|
|
36
36
|
|
|
37
37
|
const server = await vite.createServer({
|
|
@@ -53,7 +53,7 @@ export async function load_explicit_env(kit, file, root, mode) {
|
|
|
53
53
|
/** @type {Record<string, EnvVarConfig<any>>} */
|
|
54
54
|
let variables;
|
|
55
55
|
|
|
56
|
-
const runner = get_runner(server);
|
|
56
|
+
const runner = get_runner(vite, server);
|
|
57
57
|
|
|
58
58
|
/** @type {import('../runtime/app/env/internal.js')} */ (
|
|
59
59
|
await runner.import(`${runtime_directory}/app/env/internal.js`)
|
|
@@ -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
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
|
-
import {
|
|
4
|
+
import { walk } from '../../utils/filesystem.js';
|
|
5
5
|
import { posixify } from '../../utils/os.js';
|
|
6
6
|
import { noop } from '../../utils/functions.js';
|
|
7
7
|
import { decode_uri, is_root_relative, resolve } from '../../utils/url.js';
|
|
@@ -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
|
|
|
@@ -156,7 +157,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
156
157
|
const file = output_filename('/', true);
|
|
157
158
|
const dest = `${config.outDir}/output/prerendered/pages/${file}`;
|
|
158
159
|
|
|
159
|
-
|
|
160
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
160
161
|
writeFileSync(dest, fallback);
|
|
161
162
|
|
|
162
163
|
prerendered.pages.set('/', { file });
|
|
@@ -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(
|
|
@@ -471,7 +480,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
471
480
|
}
|
|
472
481
|
|
|
473
482
|
if (!headers['x-sveltekit-normalize']) {
|
|
474
|
-
|
|
483
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
475
484
|
|
|
476
485
|
writeFileSync(
|
|
477
486
|
dest,
|
|
@@ -517,7 +526,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
517
526
|
);
|
|
518
527
|
}
|
|
519
528
|
|
|
520
|
-
|
|
529
|
+
mkdirSync(dir, { recursive: true });
|
|
521
530
|
|
|
522
531
|
writeFileSync(dest, body);
|
|
523
532
|
written.add(file);
|
|
@@ -620,14 +629,10 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
620
629
|
}
|
|
621
630
|
}
|
|
622
631
|
|
|
623
|
-
const transport = (await internal.get_hooks()).transport ?? {};
|
|
624
632
|
for (const internals of prerender_functions) {
|
|
625
633
|
if (internals.has_arg) {
|
|
626
634
|
for (const arg of (await internals.inputs?.()) ?? []) {
|
|
627
|
-
void enqueue(
|
|
628
|
-
null,
|
|
629
|
-
remote_prefix + internals.id + '/' + stringify_remote_arg(arg, transport)
|
|
630
|
-
);
|
|
635
|
+
void enqueue(null, remote_prefix + internals.id + '/' + stringify_remote_arg(arg));
|
|
631
636
|
}
|
|
632
637
|
} else {
|
|
633
638
|
void enqueue(null, remote_prefix + internals.id);
|
|
@@ -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;
|
package/src/core/sync/sync.js
CHANGED
|
@@ -89,13 +89,14 @@ export function all_types(config, root) {
|
|
|
89
89
|
|
|
90
90
|
/**
|
|
91
91
|
* Generate modules and types for explicit env vars
|
|
92
|
+
* @param {typeof import('vite')} vite
|
|
92
93
|
* @param {import('types').ValidatedKitConfig} kit
|
|
93
94
|
* @param {string | null} entry
|
|
94
95
|
* @param {string} root The Vite root
|
|
95
96
|
* @param {string} mode The Vite mode
|
|
96
97
|
*/
|
|
97
|
-
export async function env(kit, entry, root, mode) {
|
|
98
|
-
const env_config = await load_explicit_env(kit, entry, root, mode);
|
|
98
|
+
export async function env(vite, kit, entry, root, mode) {
|
|
99
|
+
const env_config = await load_explicit_env(vite, kit, entry, root, mode);
|
|
99
100
|
|
|
100
101
|
write_env(entry, env_config, root);
|
|
101
102
|
|
package/src/core/sync/utils.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { styleText } from 'node:util';
|
|
4
|
-
import {
|
|
4
|
+
import { resolve_entry } from '../../utils/filesystem.js';
|
|
5
5
|
|
|
6
6
|
/** @type {Map<string, string>} */
|
|
7
7
|
const previous_contents = new Map();
|
|
@@ -22,7 +22,7 @@ export function write_if_changed(file, code) {
|
|
|
22
22
|
*/
|
|
23
23
|
export function write(file, code) {
|
|
24
24
|
previous_contents.set(file, code);
|
|
25
|
-
|
|
25
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
26
26
|
fs.writeFileSync(file, code);
|
|
27
27
|
}
|
|
28
28
|
|
|
@@ -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(' | ')};`,
|