@sveltejs/kit 3.0.0-next.0 → 3.0.0-next.10
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/core/adapt/builder.js +29 -43
- package/src/core/adapt/index.js +1 -4
- package/src/core/config/index.js +132 -71
- package/src/core/config/options.js +294 -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/prerender.js +42 -23
- 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 +13 -14
- 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 +2 -2
- package/src/exports/env/index.js +12 -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 +2 -2
- 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 +63 -0
- package/src/exports/public.d.ts +323 -170
- 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 +42 -44
- package/src/exports/vite/index.js +810 -593
- package/src/exports/vite/preview/index.js +29 -22
- 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 +21 -36
- 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 +6 -0
- 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 +9 -5
- 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 +38 -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 +14 -18
- package/src/runtime/server/env_module.js +0 -5
- package/src/runtime/server/index.js +2 -2
- package/src/runtime/server/page/actions.js +41 -26
- package/src/runtime/server/page/index.js +9 -15
- package/src/runtime/server/page/load_data.js +1 -1
- package/src/runtime/server/page/render.js +112 -187
- package/src/runtime/server/page/respond_with_error.js +7 -8
- package/src/runtime/server/page/server_routing.js +27 -18
- package/src/runtime/server/remote.js +355 -216
- package/src/runtime/server/respond.js +97 -61
- package/src/runtime/server/utils.js +32 -9
- 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.d.ts +10 -5
- package/src/types/global-private.d.ts +15 -22
- package/src/types/internal.d.ts +89 -74
- package/src/types/private.d.ts +33 -1
- package/src/utils/error.js +24 -4
- package/src/utils/import.js +6 -1
- package/src/utils/imports.js +83 -0
- package/src/utils/mime.js +9 -0
- 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 +467 -537
- package/types/index.d.ts.map +22 -39
- package/src/core/sync/write_root.js +0 -148
- package/src/exports/internal/server.js +0 -22
- package/src/types/synthetic/$lib.md +0 -5
- /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
package/src/core/env.js
CHANGED
|
@@ -38,6 +38,7 @@ export async function load_explicit_env(kit, file, root, mode) {
|
|
|
38
38
|
logLevel: 'silent',
|
|
39
39
|
mode,
|
|
40
40
|
define: {
|
|
41
|
+
__SVELTEKIT_PAYLOAD__: 'undefined', // coming in through static import in env/internal.js but will end up unused
|
|
41
42
|
__SVELTEKIT_APP_VERSION__: JSON.stringify(kit.version.name) // needed by $app/env
|
|
42
43
|
},
|
|
43
44
|
resolve: {
|
|
@@ -51,6 +52,10 @@ export async function load_explicit_env(kit, file, root, mode) {
|
|
|
51
52
|
/** @type {Record<string, EnvVarConfig<any>>} */
|
|
52
53
|
let variables;
|
|
53
54
|
|
|
55
|
+
/** @type {import('../runtime/app/env/internal.js')} */ (
|
|
56
|
+
await server.ssrLoadModule(`${runtime_directory}/app/env/internal.js`)
|
|
57
|
+
).set_building();
|
|
58
|
+
|
|
54
59
|
try {
|
|
55
60
|
({ variables } = await server.ssrLoadModule(file));
|
|
56
61
|
|
|
@@ -87,11 +92,12 @@ export async function load_explicit_env(kit, file, root, mode) {
|
|
|
87
92
|
|
|
88
93
|
/**
|
|
89
94
|
* Creates the `__sveltekit/env` module
|
|
90
|
-
* @param {Record<string, EnvVarConfig<any
|
|
95
|
+
* @param {Record<string, EnvVarConfig<any> | undefined> | null} variables
|
|
91
96
|
* @param {Record<string, string>} env
|
|
92
97
|
* @param {string | null} entry
|
|
98
|
+
* @param {boolean} is_dev
|
|
93
99
|
*/
|
|
94
|
-
export function create_sveltekit_env(variables, env, entry) {
|
|
100
|
+
export function create_sveltekit_env(variables, env, entry, is_dev) {
|
|
95
101
|
const imports = entry
|
|
96
102
|
? [
|
|
97
103
|
`import { variables } from ${JSON.stringify(entry)};`,
|
|
@@ -106,7 +112,7 @@ export function create_sveltekit_env(variables, env, entry) {
|
|
|
106
112
|
const issues = {};
|
|
107
113
|
|
|
108
114
|
for (const [name, config] of Object.entries(variables ?? {})) {
|
|
109
|
-
if (config
|
|
115
|
+
if (config?.static) {
|
|
110
116
|
if (config.public) {
|
|
111
117
|
const value = validate(variables ?? {}, env[name], name, issues);
|
|
112
118
|
declarations.push(`explicit_public_env.${name} = ${devalue.uneval(value)};`);
|
|
@@ -116,7 +122,7 @@ export function create_sveltekit_env(variables, env, entry) {
|
|
|
116
122
|
`const ${name} = validate(variables, env.${name}, ${JSON.stringify(name)}, issues);`
|
|
117
123
|
);
|
|
118
124
|
|
|
119
|
-
if (config
|
|
125
|
+
if (config?.public) {
|
|
120
126
|
setters.push(`explicit_public_env.${name} = ${name};`);
|
|
121
127
|
setters.push(`rendered_env.${name} = ${name};`);
|
|
122
128
|
} else {
|
|
@@ -145,6 +151,19 @@ export function create_sveltekit_env(variables, env, entry) {
|
|
|
145
151
|
}`
|
|
146
152
|
];
|
|
147
153
|
|
|
154
|
+
// In dev, initialise the env immediately. Tools like `vite-node` load modules
|
|
155
|
+
// through the Vite config but don't run the SvelteKit dev server, which is what
|
|
156
|
+
// normally calls `set_env`. Without this, dynamic env vars imported from
|
|
157
|
+
// `$app/env/public` and `$app/env/private` would be `undefined` in such contexts.
|
|
158
|
+
if (is_dev) {
|
|
159
|
+
/** @type {Record<string, string>} */
|
|
160
|
+
const dev_env = {};
|
|
161
|
+
for (const name of Object.keys(variables ?? {})) {
|
|
162
|
+
if (name in env) dev_env[name] = env[name];
|
|
163
|
+
}
|
|
164
|
+
blocks.push(`set_env(${devalue.uneval(dev_env)});`);
|
|
165
|
+
}
|
|
166
|
+
|
|
148
167
|
const module = blocks.join('\n\n');
|
|
149
168
|
|
|
150
169
|
return module;
|
|
@@ -213,9 +232,36 @@ export function create_sveltekit_env_public(variables, env, prelude) {
|
|
|
213
232
|
return `${prelude}\n\n${exports.join('')}`;
|
|
214
233
|
}
|
|
215
234
|
|
|
235
|
+
/**
|
|
236
|
+
* Creates the `__sveltekit/env/service-worker` module used in production. When an app uses
|
|
237
|
+
* dynamic public env vars, they're loaded at runtime via an import of the prerendered
|
|
238
|
+
* `env.js`. If there are none, values are inlined.
|
|
239
|
+
* @param {Record<string, EnvVarConfig<any>> | null} variables
|
|
240
|
+
* @param {Record<string, string>} env
|
|
241
|
+
* @param {string} global
|
|
242
|
+
* @param {string} base
|
|
243
|
+
* @param {string} app_dir
|
|
244
|
+
*/
|
|
245
|
+
export function create_sveltekit_env_service_worker(variables, env, global, base, app_dir) {
|
|
246
|
+
const has_dynamic_public_env = Object.values(variables ?? {}).some(
|
|
247
|
+
(config) => config.public && !config.static
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
if (!has_dynamic_public_env) {
|
|
251
|
+
return create_sveltekit_env_service_worker_dev(variables, env, global);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return dedent`
|
|
255
|
+
import { env } from '${base}/${app_dir}/env.js';
|
|
256
|
+
|
|
257
|
+
globalThis.__SVELTEKIT_EXPERIMENTAL_EXPLICIT_ENVIRONMENT_VARIABLES__ = true;
|
|
258
|
+
|
|
259
|
+
${global} = { env };
|
|
260
|
+
`;
|
|
261
|
+
}
|
|
262
|
+
|
|
216
263
|
/**
|
|
217
264
|
* Creates the `__sveltekit/env/service-worker` module used in development
|
|
218
|
-
* (but not in prod, which goes through build_service_worker instead)
|
|
219
265
|
* @param {Record<string, EnvVarConfig<any>> | null} variables
|
|
220
266
|
* @param {Record<string, string>} env
|
|
221
267
|
* @param {string} global
|
|
@@ -330,3 +376,73 @@ export const reserved = new Set([
|
|
|
330
376
|
]);
|
|
331
377
|
|
|
332
378
|
export const valid_identifier = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Generates `export const` declarations (and, for reserved-word names that need
|
|
382
|
+
* aliasing, `const` + re-export specifiers) for a set of named exports.
|
|
383
|
+
*
|
|
384
|
+
* For regular names, emits a single efficient `export const name = expr;` statement.
|
|
385
|
+
* For reserved-word names (e.g. `delete`, `class`), emits `const alias = expr;` plus
|
|
386
|
+
* a re-export specifier (`alias as name`), since reserved words can't be `const`
|
|
387
|
+
* binding names but CAN appear in export specifiers.
|
|
388
|
+
*
|
|
389
|
+
* You can do evil things like `export { c as class }`. In order to import/re-export
|
|
390
|
+
* these, you need to alias the binding, then un-alias it when re-exporting:
|
|
391
|
+
*
|
|
392
|
+
* const _0 = ...; // safe binding name
|
|
393
|
+
* export { _0 as class }; // valid — `class` is allowed in export specifiers
|
|
394
|
+
*
|
|
395
|
+
* Aliases are chosen to avoid collisions with any of the supplied names. The
|
|
396
|
+
* namespace binding (used to hold the imported module) is likewise chosen to
|
|
397
|
+
* avoid collisions.
|
|
398
|
+
*
|
|
399
|
+
* @param {Iterable<string>} names — the export names
|
|
400
|
+
* @param {(name: string, namespace: string) => string} build_expression —
|
|
401
|
+
* called for each name to produce the right-hand side of the declaration;
|
|
402
|
+
* receives the chosen namespace binding so it can reference the imported module
|
|
403
|
+
* @param {string} namespace_prefix — the preferred binding name for the namespace
|
|
404
|
+
* (suffixed with a number if it collides with any export name)
|
|
405
|
+
* @returns {{ namespace: string, declarations: string[], reexports: string[] }}
|
|
406
|
+
*/
|
|
407
|
+
export function create_exported_declarations(names, build_expression, namespace_prefix) {
|
|
408
|
+
/** @type {Set<string>} */
|
|
409
|
+
const set = new Set(names);
|
|
410
|
+
|
|
411
|
+
let namespace = namespace_prefix;
|
|
412
|
+
let namespace_index = 0;
|
|
413
|
+
while (set.has(namespace)) {
|
|
414
|
+
namespace = `${namespace_prefix}${namespace_index++}`;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
let alias_index = 0;
|
|
418
|
+
/** @type {Map<string, string>} */
|
|
419
|
+
const aliases = new Map();
|
|
420
|
+
|
|
421
|
+
for (const name of set) {
|
|
422
|
+
if (!reserved.has(name)) continue;
|
|
423
|
+
|
|
424
|
+
let alias = `_${alias_index++}`;
|
|
425
|
+
while (set.has(alias)) {
|
|
426
|
+
alias = `_${alias_index++}`;
|
|
427
|
+
}
|
|
428
|
+
aliases.set(name, alias);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
/** @type {string[]} */
|
|
432
|
+
const declarations = [];
|
|
433
|
+
/** @type {string[]} */
|
|
434
|
+
const reexports = [];
|
|
435
|
+
|
|
436
|
+
for (const name of set) {
|
|
437
|
+
const alias = aliases.get(name);
|
|
438
|
+
const expr = build_expression(name, namespace);
|
|
439
|
+
if (alias) {
|
|
440
|
+
declarations.push(`const ${alias} = ${expr};`);
|
|
441
|
+
reexports.push(`${alias} as ${name}`);
|
|
442
|
+
} else {
|
|
443
|
+
declarations.push(`export const ${name} = ${expr};`);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
return { namespace, declarations, reexports };
|
|
448
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @import { RemoteChunk } from 'types' */
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
-
import
|
|
4
|
+
import { lookup as mime_lookup } from '../../utils/mime.js';
|
|
5
5
|
import { s } from '../../utils/misc.js';
|
|
6
6
|
import { get_mime_lookup } from '../utils.js';
|
|
7
7
|
import { resolve_symlinks } from '../../exports/vite/build/utils.js';
|
|
@@ -69,10 +69,8 @@ export function generate_manifest({
|
|
|
69
69
|
assets.push(build_data.service_worker);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const matchers = new Set(
|
|
75
|
-
build_data.client?.nodes ? Object.keys(build_data.manifest_data.matchers) : undefined
|
|
72
|
+
const uses_matchers = build_data.manifest_data.routes.some((route) =>
|
|
73
|
+
route.params.some((param) => param.matcher)
|
|
76
74
|
);
|
|
77
75
|
|
|
78
76
|
/** @param {Array<number | undefined>} indexes */
|
|
@@ -93,7 +91,7 @@ export function generate_manifest({
|
|
|
93
91
|
files[file] = fs.statSync(path.resolve(build_data.out_dir, 'server', file)).size;
|
|
94
92
|
|
|
95
93
|
const ext = path.extname(file);
|
|
96
|
-
mime_types[ext] ??=
|
|
94
|
+
mime_types[ext] ??= mime_lookup(ext) || '';
|
|
97
95
|
}
|
|
98
96
|
|
|
99
97
|
// prettier-ignore
|
|
@@ -117,10 +115,6 @@ export function generate_manifest({
|
|
|
117
115
|
${routes.map(route => {
|
|
118
116
|
if (!route.page && !route.endpoint) return;
|
|
119
117
|
|
|
120
|
-
route.params.forEach(param => {
|
|
121
|
-
if (param.matcher) matchers.add(param.matcher);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
118
|
return dedent`
|
|
125
119
|
{
|
|
126
120
|
id: ${s(route.id)},
|
|
@@ -134,11 +128,14 @@ export function generate_manifest({
|
|
|
134
128
|
],
|
|
135
129
|
prerendered_routes: new Set(${s(prerendered)}),
|
|
136
130
|
matchers: async () => {
|
|
137
|
-
${
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
131
|
+
${
|
|
132
|
+
uses_matchers && build_data.manifest_data.params
|
|
133
|
+
? dedent`
|
|
134
|
+
const { params } = await import('${join_relative(relative_path, '/entries/params.js')}');
|
|
135
|
+
return params;
|
|
136
|
+
`
|
|
137
|
+
: 'return {};'
|
|
138
|
+
}
|
|
142
139
|
},
|
|
143
140
|
server_assets: ${s(files)}
|
|
144
141
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** @import { Adapter } from '@sveltejs/kit' */
|
|
2
1
|
/** @import { RemoteChunk } from 'types' */
|
|
3
2
|
import { join } from 'node:path';
|
|
4
3
|
import { pathToFileURL } from 'node:url';
|
|
@@ -10,7 +9,6 @@ import { has_server_load, resolve_route } from '../../utils/routing.js';
|
|
|
10
9
|
import { check_feature } from '../../utils/features.js';
|
|
11
10
|
import { createReadableStream } from '@sveltejs/kit/node';
|
|
12
11
|
import { PageNodes } from '../../utils/page_nodes.js';
|
|
13
|
-
import { build_server_nodes } from '../../exports/vite/build/build_server.js';
|
|
14
12
|
|
|
15
13
|
export default forked(import.meta.url, analyse);
|
|
16
14
|
|
|
@@ -22,9 +20,7 @@ export default forked(import.meta.url, analyse);
|
|
|
22
20
|
* server_manifest: import('vite').Manifest;
|
|
23
21
|
* tracked_features: Record<string, string[]>;
|
|
24
22
|
* env: Record<string, string>;
|
|
25
|
-
* out: string;
|
|
26
23
|
* remotes: RemoteChunk[];
|
|
27
|
-
* root: string;
|
|
28
24
|
* vite_config_file: string | undefined;
|
|
29
25
|
* }} opts
|
|
30
26
|
*/
|
|
@@ -35,24 +31,14 @@ async function analyse({
|
|
|
35
31
|
server_manifest,
|
|
36
32
|
tracked_features,
|
|
37
33
|
env,
|
|
38
|
-
out,
|
|
39
34
|
remotes,
|
|
40
|
-
root,
|
|
41
35
|
vite_config_file
|
|
42
36
|
}) {
|
|
43
37
|
/** @type {import('@sveltejs/kit').SSRManifest} */
|
|
44
38
|
const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;
|
|
45
39
|
|
|
46
40
|
const vite_config = await load_vite_config(vite_config_file);
|
|
47
|
-
|
|
48
41
|
const config = extract_svelte_config(vite_config).kit;
|
|
49
|
-
|
|
50
|
-
// TODO i think this can just be config.adapter?
|
|
51
|
-
/** @type {Adapter | undefined} */
|
|
52
|
-
const adapter = vite_config.plugins.find(
|
|
53
|
-
(plugin) => plugin.name === 'vite-plugin-sveltekit-adapter'
|
|
54
|
-
)?.api?.adapter;
|
|
55
|
-
|
|
56
42
|
const server_root = join(config.outDir, 'output');
|
|
57
43
|
|
|
58
44
|
/** @type {import('types').ServerInternalModule} */
|
|
@@ -62,13 +48,15 @@ async function analyse({
|
|
|
62
48
|
// essential we do this before analysing the code
|
|
63
49
|
internal.set_building();
|
|
64
50
|
|
|
65
|
-
// set
|
|
66
|
-
internal.set_env(env);
|
|
51
|
+
// set `read` and `manifest`, in case they're used in initialisation
|
|
67
52
|
internal.set_manifest(manifest);
|
|
68
53
|
internal.set_read_implementation((file) => createReadableStream(`${server_root}/server/${file}`));
|
|
69
54
|
|
|
70
|
-
//
|
|
71
|
-
|
|
55
|
+
// `set_env` lives in a separate module that imports the user's `src/env` config. We import it
|
|
56
|
+
// *after* `set_building()` so that `building`-dependent expressions resolve correctly
|
|
57
|
+
/** @type {import('__sveltekit/env')} */
|
|
58
|
+
const { set_env } = await import(pathToFileURL(`${server_root}/server/env.js`).href);
|
|
59
|
+
set_env(env);
|
|
72
60
|
|
|
73
61
|
/** @type {import('types').ServerMetadata} */
|
|
74
62
|
const metadata = {
|
|
@@ -134,7 +122,7 @@ async function analyse({
|
|
|
134
122
|
server_manifest,
|
|
135
123
|
tracked_features
|
|
136
124
|
)) {
|
|
137
|
-
check_feature(route.id, route_config, feature, adapter);
|
|
125
|
+
check_feature(route.id, route_config, feature, config.adapter);
|
|
138
126
|
}
|
|
139
127
|
}
|
|
140
128
|
|
|
@@ -38,6 +38,18 @@ export function crawl(html, base) {
|
|
|
38
38
|
/** @type {string[]} */
|
|
39
39
|
const hrefs = [];
|
|
40
40
|
|
|
41
|
+
/** @type {string[]} */
|
|
42
|
+
const invalid = [];
|
|
43
|
+
|
|
44
|
+
/** @param {string} url */
|
|
45
|
+
const push_href = (url) => {
|
|
46
|
+
try {
|
|
47
|
+
hrefs.push(resolve(base, url));
|
|
48
|
+
} catch {
|
|
49
|
+
invalid.push(url);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
41
53
|
let i = 0;
|
|
42
54
|
main: while (i < html.length) {
|
|
43
55
|
const char = html[i];
|
|
@@ -186,9 +198,13 @@ export function crawl(html, base) {
|
|
|
186
198
|
|
|
187
199
|
if (href) {
|
|
188
200
|
if (tag === 'BASE') {
|
|
189
|
-
|
|
201
|
+
try {
|
|
202
|
+
base = resolve(base, href);
|
|
203
|
+
} catch {
|
|
204
|
+
invalid.push(href);
|
|
205
|
+
}
|
|
190
206
|
} else if (!rel || !/\bexternal\b/i.test(rel)) {
|
|
191
|
-
|
|
207
|
+
push_href(href);
|
|
192
208
|
}
|
|
193
209
|
}
|
|
194
210
|
|
|
@@ -201,7 +217,7 @@ export function crawl(html, base) {
|
|
|
201
217
|
}
|
|
202
218
|
|
|
203
219
|
if (src) {
|
|
204
|
-
|
|
220
|
+
push_href(src);
|
|
205
221
|
}
|
|
206
222
|
|
|
207
223
|
if (srcset) {
|
|
@@ -222,7 +238,7 @@ export function crawl(html, base) {
|
|
|
222
238
|
candidates.push(value);
|
|
223
239
|
for (const candidate of candidates) {
|
|
224
240
|
const src = candidate.split(WHITESPACE)[0];
|
|
225
|
-
if (src)
|
|
241
|
+
if (src) push_href(src);
|
|
226
242
|
}
|
|
227
243
|
}
|
|
228
244
|
|
|
@@ -230,7 +246,7 @@ export function crawl(html, base) {
|
|
|
230
246
|
const attr = name ?? property;
|
|
231
247
|
|
|
232
248
|
if (attr && CRAWLABLE_META_NAME_ATTRS.has(attr)) {
|
|
233
|
-
|
|
249
|
+
push_href(content);
|
|
234
250
|
}
|
|
235
251
|
}
|
|
236
252
|
}
|
|
@@ -239,5 +255,5 @@ export function crawl(html, base) {
|
|
|
239
255
|
i += 1;
|
|
240
256
|
}
|
|
241
257
|
|
|
242
|
-
return { ids, hrefs };
|
|
258
|
+
return { ids, hrefs, invalid };
|
|
243
259
|
}
|
|
@@ -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';
|
|
@@ -44,14 +43,20 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
44
43
|
/** @type {import('types').ServerInternalModule} */
|
|
45
44
|
const internal = await import(pathToFileURL(`${out}/server/internal.js`).href);
|
|
46
45
|
|
|
47
|
-
/** @type {import('types').ServerModule} */
|
|
48
|
-
const { Server } = await import(pathToFileURL(`${out}/server/index.js`).href);
|
|
49
|
-
|
|
50
46
|
// configure `import { building } from `$app/env` —
|
|
51
47
|
// essential we do this before analysing the code
|
|
52
48
|
internal.set_building();
|
|
53
49
|
internal.set_prerendering();
|
|
54
50
|
|
|
51
|
+
// `set_env` and `Server` live in modules that import the user's `src/env` config. We import them
|
|
52
|
+
// *after* `set_building()` so that `building`-dependent expressions resolve correctly
|
|
53
|
+
/** @type {import('__sveltekit/env')} */
|
|
54
|
+
const { set_env } = await import(pathToFileURL(`${out}/server/env.js`).href);
|
|
55
|
+
set_env(env);
|
|
56
|
+
|
|
57
|
+
/** @type {import('types').ServerModule} */
|
|
58
|
+
const { Server } = await import(pathToFileURL(`${out}/server/index.js`).href);
|
|
59
|
+
|
|
55
60
|
/**
|
|
56
61
|
* @template {{message: string}} T
|
|
57
62
|
* @template {Omit<T, 'message'>} K
|
|
@@ -105,12 +110,14 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
105
110
|
|
|
106
111
|
const config = extract_svelte_config(vite_config).kit;
|
|
107
112
|
|
|
113
|
+
const prerender_origin = config.paths.origin || 'http://sveltekit-prerender';
|
|
114
|
+
|
|
108
115
|
if (hash) {
|
|
109
116
|
const fallback = await generate_fallback({
|
|
110
117
|
manifest_path,
|
|
111
118
|
env,
|
|
112
119
|
out_dir: config.outDir,
|
|
113
|
-
origin:
|
|
120
|
+
origin: prerender_origin,
|
|
114
121
|
assets: config.files.assets
|
|
115
122
|
});
|
|
116
123
|
|
|
@@ -125,13 +132,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
125
132
|
return { prerendered, prerender_map };
|
|
126
133
|
}
|
|
127
134
|
|
|
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?.();
|
|
135
|
+
const emulator = await config.adapter?.emulate?.();
|
|
135
136
|
|
|
136
137
|
/** @type {import('types').Logger} */
|
|
137
138
|
const log = logger({ verbose });
|
|
@@ -145,7 +146,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
145
146
|
({ status, path, referrer, referenceType }) => {
|
|
146
147
|
const message =
|
|
147
148
|
status === 404 && !path.startsWith(config.paths.base)
|
|
148
|
-
? `${path} does not begin with \`base
|
|
149
|
+
? `${path} does not begin with \`base\`. You can fix this by using \`resolve('${path}')\` from \`$app/paths\`. The base path is configurable from \`paths.base\` - see https://svelte.dev/docs/kit/configuration#paths for more info`
|
|
149
150
|
: path;
|
|
150
151
|
|
|
151
152
|
return `${status} ${message}${referrer ? ` (${referenceType} from ${referrer})` : ''}`;
|
|
@@ -180,6 +181,14 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
180
181
|
}
|
|
181
182
|
);
|
|
182
183
|
|
|
184
|
+
const handle_invalid_url = normalise_error_handler(
|
|
185
|
+
log,
|
|
186
|
+
config.prerender.handleInvalidUrl,
|
|
187
|
+
({ href, referrer }) => {
|
|
188
|
+
return `Invalid URL ${href}${referrer ? ` (linked from ${referrer})` : ''}`;
|
|
189
|
+
}
|
|
190
|
+
);
|
|
191
|
+
|
|
183
192
|
const q = queue(config.prerender.concurrency);
|
|
184
193
|
|
|
185
194
|
/**
|
|
@@ -210,6 +219,8 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
210
219
|
|
|
211
220
|
const seen = new Set();
|
|
212
221
|
const written = new Set();
|
|
222
|
+
|
|
223
|
+
/** @type {Map<string, Promise<any>>} */
|
|
213
224
|
const remote_responses = new Map();
|
|
214
225
|
|
|
215
226
|
/** @type {Map<string, Set<string>>} */
|
|
@@ -249,7 +260,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
249
260
|
/** @type {Map<string, import('types').PrerenderDependency>} */
|
|
250
261
|
const dependencies = new Map();
|
|
251
262
|
|
|
252
|
-
const response = await server.respond(new Request(
|
|
263
|
+
const response = await server.respond(new Request(prerender_origin + encoded), {
|
|
253
264
|
getClientAddress() {
|
|
254
265
|
throw new Error('Cannot read clientAddress during prerendering');
|
|
255
266
|
},
|
|
@@ -332,16 +343,20 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
332
343
|
|
|
333
344
|
// if it's a 200 HTML response, crawl it. Skip error responses, as we don't save those
|
|
334
345
|
if (response.ok && config.prerender.crawl && headers['content-type'] === 'text/html') {
|
|
335
|
-
const { ids, hrefs } = crawl(body.toString(), decoded);
|
|
346
|
+
const { ids, hrefs, invalid } = crawl(body.toString(), decoded);
|
|
347
|
+
|
|
348
|
+
for (const href of invalid) {
|
|
349
|
+
handle_invalid_url({ href, referrer: decoded });
|
|
350
|
+
}
|
|
336
351
|
|
|
337
352
|
actual_hashlinks.set(decoded, ids);
|
|
338
353
|
|
|
339
354
|
/** @param {string} href */
|
|
340
355
|
const removePrerenderOrigin = (href) => {
|
|
341
|
-
if (href.startsWith(
|
|
342
|
-
if (href ===
|
|
343
|
-
if (href.at(
|
|
344
|
-
return href.slice(
|
|
356
|
+
if (href.startsWith(prerender_origin)) {
|
|
357
|
+
if (href === prerender_origin) return '/';
|
|
358
|
+
if (href.at(prerender_origin.length) !== '/') return href;
|
|
359
|
+
return href.slice(prerender_origin.length);
|
|
345
360
|
}
|
|
346
361
|
return href;
|
|
347
362
|
};
|
|
@@ -386,6 +401,12 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
386
401
|
const type = headers['content-type'];
|
|
387
402
|
const is_html = response_type === REDIRECT || type === 'text/html';
|
|
388
403
|
|
|
404
|
+
if (!is_html && response.status === 200 && decoded.slice(config.paths.base.length + 1) === '') {
|
|
405
|
+
throw new Error(
|
|
406
|
+
`Cannot prerender a root +server.js that returns a non-HTML response - static hosts always serve an HTML file for \`${config.paths.base || '/'}\``
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
|
|
389
410
|
const file = output_filename(decoded, is_html);
|
|
390
411
|
const dest = `${config.outDir}/output/prerendered/${category}/${file}`;
|
|
391
412
|
|
|
@@ -495,10 +516,8 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
495
516
|
}
|
|
496
517
|
}
|
|
497
518
|
|
|
498
|
-
// the user's remote function modules may reference
|
|
499
|
-
//
|
|
500
|
-
// evaluating those modules to avoid potential runtime errors
|
|
501
|
-
internal.set_env(env);
|
|
519
|
+
// the user's remote function modules may reference `read` or the `manifest` at the top-level
|
|
520
|
+
// so we need to set them before evaluating those modules to avoid potential runtime errors
|
|
502
521
|
internal.set_manifest(manifest);
|
|
503
522
|
internal.set_read_implementation((file) => createReadableStream(`${out}/server/${file}`));
|
|
504
523
|
|