@sveltejs/kit 3.0.0-next.1 → 3.0.0-next.11
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 +33 -21
- package/src/constants.js +2 -0
- package/src/core/adapt/builder.js +32 -49
- package/src/core/adapt/index.js +1 -4
- package/src/core/config/index.js +137 -71
- package/src/core/config/options.js +236 -244
- package/src/core/config/types.d.ts +1 -1
- package/src/core/env.js +121 -5
- package/src/core/generate_manifest/index.js +12 -15
- package/src/core/postbuild/analyse.js +7 -19
- package/src/core/postbuild/crawl.js +22 -6
- package/src/core/postbuild/fallback.js +2 -1
- package/src/core/postbuild/prerender.js +114 -48
- package/src/core/postbuild/queue.js +2 -1
- package/src/core/sync/create_manifest_data/index.js +53 -50
- package/src/core/sync/sync.js +0 -2
- package/src/core/sync/write_client_manifest.js +8 -15
- package/src/core/sync/write_env.js +2 -1
- package/src/core/sync/write_non_ambient.js +12 -9
- package/src/core/sync/write_server.js +14 -15
- package/src/core/sync/write_tsconfig.js +16 -8
- package/src/core/sync/write_tsconfig_test/package.json +7 -0
- package/src/core/sync/write_types/index.js +28 -24
- package/src/core/utils.js +30 -5
- package/src/exports/env/index.js +77 -0
- package/src/exports/hooks/index.js +3 -9
- package/src/exports/hooks/sequence.js +3 -2
- package/src/exports/index.js +35 -13
- package/src/exports/internal/client.js +5 -0
- package/src/exports/internal/env.js +8 -5
- package/src/exports/internal/index.js +1 -90
- package/src/exports/internal/{event.js → server/event.js} +1 -2
- package/src/exports/internal/server/index.js +33 -0
- package/src/exports/internal/shared.js +89 -0
- package/src/exports/node/index.js +62 -15
- package/src/exports/params.js +68 -0
- package/src/exports/public.d.ts +363 -189
- package/src/exports/url.js +86 -0
- package/src/exports/vite/build/build_server.js +53 -59
- package/src/exports/vite/build/remote.js +18 -11
- package/src/exports/vite/build/utils.js +0 -8
- package/src/exports/vite/dev/index.js +92 -50
- package/src/exports/vite/index.js +903 -681
- package/src/exports/vite/module_ids.js +0 -2
- package/src/exports/vite/preview/index.js +32 -24
- package/src/exports/vite/static_analysis/index.js +2 -4
- package/src/exports/vite/static_analysis/types.d.ts +14 -0
- package/src/exports/vite/utils.js +40 -35
- package/src/runtime/app/env/internal.js +4 -4
- package/src/runtime/app/env/types.d.ts +1 -1
- package/src/runtime/app/environment/index.js +3 -3
- package/src/runtime/app/forms.js +24 -7
- package/src/runtime/app/paths/client.js +4 -10
- package/src/runtime/app/paths/internal/client.js +4 -2
- package/src/runtime/app/paths/internal/server.js +2 -23
- package/src/runtime/app/paths/public.d.ts +0 -28
- package/src/runtime/app/paths/server.js +10 -6
- package/src/runtime/app/server/index.js +1 -1
- package/src/runtime/app/server/remote/command.js +0 -3
- package/src/runtime/app/server/remote/form.js +27 -15
- package/src/runtime/app/server/remote/prerender.js +29 -36
- package/src/runtime/app/server/remote/query.js +101 -99
- package/src/runtime/app/server/remote/requested.js +22 -14
- package/src/runtime/app/server/remote/shared.js +30 -26
- package/src/runtime/app/state/client.js +1 -2
- package/src/runtime/app/stores.js +13 -76
- package/src/runtime/client/bundle.js +1 -1
- package/src/runtime/client/client-entry.js +3 -0
- package/src/runtime/client/client.js +411 -318
- package/src/runtime/client/entry.js +24 -3
- package/src/runtime/client/fetcher.js +3 -2
- package/src/runtime/client/ndjson.js +6 -33
- package/src/runtime/client/payload.js +17 -0
- package/src/runtime/client/remote-functions/cache.svelte.js +3 -1
- package/src/runtime/client/remote-functions/command.svelte.js +7 -32
- package/src/runtime/client/remote-functions/form.svelte.js +183 -112
- package/src/runtime/client/remote-functions/prerender.svelte.js +29 -8
- package/src/runtime/client/remote-functions/query/index.js +7 -14
- package/src/runtime/client/remote-functions/query/instance.svelte.js +63 -18
- package/src/runtime/client/remote-functions/query/proxy.js +3 -3
- package/src/runtime/client/remote-functions/query-batch.svelte.js +60 -68
- package/src/runtime/client/remote-functions/query-live/instance.svelte.js +60 -18
- package/src/runtime/client/remote-functions/query-live/iterator.js +36 -55
- package/src/runtime/client/remote-functions/shared.svelte.js +88 -62
- package/src/runtime/client/sse.js +32 -0
- package/src/runtime/client/state.svelte.js +65 -49
- package/src/runtime/client/stream.js +39 -0
- package/src/runtime/client/types.d.ts +11 -7
- package/src/runtime/client/utils.js +0 -96
- package/src/runtime/components/root.svelte +66 -0
- package/src/runtime/env/dynamic/private.js +7 -0
- package/src/runtime/env/dynamic/public.js +7 -0
- package/src/runtime/env/static/private.js +6 -0
- package/src/runtime/env/static/public.js +6 -0
- package/src/runtime/form-utils.js +100 -22
- package/src/runtime/server/cookie.js +69 -52
- package/src/runtime/server/csrf.js +65 -0
- package/src/runtime/server/data/index.js +15 -19
- package/src/runtime/server/env_module.js +0 -5
- package/src/runtime/server/errors.js +135 -0
- package/src/runtime/server/fetch.js +1 -1
- package/src/runtime/server/index.js +22 -12
- package/src/runtime/server/internal.js +25 -0
- package/src/runtime/server/page/actions.js +43 -27
- package/src/runtime/server/page/data_serializer.js +10 -10
- package/src/runtime/server/page/index.js +12 -17
- package/src/runtime/server/page/load_data.js +2 -2
- package/src/runtime/server/page/render.js +114 -193
- package/src/runtime/server/page/respond_with_error.js +11 -11
- package/src/runtime/server/page/server_routing.js +27 -18
- package/src/runtime/server/remote-functions.js +596 -0
- package/src/runtime/server/respond.js +100 -68
- package/src/runtime/server/sourcemaps.js +183 -0
- package/src/runtime/server/utils.js +2 -134
- package/src/runtime/shared.js +83 -13
- package/src/runtime/telemetry/otel.js +1 -1
- package/src/runtime/types.d.ts +8 -0
- package/src/types/ambient-private.d.ts +2 -0
- package/src/types/ambient.d.ts +10 -5
- package/src/types/global-private.d.ts +13 -25
- package/src/types/internal.d.ts +95 -80
- package/src/types/private.d.ts +41 -1
- package/src/utils/error.js +24 -4
- package/src/utils/escape.js +9 -25
- package/src/utils/features.js +1 -1
- package/src/utils/fork.js +7 -2
- package/src/utils/import.js +6 -1
- package/src/utils/imports.js +83 -0
- package/src/utils/mime.js +9 -0
- package/src/utils/page_nodes.js +3 -5
- package/src/utils/params.js +66 -0
- package/src/utils/routing.js +90 -44
- package/src/utils/shared-iterator.js +5 -0
- package/src/utils/streaming.js +14 -4
- package/src/utils/url.js +20 -2
- package/src/version.js +1 -1
- package/types/index.d.ts +537 -557
- package/types/index.d.ts.map +24 -39
- package/src/core/sync/write_root.js +0 -148
- package/src/exports/internal/server.js +0 -22
- package/src/runtime/server/remote.js +0 -457
- package/src/runtime/shared-server.js +0 -7
- package/src/types/synthetic/$lib.md +0 -5
- /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** @import { Adapter } from '@sveltejs/kit' */
|
|
2
1
|
import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
3
2
|
import { dirname, join } from 'node:path';
|
|
4
3
|
import { pathToFileURL } from 'node:url';
|
|
@@ -17,6 +16,7 @@ import * as devalue from 'devalue';
|
|
|
17
16
|
import { createReadableStream } from '@sveltejs/kit/node';
|
|
18
17
|
import generate_fallback from './fallback.js';
|
|
19
18
|
import { stringify_remote_arg } from '../../runtime/shared.js';
|
|
19
|
+
import { log_response } from '../../exports/vite/utils.js';
|
|
20
20
|
|
|
21
21
|
export default forked(import.meta.url, prerender);
|
|
22
22
|
|
|
@@ -44,37 +44,74 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
44
44
|
/** @type {import('types').ServerInternalModule} */
|
|
45
45
|
const internal = await import(pathToFileURL(`${out}/server/internal.js`).href);
|
|
46
46
|
|
|
47
|
-
/** @type {import('types').ServerModule} */
|
|
48
|
-
const { Server } = await import(pathToFileURL(`${out}/server/index.js`).href);
|
|
49
|
-
|
|
50
47
|
// configure `import { building } from `$app/env` —
|
|
51
48
|
// essential we do this before analysing the code
|
|
52
49
|
internal.set_building();
|
|
53
50
|
internal.set_prerendering();
|
|
54
51
|
|
|
52
|
+
// `set_env` and `Server` live in modules that import the user's `src/env` config. We import them
|
|
53
|
+
// *after* `set_building()` so that `building`-dependent expressions resolve correctly
|
|
54
|
+
/** @type {import('__sveltekit/env')} */
|
|
55
|
+
const { set_env } = await import(pathToFileURL(`${out}/server/env.js`).href);
|
|
56
|
+
set_env(env);
|
|
57
|
+
|
|
58
|
+
/** @type {import('types').ServerModule} */
|
|
59
|
+
const { Server } = await import(pathToFileURL(`${out}/server/index.js`).href);
|
|
60
|
+
|
|
61
|
+
const throw_handled = () => {
|
|
62
|
+
throw new Error('__handled__');
|
|
63
|
+
};
|
|
64
|
+
|
|
55
65
|
/**
|
|
56
66
|
* @template {{message: string}} T
|
|
57
67
|
* @template {Omit<T, 'message'>} K
|
|
58
|
-
* @param {
|
|
59
|
-
* @param {'fail' | 'warn' | 'ignore' | ((details: T) => void)} input
|
|
68
|
+
* @param {string} name
|
|
69
|
+
* @param {'fail' | 'warn' | 'ignore' | undefined | ((details: T) => void)} input
|
|
60
70
|
* @param {(details: K) => string} format
|
|
61
|
-
* @returns {(details: K) => void}
|
|
71
|
+
* @returns {(details: K & { error?: unknown }) => void}
|
|
62
72
|
*/
|
|
63
|
-
function normalise_error_handler(
|
|
73
|
+
function normalise_error_handler(name, input, format) {
|
|
74
|
+
/**
|
|
75
|
+
* @param {any} details
|
|
76
|
+
*/
|
|
77
|
+
function log_failure(details) {
|
|
78
|
+
const message = format(details);
|
|
79
|
+
log.error(`\n${message}\n`);
|
|
80
|
+
}
|
|
81
|
+
|
|
64
82
|
switch (input) {
|
|
65
83
|
case 'fail':
|
|
66
84
|
return (details) => {
|
|
67
|
-
|
|
85
|
+
log_failure(details);
|
|
86
|
+
throw_handled();
|
|
68
87
|
};
|
|
69
88
|
case 'warn':
|
|
70
|
-
return
|
|
71
|
-
log.error(format(details));
|
|
72
|
-
};
|
|
89
|
+
return log_failure;
|
|
73
90
|
case 'ignore':
|
|
74
91
|
return noop;
|
|
92
|
+
case undefined: {
|
|
93
|
+
return (details) => {
|
|
94
|
+
log_failure(details);
|
|
95
|
+
|
|
96
|
+
log.err(
|
|
97
|
+
`To suppress or handle this error, implement \`${name}\` in https://svelte.dev/docs/kit/configuration#prerender\n`
|
|
98
|
+
);
|
|
99
|
+
|
|
100
|
+
throw_handled();
|
|
101
|
+
};
|
|
102
|
+
}
|
|
75
103
|
default:
|
|
76
|
-
|
|
77
|
-
|
|
104
|
+
return (details) => {
|
|
105
|
+
const message = format(details);
|
|
106
|
+
|
|
107
|
+
try {
|
|
108
|
+
// @ts-expect-error TS thinks T might be of a different kind, but it's not
|
|
109
|
+
input({ ...details, message });
|
|
110
|
+
} catch (error) {
|
|
111
|
+
log.prettyError(error, import.meta.dirname);
|
|
112
|
+
throw_handled();
|
|
113
|
+
}
|
|
114
|
+
};
|
|
78
115
|
}
|
|
79
116
|
}
|
|
80
117
|
|
|
@@ -105,12 +142,14 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
105
142
|
|
|
106
143
|
const config = extract_svelte_config(vite_config).kit;
|
|
107
144
|
|
|
145
|
+
const prerender_origin = config.paths.origin || 'http://sveltekit-prerender';
|
|
146
|
+
|
|
108
147
|
if (hash) {
|
|
109
148
|
const fallback = await generate_fallback({
|
|
110
149
|
manifest_path,
|
|
111
150
|
env,
|
|
112
151
|
out_dir: config.outDir,
|
|
113
|
-
origin:
|
|
152
|
+
origin: prerender_origin,
|
|
114
153
|
assets: config.files.assets
|
|
115
154
|
});
|
|
116
155
|
|
|
@@ -125,13 +164,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
125
164
|
return { prerendered, prerender_map };
|
|
126
165
|
}
|
|
127
166
|
|
|
128
|
-
|
|
129
|
-
/** @type {Adapter | undefined} */
|
|
130
|
-
const adapter = vite_config.plugins.find(
|
|
131
|
-
(plugin) => plugin.name === 'vite-plugin-sveltekit-adapter'
|
|
132
|
-
)?.api?.adapter;
|
|
133
|
-
|
|
134
|
-
const emulator = await adapter?.emulate?.();
|
|
167
|
+
const emulator = await config.adapter?.emulate?.();
|
|
135
168
|
|
|
136
169
|
/** @type {import('types').Logger} */
|
|
137
170
|
const log = logger({ verbose });
|
|
@@ -140,43 +173,58 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
140
173
|
const saved = new Map();
|
|
141
174
|
|
|
142
175
|
const handle_http_error = normalise_error_handler(
|
|
143
|
-
|
|
176
|
+
'handleHttpError',
|
|
144
177
|
config.prerender.handleHttpError,
|
|
145
178
|
({ status, path, referrer, referenceType }) => {
|
|
146
|
-
|
|
147
|
-
status === 404 && !path.startsWith(config.paths.base)
|
|
148
|
-
? `${path} does not begin with \`base\`, which is configured in \`paths.base\` and can be imported from \`$app/paths\` - see https://svelte.dev/docs/kit/configuration#paths for more info`
|
|
149
|
-
: path;
|
|
179
|
+
let message = `Failed to prerender ${path}`;
|
|
150
180
|
|
|
151
|
-
|
|
181
|
+
if (status === 404) {
|
|
182
|
+
if (!path.startsWith(config.paths.base)) {
|
|
183
|
+
message = referrer ? `${path} (${referenceType} from ${referrer})` : path;
|
|
184
|
+
|
|
185
|
+
message += ` does not begin with \`base\`. You can fix this by using \`resolve('${path}')\` from \`$app/paths\`. The base path is configurable from \`paths.base\``;
|
|
186
|
+
} else if (referrer) {
|
|
187
|
+
message = `${path} was ${referenceType} from ${referrer}`;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return message;
|
|
152
192
|
}
|
|
153
193
|
);
|
|
154
194
|
|
|
155
195
|
const handle_missing_id = normalise_error_handler(
|
|
156
|
-
|
|
196
|
+
'handleMissingId',
|
|
157
197
|
config.prerender.handleMissingId,
|
|
158
198
|
({ path, id, referrers }) => {
|
|
159
199
|
return (
|
|
160
|
-
`The following pages contain links to ${path}#${id}, but no element with id="${id}" exists on ${path}
|
|
200
|
+
`The following pages contain links to ${path}#${id}, but no element with id="${id}" exists on ${path}:` +
|
|
161
201
|
referrers.map((l) => `\n - ${l}`).join('')
|
|
162
202
|
);
|
|
163
203
|
}
|
|
164
204
|
);
|
|
165
205
|
|
|
166
206
|
const handle_entry_generator_mismatch = normalise_error_handler(
|
|
167
|
-
|
|
207
|
+
'handleEntryGeneratorMismatch',
|
|
168
208
|
config.prerender.handleEntryGeneratorMismatch,
|
|
169
209
|
({ generatedFromId, entry, matchedId }) => {
|
|
170
|
-
return `The entries export from ${generatedFromId} generated entry ${entry}, which was matched by ${matchedId
|
|
210
|
+
return `The entries export from ${generatedFromId} generated entry ${entry}, which was matched by ${matchedId === entry ? 'a static route' : matchedId}`;
|
|
171
211
|
}
|
|
172
212
|
);
|
|
173
213
|
|
|
174
214
|
const handle_not_prerendered_route = normalise_error_handler(
|
|
175
|
-
|
|
215
|
+
'handleUnseenRoutes',
|
|
176
216
|
config.prerender.handleUnseenRoutes,
|
|
177
217
|
({ routes }) => {
|
|
178
218
|
const list = routes.map((id) => ` - ${id}`).join('\n');
|
|
179
|
-
return `The following routes were marked as prerenderable, but were not prerendered because they were not found while crawling your app:\n${list}
|
|
219
|
+
return `The following routes were marked as prerenderable, but were not prerendered because they were not found while crawling your app:\n${list}`;
|
|
220
|
+
}
|
|
221
|
+
);
|
|
222
|
+
|
|
223
|
+
const handle_invalid_url = normalise_error_handler(
|
|
224
|
+
'handleInvalidUrl',
|
|
225
|
+
config.prerender.handleInvalidUrl,
|
|
226
|
+
({ href, referrer }) => {
|
|
227
|
+
return `Invalid URL ${href}${referrer ? ` (linked from ${referrer})` : ''}`;
|
|
180
228
|
}
|
|
181
229
|
);
|
|
182
230
|
|
|
@@ -210,6 +258,8 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
210
258
|
|
|
211
259
|
const seen = new Set();
|
|
212
260
|
const written = new Set();
|
|
261
|
+
|
|
262
|
+
/** @type {Map<string, Promise<any>>} */
|
|
213
263
|
const remote_responses = new Map();
|
|
214
264
|
|
|
215
265
|
/** @type {Map<string, Set<string>>} */
|
|
@@ -249,7 +299,9 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
249
299
|
/** @type {Map<string, import('types').PrerenderDependency>} */
|
|
250
300
|
const dependencies = new Map();
|
|
251
301
|
|
|
252
|
-
const
|
|
302
|
+
const request = new Request(prerender_origin + encoded);
|
|
303
|
+
|
|
304
|
+
const response = await server.respond(request, {
|
|
253
305
|
getClientAddress() {
|
|
254
306
|
throw new Error('Cannot read clientAddress during prerendering');
|
|
255
307
|
},
|
|
@@ -287,6 +339,10 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
287
339
|
});
|
|
288
340
|
}
|
|
289
341
|
|
|
342
|
+
if (response.status !== 204) {
|
|
343
|
+
log_response(response.status, request);
|
|
344
|
+
}
|
|
345
|
+
|
|
290
346
|
const body = Buffer.from(await response.arrayBuffer());
|
|
291
347
|
|
|
292
348
|
const category = decoded.startsWith(remote_prefix) ? 'data' : 'pages';
|
|
@@ -332,16 +388,20 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
332
388
|
|
|
333
389
|
// if it's a 200 HTML response, crawl it. Skip error responses, as we don't save those
|
|
334
390
|
if (response.ok && config.prerender.crawl && headers['content-type'] === 'text/html') {
|
|
335
|
-
const { ids, hrefs } = crawl(body.toString(), decoded);
|
|
391
|
+
const { ids, hrefs, invalid } = crawl(body.toString(), decoded);
|
|
392
|
+
|
|
393
|
+
for (const href of invalid) {
|
|
394
|
+
handle_invalid_url({ href, referrer: decoded });
|
|
395
|
+
}
|
|
336
396
|
|
|
337
397
|
actual_hashlinks.set(decoded, ids);
|
|
338
398
|
|
|
339
399
|
/** @param {string} href */
|
|
340
400
|
const removePrerenderOrigin = (href) => {
|
|
341
|
-
if (href.startsWith(
|
|
342
|
-
if (href ===
|
|
343
|
-
if (href.at(
|
|
344
|
-
return href.slice(
|
|
401
|
+
if (href.startsWith(prerender_origin)) {
|
|
402
|
+
if (href === prerender_origin) return '/';
|
|
403
|
+
if (href.at(prerender_origin.length) !== '/') return href;
|
|
404
|
+
return href.slice(prerender_origin.length);
|
|
345
405
|
}
|
|
346
406
|
return href;
|
|
347
407
|
};
|
|
@@ -386,6 +446,12 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
386
446
|
const type = headers['content-type'];
|
|
387
447
|
const is_html = response_type === REDIRECT || type === 'text/html';
|
|
388
448
|
|
|
449
|
+
if (!is_html && response.status === 200 && decoded.slice(config.paths.base.length + 1) === '') {
|
|
450
|
+
throw new Error(
|
|
451
|
+
`Cannot prerender a root +server.js that returns a non-HTML response - static hosts always serve an HTML file for \`${config.paths.base || '/'}\``
|
|
452
|
+
);
|
|
453
|
+
}
|
|
454
|
+
|
|
389
455
|
const file = output_filename(decoded, is_html);
|
|
390
456
|
const dest = `${config.outDir}/output/prerendered/${category}/${file}`;
|
|
391
457
|
|
|
@@ -407,8 +473,6 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
407
473
|
if (!headers['x-sveltekit-normalize']) {
|
|
408
474
|
mkdirp(dirname(dest));
|
|
409
475
|
|
|
410
|
-
log.warn(`${response.status} ${decoded} -> ${location}`);
|
|
411
|
-
|
|
412
476
|
writeFileSync(
|
|
413
477
|
dest,
|
|
414
478
|
`<script>location.href=${devalue.uneval(
|
|
@@ -455,7 +519,6 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
455
519
|
|
|
456
520
|
mkdirp(dir);
|
|
457
521
|
|
|
458
|
-
log.info(`${response.status} ${decoded}`);
|
|
459
522
|
writeFileSync(dest, body);
|
|
460
523
|
written.add(file);
|
|
461
524
|
|
|
@@ -471,7 +534,12 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
471
534
|
|
|
472
535
|
prerendered.paths.push(decoded);
|
|
473
536
|
} else if (response_type !== OK) {
|
|
474
|
-
handle_http_error({
|
|
537
|
+
handle_http_error({
|
|
538
|
+
status: response.status,
|
|
539
|
+
path: decoded,
|
|
540
|
+
referrer,
|
|
541
|
+
referenceType
|
|
542
|
+
});
|
|
475
543
|
}
|
|
476
544
|
|
|
477
545
|
manifest.assets.add(file);
|
|
@@ -495,10 +563,8 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
495
563
|
}
|
|
496
564
|
}
|
|
497
565
|
|
|
498
|
-
// the user's remote function modules may reference
|
|
499
|
-
//
|
|
500
|
-
// evaluating those modules to avoid potential runtime errors
|
|
501
|
-
internal.set_env(env);
|
|
566
|
+
// the user's remote function modules may reference `read` or the `manifest` at the top-level
|
|
567
|
+
// so we need to set them before evaluating those modules to avoid potential runtime errors
|
|
502
568
|
internal.set_manifest(manifest);
|
|
503
569
|
internal.set_read_implementation((file) => createReadableStream(`${out}/server/${file}`));
|
|
504
570
|
|
|
@@ -28,7 +28,7 @@ export function queue(concurrency) {
|
|
|
28
28
|
|
|
29
29
|
if (task) {
|
|
30
30
|
current += 1;
|
|
31
|
-
const promise =
|
|
31
|
+
const promise = (async () => task.fn())(); // could throw synchronously
|
|
32
32
|
|
|
33
33
|
void promise
|
|
34
34
|
.then(task.fulfil, (err) => {
|
|
@@ -54,6 +54,7 @@ export function queue(concurrency) {
|
|
|
54
54
|
const promise = new Promise((fulfil, reject) => {
|
|
55
55
|
tasks.push({ fn, fulfil, reject });
|
|
56
56
|
});
|
|
57
|
+
promise.catch(() => {});
|
|
57
58
|
|
|
58
59
|
dequeue();
|
|
59
60
|
return promise;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { lookup } from '
|
|
1
|
+
import { lookup } from '../../../utils/mime.js';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { styleText } from 'node:util';
|
|
@@ -29,27 +29,20 @@ export default function create_manifest_data({
|
|
|
29
29
|
}) {
|
|
30
30
|
const assets = create_assets(config);
|
|
31
31
|
const hooks = create_hooks(config, cwd);
|
|
32
|
-
const
|
|
32
|
+
const params = resolve_params(config, cwd);
|
|
33
33
|
const { nodes, routes } = create_routes_and_nodes(cwd, config, fallback);
|
|
34
34
|
|
|
35
|
-
for (const route of routes) {
|
|
36
|
-
for (const param of route.params) {
|
|
37
|
-
if (param.matcher && !matchers[param.matcher]) {
|
|
38
|
-
throw new Error(`No matcher found for parameter '${param.matcher}' in route ${route.id}`);
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
35
|
return {
|
|
44
36
|
assets,
|
|
45
37
|
hooks,
|
|
46
|
-
|
|
38
|
+
params,
|
|
47
39
|
nodes,
|
|
48
40
|
routes
|
|
49
41
|
};
|
|
50
42
|
}
|
|
51
43
|
|
|
52
44
|
/**
|
|
45
|
+
* Returns a list of files in the `static` directory.
|
|
53
46
|
* @param {import('types').ValidatedConfig} config
|
|
54
47
|
*/
|
|
55
48
|
export function create_assets(config) {
|
|
@@ -80,38 +73,9 @@ function create_hooks(config, cwd) {
|
|
|
80
73
|
* @param {import('types').ValidatedConfig} config
|
|
81
74
|
* @param {string} cwd
|
|
82
75
|
*/
|
|
83
|
-
function
|
|
84
|
-
const
|
|
85
|
-
|
|
86
|
-
/** @type {Record<string, string>} */
|
|
87
|
-
const matchers = {};
|
|
88
|
-
if (fs.existsSync(config.kit.files.params)) {
|
|
89
|
-
for (const file of fs.readdirSync(config.kit.files.params)) {
|
|
90
|
-
const ext = path.extname(file);
|
|
91
|
-
if (!config.kit.moduleExtensions.includes(ext)) continue;
|
|
92
|
-
const type = file.slice(0, -ext.length);
|
|
93
|
-
|
|
94
|
-
if (/^\w+$/.test(type)) {
|
|
95
|
-
const matcher_file = path.join(params_base, file);
|
|
96
|
-
|
|
97
|
-
// Disallow same matcher with different extensions
|
|
98
|
-
if (matchers[type]) {
|
|
99
|
-
throw new Error(`Duplicate matchers: ${matcher_file} and ${matchers[type]}`);
|
|
100
|
-
} else {
|
|
101
|
-
matchers[type] = matcher_file;
|
|
102
|
-
}
|
|
103
|
-
} else {
|
|
104
|
-
// Allow for matcher test collocation
|
|
105
|
-
if (type.endsWith('.test') || type.endsWith('.spec')) continue;
|
|
106
|
-
|
|
107
|
-
throw new Error(
|
|
108
|
-
`Matcher names can only have underscores and alphanumeric characters — "${file}" is invalid`
|
|
109
|
-
);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return matchers;
|
|
76
|
+
function resolve_params(config, cwd) {
|
|
77
|
+
const params_file = resolve_entry(config.kit.files.params);
|
|
78
|
+
return params_file ? posixify(path.relative(cwd, params_file)) : null;
|
|
115
79
|
}
|
|
116
80
|
|
|
117
81
|
/**
|
|
@@ -130,6 +94,7 @@ function create_routes_and_nodes(cwd, config, fallback) {
|
|
|
130
94
|
/** @type {import('types').PageNode[]} */
|
|
131
95
|
const nodes = [];
|
|
132
96
|
|
|
97
|
+
// create route data by processing files in `src/routes`
|
|
133
98
|
if (fs.existsSync(config.kit.files.routes)) {
|
|
134
99
|
/**
|
|
135
100
|
* @param {number} depth
|
|
@@ -177,7 +142,7 @@ function create_routes_and_nodes(cwd, config, fallback) {
|
|
|
177
142
|
throw new Error(`Route ${id} should be renamed to ${id.replace(/#/g, '[x+23]')}`);
|
|
178
143
|
}
|
|
179
144
|
|
|
180
|
-
if (/\[
|
|
145
|
+
if (/\[\.\.\.[\w-]+\]\/\[\[/.test(id)) {
|
|
181
146
|
throw new Error(
|
|
182
147
|
`Invalid route ${id} — an [[optional]] route segment cannot follow a [...rest] route segment`
|
|
183
148
|
);
|
|
@@ -218,10 +183,17 @@ function create_routes_and_nodes(cwd, config, fallback) {
|
|
|
218
183
|
|
|
219
184
|
// We can't use withFileTypes because of a NodeJs bug which returns wrong results
|
|
220
185
|
// with isDirectory() in case of symlinks: https://github.com/nodejs/node/issues/30646
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
186
|
+
// We sort the entries because `readdirSync` order is not guaranteed and differs
|
|
187
|
+
// between runtimes (e.g. Node returns entries alphabetically, Bun in directory
|
|
188
|
+
// order). Node indices are assigned from this traversal order, so without sorting
|
|
189
|
+
// the SSR and client manifests can disagree, causing hydration mismatches.
|
|
190
|
+
const files = fs
|
|
191
|
+
.readdirSync(dir)
|
|
192
|
+
.sort()
|
|
193
|
+
.map((name) => ({
|
|
194
|
+
is_dir: fs.statSync(path.join(dir, name)).isDirectory(),
|
|
195
|
+
name
|
|
196
|
+
}));
|
|
225
197
|
|
|
226
198
|
// process files first
|
|
227
199
|
for (const file of files) {
|
|
@@ -365,7 +337,7 @@ function create_routes_and_nodes(cwd, config, fallback) {
|
|
|
365
337
|
const root = routes[0];
|
|
366
338
|
if (!root.leaf && !root.error && !root.layout && !root.endpoint) {
|
|
367
339
|
throw new Error(
|
|
368
|
-
'No routes found. If you are using a custom src/routes directory, make sure it is specified in your
|
|
340
|
+
'No routes found. If you are using a custom src/routes directory, make sure it is specified in your SvelteKit Vite plugin options'
|
|
369
341
|
);
|
|
370
342
|
}
|
|
371
343
|
}
|
|
@@ -388,6 +360,7 @@ function create_routes_and_nodes(cwd, config, fallback) {
|
|
|
388
360
|
|
|
389
361
|
prevent_conflicts(routes);
|
|
390
362
|
|
|
363
|
+
// fallback root layout and root error components
|
|
391
364
|
const root = routes[0];
|
|
392
365
|
|
|
393
366
|
if (!root.layout?.component) {
|
|
@@ -396,10 +369,11 @@ function create_routes_and_nodes(cwd, config, fallback) {
|
|
|
396
369
|
}
|
|
397
370
|
|
|
398
371
|
if (!root.error?.component) {
|
|
399
|
-
if (!root.error) root.error = { depth: 0 };
|
|
372
|
+
if (!root.error) root.error = { depth: 0, parent: root.layout };
|
|
400
373
|
root.error.component = posixify(path.relative(cwd, `${fallback}/error.svelte`));
|
|
401
374
|
}
|
|
402
375
|
|
|
376
|
+
// populate the page nodes list
|
|
403
377
|
// we do layouts/errors first as they are more likely to be reused,
|
|
404
378
|
// and smaller indexes take fewer bytes. also, this guarantees that
|
|
405
379
|
// the default error/layout are 0/1
|
|
@@ -421,6 +395,7 @@ function create_routes_and_nodes(cwd, config, fallback) {
|
|
|
421
395
|
|
|
422
396
|
const node_analyser = create_node_analyser(cwd);
|
|
423
397
|
|
|
398
|
+
// add the related layout, page, and error nodes for a route
|
|
424
399
|
for (const route of routes) {
|
|
425
400
|
if (!route.leaf) continue;
|
|
426
401
|
|
|
@@ -465,6 +440,22 @@ function create_routes_and_nodes(cwd, config, fallback) {
|
|
|
465
440
|
}
|
|
466
441
|
}
|
|
467
442
|
|
|
443
|
+
// add parents to error nodes so that we can compute which page options apply to them
|
|
444
|
+
for (const route of routes) {
|
|
445
|
+
if (!route.error) continue;
|
|
446
|
+
|
|
447
|
+
/** @type {import('types').RouteData | null} */
|
|
448
|
+
let current_route = route;
|
|
449
|
+
while (current_route) {
|
|
450
|
+
if (current_route.layout) {
|
|
451
|
+
route.error.parent = current_route.layout;
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
current_route = current_route.parent;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// compute the final page options for each page node
|
|
468
459
|
for (const node of nodes) {
|
|
469
460
|
node.page_options = node_analyser.get_page_options(node);
|
|
470
461
|
}
|
|
@@ -473,6 +464,17 @@ function create_routes_and_nodes(cwd, config, fallback) {
|
|
|
473
464
|
if (route.endpoint) {
|
|
474
465
|
route.endpoint.page_options = get_page_options(route.endpoint.file, cwd);
|
|
475
466
|
}
|
|
467
|
+
|
|
468
|
+
if (route.page && route.endpoint) {
|
|
469
|
+
const page = nodes[route.page.leaf];
|
|
470
|
+
if (page.page_options?.prerender || route.endpoint.page_options?.prerender) {
|
|
471
|
+
const endpoint_file = route.endpoint.file.split('/').pop();
|
|
472
|
+
|
|
473
|
+
throw new Error(
|
|
474
|
+
`Cannot prerender a route (${route.id}) with both a \`+page.svelte\` and a \`${endpoint_file}\``
|
|
475
|
+
);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
476
478
|
}
|
|
477
479
|
|
|
478
480
|
return {
|
|
@@ -482,6 +484,7 @@ function create_routes_and_nodes(cwd, config, fallback) {
|
|
|
482
484
|
}
|
|
483
485
|
|
|
484
486
|
/**
|
|
487
|
+
* Determine if and how the file is relevant to the routing system.
|
|
485
488
|
* @param {string} project_relative
|
|
486
489
|
* @param {string} file
|
|
487
490
|
* @param {string[]} component_extensions
|
package/src/core/sync/sync.js
CHANGED
|
@@ -2,7 +2,6 @@ import path from 'node:path';
|
|
|
2
2
|
import process from 'node:process';
|
|
3
3
|
import create_manifest_data from './create_manifest_data/index.js';
|
|
4
4
|
import { write_client_manifest } from './write_client_manifest.js';
|
|
5
|
-
import { write_root } from './write_root.js';
|
|
6
5
|
import { write_tsconfig } from './write_tsconfig.js';
|
|
7
6
|
import { write_types, write_all_types } from './write_types/index.js';
|
|
8
7
|
import { write_ambient } from './write_ambient.js';
|
|
@@ -37,7 +36,6 @@ export function create(config, root) {
|
|
|
37
36
|
|
|
38
37
|
write_client_manifest(config.kit, manifest_data, `${output}/client`);
|
|
39
38
|
write_server(config, output, root);
|
|
40
|
-
write_root(manifest_data, config, output);
|
|
41
39
|
write_all_types(config, manifest_data, root);
|
|
42
40
|
write_non_ambient(config.kit, manifest_data);
|
|
43
41
|
|
|
@@ -176,26 +176,19 @@ export function write_client_manifest(kit, manifest_data, output, metadata) {
|
|
|
176
176
|
|
|
177
177
|
export const decode = (type, value) => decoders[type](value);
|
|
178
178
|
|
|
179
|
-
export
|
|
179
|
+
export const get_error_template = () => import('../shared/error-template.js').then(m => m.default);
|
|
180
180
|
`
|
|
181
181
|
);
|
|
182
182
|
|
|
183
183
|
if (client_routing) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const matchers = [];
|
|
188
|
-
|
|
189
|
-
for (const key in manifest_data.matchers) {
|
|
190
|
-
const src = manifest_data.matchers[key];
|
|
191
|
-
|
|
192
|
-
imports.push(`import { match as ${key} } from ${s(relative_path(output, src))};`);
|
|
193
|
-
matchers.push(key);
|
|
194
|
-
}
|
|
184
|
+
const uses_matchers = manifest_data.routes.some((route) =>
|
|
185
|
+
route.params.some((param) => param.matcher)
|
|
186
|
+
);
|
|
195
187
|
|
|
196
|
-
const module =
|
|
197
|
-
|
|
198
|
-
|
|
188
|
+
const module =
|
|
189
|
+
!manifest_data.params || !uses_matchers
|
|
190
|
+
? 'export const matchers = {};'
|
|
191
|
+
: `import { params as matchers } from ${s(relative_path(output, manifest_data.params))};\n\nexport { matchers };`;
|
|
199
192
|
|
|
200
193
|
write_if_changed(`${output}/matchers.js`, module);
|
|
201
194
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { create_explicit_env_types } from '../env.js';
|
|
4
4
|
import { write_if_changed } from './utils.js';
|
|
5
|
+
import { posixify } from '../../utils/os.js';
|
|
5
6
|
|
|
6
7
|
const DOCS = '// See https://svelte.dev/docs/kit/environment-variables for more information';
|
|
7
8
|
|
|
@@ -18,7 +19,7 @@ export function write_env(kit, entry, env_config) {
|
|
|
18
19
|
const out = path.join(kit.outDir, 'env.d.ts');
|
|
19
20
|
|
|
20
21
|
if (entry && env_config) {
|
|
21
|
-
const relative = path.relative(kit.outDir, entry);
|
|
22
|
+
const relative = posixify(path.relative(kit.outDir, entry));
|
|
22
23
|
content.push(
|
|
23
24
|
`// This file is generated from ${relative}.\n${DOCS}`,
|
|
24
25
|
create_explicit_env_types(env_config, relative, 'private'),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { GENERATED_COMMENT } from '../../constants.js';
|
|
3
|
+
import { resolve_entry } from '../../utils/filesystem.js';
|
|
3
4
|
import { posixify } from '../../utils/os.js';
|
|
4
5
|
import { write_if_changed } from './utils.js';
|
|
5
6
|
import { s } from '../../utils/misc.js';
|
|
@@ -85,10 +86,6 @@ export {};
|
|
|
85
86
|
* @param {import('types').ValidatedKitConfig} config
|
|
86
87
|
*/
|
|
87
88
|
function generate_app_types(manifest_data, config) {
|
|
88
|
-
/** @param {string} matcher */
|
|
89
|
-
const path_to_matcher = (matcher) =>
|
|
90
|
-
posixify(path.relative(config.outDir, path.join(config.files.params, matcher + '.js')));
|
|
91
|
-
|
|
92
89
|
/** @type {Map<string, string>} */
|
|
93
90
|
const matcher_types = new Map();
|
|
94
91
|
|
|
@@ -98,7 +95,15 @@ function generate_app_types(manifest_data, config) {
|
|
|
98
95
|
|
|
99
96
|
let type = matcher_types.get(matcher);
|
|
100
97
|
if (!type) {
|
|
101
|
-
|
|
98
|
+
const path_to_params = () => {
|
|
99
|
+
const params_file =
|
|
100
|
+
resolve_entry(config.files.params) ??
|
|
101
|
+
config.files.params.replace(/\.(js|ts)$/, '') + '.js';
|
|
102
|
+
|
|
103
|
+
return posixify(path.relative(config.outDir, params_file));
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
type = `import('@sveltejs/kit').MatcherParam<(typeof import('${path_to_params()}').params)[${JSON.stringify(matcher)}]>`;
|
|
102
107
|
matcher_types.set(matcher, type);
|
|
103
108
|
}
|
|
104
109
|
|
|
@@ -204,7 +209,7 @@ function generate_app_types(manifest_data, config) {
|
|
|
204
209
|
if (route.params.length > 0) {
|
|
205
210
|
const params = route.params.map((p) => {
|
|
206
211
|
const type = get_matcher_type(p.matcher);
|
|
207
|
-
return `${p.name}${p.optional ? '?:' : ':'} ${type}${p.optional ? ' | undefined' : ''}`;
|
|
212
|
+
return `${/^\w+$/.test(p.name) ? p.name : `'${p.name}'`}${p.optional ? '?:' : ':'} ${type}${p.optional ? ' | undefined' : ''}`;
|
|
208
213
|
});
|
|
209
214
|
const route_type = `${s(route.id)}: { ${params.join('; ')} }`;
|
|
210
215
|
|
|
@@ -225,7 +230,7 @@ function generate_app_types(manifest_data, config) {
|
|
|
225
230
|
const params = Array.from(layout_params)
|
|
226
231
|
.map(([name, { optional, matchers }]) => {
|
|
227
232
|
const type = get_matchers_type(matchers);
|
|
228
|
-
return `${name}${optional ? '?:' : ':'} ${type}${optional ? ' | undefined' : ''}`;
|
|
233
|
+
return `${/^\w+$/.test(name) ? name : `'${name}'`}${optional ? '?:' : ':'} ${type}${optional ? ' | undefined' : ''}`;
|
|
229
234
|
})
|
|
230
235
|
.join('; ');
|
|
231
236
|
|
|
@@ -239,8 +244,6 @@ function generate_app_types(manifest_data, config) {
|
|
|
239
244
|
|
|
240
245
|
return [
|
|
241
246
|
'declare module "$app/types" {',
|
|
242
|
-
'\ttype MatcherParam<M> = M extends (param : string) => param is (infer U extends string) ? U : string;',
|
|
243
|
-
'',
|
|
244
247
|
'\texport interface AppTypes {',
|
|
245
248
|
`\t\tRouteId(): ${manifest_data.routes.map((r) => s(r.id)).join(' | ')};`,
|
|
246
249
|
`\t\tRouteParams(): {\n\t\t\t${dynamic_routes.join(';\n\t\t\t')}\n\t\t};`,
|