@sveltejs/kit 3.0.0-next.2 → 3.0.0-next.21
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 +62 -36
- package/src/cli.js +15 -12
- package/src/constants.js +6 -1
- package/src/core/adapt/builder.js +66 -72
- package/src/core/adapt/index.js +17 -6
- package/src/core/config/index.js +134 -80
- package/src/core/config/options.js +295 -273
- package/src/core/config/types.d.ts +1 -1
- package/src/core/env.js +146 -16
- package/src/core/generate_manifest/index.js +18 -15
- package/src/core/postbuild/analyse.js +8 -20
- package/src/core/postbuild/crawl.js +22 -6
- package/src/core/postbuild/entities.js +8 -2
- package/src/core/postbuild/fallback.js +4 -2
- package/src/core/postbuild/prerender.js +222 -70
- package/src/core/postbuild/queue.js +2 -1
- package/src/core/sync/create_manifest_data/conflict.js +1 -1
- package/src/core/sync/create_manifest_data/index.js +82 -62
- package/src/core/sync/sync.js +40 -31
- package/src/core/sync/ts.js +1 -1
- package/src/core/sync/utils.js +22 -2
- package/src/core/sync/{write_non_ambient.js → write_app_types.js} +107 -58
- package/src/core/sync/write_client_manifest.js +14 -29
- package/src/core/sync/write_env.js +7 -5
- package/src/core/sync/write_server.js +37 -45
- package/src/core/sync/write_tsconfig/index.js +274 -0
- package/src/core/sync/write_tsconfig/test-app/package.json +7 -0
- package/src/core/sync/write_tsconfig/utils.js +77 -0
- package/src/core/sync/write_tsconfig/validate.js +128 -0
- package/src/core/sync/write_types/index.js +127 -123
- package/src/core/utils.js +30 -5
- package/src/exports/env/index.js +77 -0
- package/src/exports/env/public.d.ts +55 -0
- package/src/exports/hooks/index.js +3 -9
- package/src/exports/hooks/public.d.ts +195 -0
- package/src/exports/hooks/sequence.js +9 -6
- package/src/exports/index.js +52 -29
- 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} +2 -3
- package/src/exports/internal/server/index.js +37 -0
- package/src/exports/internal/server/telemetry.js +95 -0
- package/src/exports/internal/shared.js +90 -0
- package/src/exports/node/index.js +64 -22
- package/src/exports/params/index.js +70 -0
- package/src/exports/params/public.d.ts +63 -0
- package/src/exports/public.d.ts +50 -1733
- package/src/exports/remote/index.js +11 -0
- package/src/exports/remote/public.d.ts +519 -0
- package/src/exports/url.js +86 -0
- package/src/exports/vite/build/build_server.js +54 -65
- package/src/exports/vite/build/remote.js +24 -19
- package/src/exports/vite/build/utils.js +0 -8
- package/src/exports/vite/dev/index.js +218 -146
- package/src/exports/vite/index.js +1590 -858
- package/src/exports/vite/module_ids.js +2 -2
- package/src/exports/vite/preview/index.js +40 -32
- package/src/exports/vite/public.d.ts +588 -0
- package/src/exports/vite/utils.js +84 -46
- package/src/pathname.js +55 -0
- package/src/runner.js +15 -0
- 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 → forms/index.js} +73 -42
- package/src/runtime/app/forms/public.d.ts +2 -0
- package/src/runtime/app/forms/types.d.ts +56 -0
- package/src/runtime/app/internal/transport.js +53 -0
- package/src/runtime/app/manifest/index.js +1 -0
- package/src/runtime/app/{navigation.js → navigation/index.js} +2 -1
- package/src/runtime/app/navigation/public.d.ts +237 -0
- package/src/runtime/app/paths/client.js +37 -37
- package/src/runtime/app/paths/index.js +1 -1
- package/src/runtime/app/paths/internal/client.js +34 -2
- package/src/runtime/app/paths/internal/server.js +6 -23
- package/src/runtime/app/paths/internal.d.ts +3 -0
- package/src/runtime/app/paths/public.d.ts +1 -29
- package/src/runtime/app/paths/server.js +36 -17
- package/src/runtime/app/paths/types.d.ts +11 -19
- package/src/runtime/app/server/index.js +2 -2
- package/src/runtime/app/server/public.d.ts +201 -0
- package/src/runtime/app/server/remote/command.js +13 -11
- package/src/runtime/app/server/remote/form.js +61 -39
- package/src/runtime/app/server/remote/prerender.js +45 -45
- package/src/runtime/app/server/remote/query.js +106 -108
- package/src/runtime/app/server/remote/requested.js +27 -19
- package/src/runtime/app/server/remote/shared.js +76 -76
- package/src/runtime/app/service-worker/index.js +24 -0
- package/src/runtime/app/state/client.js +4 -2
- package/src/runtime/app/state/index.js +7 -5
- package/src/runtime/app/state/public.d.ts +72 -0
- package/src/runtime/app/state/server.js +3 -0
- package/src/runtime/app/stores.js +15 -78
- package/src/runtime/client/bundle.js +1 -1
- package/src/runtime/client/client-entry.js +3 -0
- package/src/runtime/client/client.js +1336 -648
- package/src/runtime/client/constants.js +3 -6
- package/src/runtime/client/entry.js +24 -3
- package/src/runtime/client/fetcher.js +25 -25
- package/src/runtime/client/ndjson.js +1 -1
- package/src/runtime/client/parse.js +1 -1
- 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 +37 -61
- package/src/runtime/client/remote-functions/form.svelte.js +267 -178
- package/src/runtime/client/remote-functions/prerender.svelte.js +32 -11
- package/src/runtime/client/remote-functions/query/index.js +10 -17
- package/src/runtime/client/remote-functions/query/instance.svelte.js +64 -18
- package/src/runtime/client/remote-functions/query/proxy.js +5 -5
- package/src/runtime/client/remote-functions/query-batch.svelte.js +61 -70
- package/src/runtime/client/remote-functions/query-live/index.js +1 -1
- package/src/runtime/client/remote-functions/query-live/instance.svelte.js +63 -21
- package/src/runtime/client/remote-functions/query-live/iterator.js +15 -12
- package/src/runtime/client/remote-functions/query-live/proxy.js +2 -12
- package/src/runtime/client/remote-functions/shared.svelte.js +90 -65
- package/src/runtime/client/snapshots.js +147 -0
- package/src/runtime/client/state.svelte.js +94 -55
- package/src/runtime/client/stream.js +3 -2
- package/src/runtime/client/types.d.ts +13 -9
- package/src/runtime/client/utils.js +22 -110
- package/src/runtime/components/root.svelte +56 -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 +172 -61
- package/src/runtime/pathname.js +20 -32
- package/src/runtime/props.svelte.js +72 -0
- package/src/runtime/server/constants.js +0 -3
- package/src/runtime/server/cookie.js +72 -55
- package/src/runtime/server/csrf.js +65 -0
- package/src/runtime/server/data/index.js +49 -53
- package/src/runtime/server/dev.js +22 -0
- package/src/runtime/server/endpoint.js +6 -7
- package/src/runtime/server/env_module.js +0 -5
- package/src/runtime/server/errors.js +160 -0
- package/src/runtime/server/fetch.js +32 -39
- package/src/runtime/server/index.js +90 -64
- package/src/runtime/server/internal.js +71 -0
- package/src/runtime/server/page/actions.js +85 -64
- package/src/runtime/server/page/crypto.js +2 -2
- package/src/runtime/server/page/csp.js +88 -104
- package/src/runtime/server/page/data_serializer.js +24 -25
- package/src/runtime/server/page/index.js +36 -53
- package/src/runtime/server/page/load_data.js +50 -57
- package/src/runtime/server/page/render.js +173 -239
- package/src/runtime/server/page/respond_with_error.js +17 -31
- package/src/runtime/server/page/serialize_data.js +2 -13
- package/src/runtime/server/page/server_routing.js +85 -26
- package/src/runtime/server/remote-functions.js +640 -0
- package/src/runtime/server/respond.js +190 -131
- package/src/runtime/server/sourcemaps.js +183 -0
- package/src/runtime/server/state.js +53 -0
- package/src/runtime/server/utils.js +13 -155
- package/src/runtime/shared.js +20 -40
- package/src/runtime/utils.js +3 -0
- package/src/types/ambient-private.d.ts +11 -1
- package/src/types/ambient.d.ts +87 -36
- package/src/types/global-private.d.ts +25 -25
- package/src/types/internal.d.ts +163 -157
- package/src/types/private.d.ts +41 -1
- package/src/utils/error.js +28 -4
- package/src/utils/escape.js +9 -25
- package/src/utils/features.js +1 -1
- package/src/utils/filesystem.js +1 -23
- package/src/utils/fork.js +7 -2
- package/src/utils/hash.js +21 -0
- package/src/utils/http.js +8 -7
- package/src/utils/import.js +9 -2
- package/src/utils/imports.js +83 -0
- package/src/utils/mime.js +9 -0
- package/src/utils/page_nodes.js +6 -7
- package/src/utils/params.js +67 -0
- package/src/utils/regex.js +9 -0
- package/src/utils/routing.js +145 -73
- package/src/utils/shared-iterator.js +5 -0
- package/src/utils/streaming.js +14 -4
- package/src/utils/url.js +33 -2
- package/src/version.js +1 -1
- package/types/index.d.ts +2616 -2433
- package/types/index.d.ts.map +120 -106
- package/src/core/sync/write_ambient.js +0 -18
- package/src/core/sync/write_root.js +0 -148
- package/src/core/sync/write_tsconfig.js +0 -250
- package/src/exports/internal/server.js +0 -22
- package/src/exports/node/polyfills.js +0 -30
- package/src/runtime/server/app.js +0 -9
- package/src/runtime/server/remote.js +0 -457
- package/src/runtime/shared-server.js +0 -7
- package/src/runtime/telemetry/otel.js +0 -21
- package/src/runtime/telemetry/record_span.js +0 -65
- package/src/types/synthetic/$lib.md +0 -5
- /package/src/exports/internal/{remote-functions.js → server/remote-functions.js} +0 -0
- /package/src/{runtime/telemetry/noop.js → telemetry.js} +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
|
+
import { clearLine, moveCursor } from 'node:readline';
|
|
4
5
|
import { pathToFileURL } from 'node:url';
|
|
5
|
-
import {
|
|
6
|
+
import { walk } from '../../utils/filesystem.js';
|
|
6
7
|
import { posixify } from '../../utils/os.js';
|
|
7
8
|
import { noop } from '../../utils/functions.js';
|
|
8
9
|
import { decode_uri, is_root_relative, resolve } from '../../utils/url.js';
|
|
@@ -17,6 +18,7 @@ import * as devalue from 'devalue';
|
|
|
17
18
|
import { createReadableStream } from '@sveltejs/kit/node';
|
|
18
19
|
import generate_fallback from './fallback.js';
|
|
19
20
|
import { stringify_remote_arg } from '../../runtime/shared.js';
|
|
21
|
+
import { matches_content_type } from '../../utils/http.js';
|
|
20
22
|
|
|
21
23
|
export default forked(import.meta.url, prerender);
|
|
22
24
|
|
|
@@ -35,46 +37,94 @@ const SPECIAL_HASHLINKS = new Set(['', 'top']);
|
|
|
35
37
|
* verbose: boolean;
|
|
36
38
|
* env: Record<string, string>;
|
|
37
39
|
* vite_config_file: string | undefined;
|
|
40
|
+
* is_tty: boolean | undefined;
|
|
38
41
|
* }} opts
|
|
39
42
|
*/
|
|
40
|
-
async function prerender({
|
|
43
|
+
async function prerender({
|
|
44
|
+
hash,
|
|
45
|
+
out,
|
|
46
|
+
manifest_path,
|
|
47
|
+
metadata,
|
|
48
|
+
verbose,
|
|
49
|
+
env,
|
|
50
|
+
vite_config_file,
|
|
51
|
+
is_tty
|
|
52
|
+
}) {
|
|
41
53
|
/** @type {import('@sveltejs/kit').SSRManifest} */
|
|
42
54
|
const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;
|
|
43
55
|
|
|
44
56
|
/** @type {import('types').ServerInternalModule} */
|
|
45
|
-
const
|
|
57
|
+
const { set_building, set_prerendering, set_manifest, set_read_implementation, log_response } =
|
|
58
|
+
await import(pathToFileURL(`${out}/server/internal.js`).href);
|
|
59
|
+
|
|
60
|
+
// configure `import { building } from `$app/env` —
|
|
61
|
+
// essential we do this before analysing the code
|
|
62
|
+
set_building();
|
|
63
|
+
set_prerendering();
|
|
64
|
+
|
|
65
|
+
// `set_env` and `Server` live in modules that import the user's `src/env` config. We import them
|
|
66
|
+
// *after* `set_building()` so that `building`-dependent expressions resolve correctly
|
|
67
|
+
/** @type {typeof import('__sveltekit/env')} */
|
|
68
|
+
const { set_env } = await import(pathToFileURL(`${out}/server/env.js`).href);
|
|
69
|
+
set_env(env);
|
|
46
70
|
|
|
47
71
|
/** @type {import('types').ServerModule} */
|
|
48
72
|
const { Server } = await import(pathToFileURL(`${out}/server/index.js`).href);
|
|
49
73
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
internal.set_prerendering();
|
|
74
|
+
const throw_handled = () => {
|
|
75
|
+
throw new Error('__handled__');
|
|
76
|
+
};
|
|
54
77
|
|
|
55
78
|
/**
|
|
56
79
|
* @template {{message: string}} T
|
|
57
80
|
* @template {Omit<T, 'message'>} K
|
|
58
|
-
* @param {
|
|
59
|
-
* @param {'fail' | 'warn' | 'ignore' | ((details: T) => void)} input
|
|
81
|
+
* @param {string} name
|
|
82
|
+
* @param {'fail' | 'warn' | 'ignore' | undefined | ((details: T) => void)} input
|
|
60
83
|
* @param {(details: K) => string} format
|
|
61
|
-
* @returns {(details: K) => void}
|
|
84
|
+
* @returns {(details: K & { error?: unknown }) => void}
|
|
62
85
|
*/
|
|
63
|
-
function normalise_error_handler(
|
|
86
|
+
function normalise_error_handler(name, input, format) {
|
|
87
|
+
/**
|
|
88
|
+
* @param {any} details
|
|
89
|
+
*/
|
|
90
|
+
function log_failure(details) {
|
|
91
|
+
const message = format(details);
|
|
92
|
+
log.error(`\n${message}\n`);
|
|
93
|
+
}
|
|
94
|
+
|
|
64
95
|
switch (input) {
|
|
65
96
|
case 'fail':
|
|
66
97
|
return (details) => {
|
|
67
|
-
|
|
98
|
+
log_failure(details);
|
|
99
|
+
throw_handled();
|
|
68
100
|
};
|
|
69
101
|
case 'warn':
|
|
70
|
-
return
|
|
71
|
-
log.error(format(details));
|
|
72
|
-
};
|
|
102
|
+
return log_failure;
|
|
73
103
|
case 'ignore':
|
|
74
104
|
return noop;
|
|
105
|
+
case undefined: {
|
|
106
|
+
return (details) => {
|
|
107
|
+
log_failure(details);
|
|
108
|
+
|
|
109
|
+
log.err(
|
|
110
|
+
`To suppress or handle this error, implement \`${name}\` in https://svelte.dev/docs/kit/configuration#prerender\n`
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
throw_handled();
|
|
114
|
+
};
|
|
115
|
+
}
|
|
75
116
|
default:
|
|
76
|
-
|
|
77
|
-
|
|
117
|
+
return (details) => {
|
|
118
|
+
const message = format(details);
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
// @ts-expect-error TS thinks T might be of a different kind, but it's not
|
|
122
|
+
input({ ...details, message });
|
|
123
|
+
} catch (error) {
|
|
124
|
+
log.prettyError(error, import.meta.dirname);
|
|
125
|
+
throw_handled();
|
|
126
|
+
}
|
|
127
|
+
};
|
|
78
128
|
}
|
|
79
129
|
}
|
|
80
130
|
|
|
@@ -103,21 +153,23 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
103
153
|
|
|
104
154
|
const vite_config = await load_vite_config(vite_config_file);
|
|
105
155
|
|
|
106
|
-
const config = extract_svelte_config(vite_config)
|
|
156
|
+
const config = extract_svelte_config(vite_config);
|
|
157
|
+
|
|
158
|
+
const prerender_origin = config.paths.origin || 'http://sveltekit-prerender';
|
|
107
159
|
|
|
108
160
|
if (hash) {
|
|
109
161
|
const fallback = await generate_fallback({
|
|
110
162
|
manifest_path,
|
|
111
163
|
env,
|
|
112
164
|
out_dir: config.outDir,
|
|
113
|
-
origin:
|
|
165
|
+
origin: prerender_origin,
|
|
114
166
|
assets: config.files.assets
|
|
115
167
|
});
|
|
116
168
|
|
|
117
169
|
const file = output_filename('/', true);
|
|
118
170
|
const dest = `${config.outDir}/output/prerendered/pages/${file}`;
|
|
119
171
|
|
|
120
|
-
|
|
172
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
121
173
|
writeFileSync(dest, fallback);
|
|
122
174
|
|
|
123
175
|
prerendered.pages.set('/', { file });
|
|
@@ -125,13 +177,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
125
177
|
return { prerendered, prerender_map };
|
|
126
178
|
}
|
|
127
179
|
|
|
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?.();
|
|
180
|
+
const emulator = await config.adapter?.emulate?.();
|
|
135
181
|
|
|
136
182
|
/** @type {import('types').Logger} */
|
|
137
183
|
const log = logger({ verbose });
|
|
@@ -140,43 +186,58 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
140
186
|
const saved = new Map();
|
|
141
187
|
|
|
142
188
|
const handle_http_error = normalise_error_handler(
|
|
143
|
-
|
|
189
|
+
'handleHttpError',
|
|
144
190
|
config.prerender.handleHttpError,
|
|
145
191
|
({ status, path, referrer, referenceType }) => {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
192
|
+
let message = `Failed to prerender ${path}`;
|
|
193
|
+
|
|
194
|
+
if (status === 404) {
|
|
195
|
+
if (!path.startsWith(config.paths.base)) {
|
|
196
|
+
message = referrer ? `${path} (${referenceType} from ${referrer})` : path;
|
|
197
|
+
|
|
198
|
+
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\``;
|
|
199
|
+
} else if (referrer) {
|
|
200
|
+
message = `${path} was ${referenceType} from ${referrer}`;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
150
203
|
|
|
151
|
-
return
|
|
204
|
+
return message;
|
|
152
205
|
}
|
|
153
206
|
);
|
|
154
207
|
|
|
155
208
|
const handle_missing_id = normalise_error_handler(
|
|
156
|
-
|
|
209
|
+
'handleMissingId',
|
|
157
210
|
config.prerender.handleMissingId,
|
|
158
211
|
({ path, id, referrers }) => {
|
|
159
212
|
return (
|
|
160
|
-
`The following pages contain links to ${path}#${id}, but no element with id="${id}" exists on ${path}
|
|
213
|
+
`The following pages contain links to ${path}#${id}, but no element with id="${id}" exists on ${path}:` +
|
|
161
214
|
referrers.map((l) => `\n - ${l}`).join('')
|
|
162
215
|
);
|
|
163
216
|
}
|
|
164
217
|
);
|
|
165
218
|
|
|
166
219
|
const handle_entry_generator_mismatch = normalise_error_handler(
|
|
167
|
-
|
|
220
|
+
'handleEntryGeneratorMismatch',
|
|
168
221
|
config.prerender.handleEntryGeneratorMismatch,
|
|
169
222
|
({ generatedFromId, entry, matchedId }) => {
|
|
170
|
-
return `The entries export from ${generatedFromId} generated entry ${entry}, which was matched by ${matchedId
|
|
223
|
+
return `The entries export from ${generatedFromId} generated entry ${entry}, which was matched by ${matchedId === entry ? 'a static route' : matchedId}`;
|
|
171
224
|
}
|
|
172
225
|
);
|
|
173
226
|
|
|
174
227
|
const handle_not_prerendered_route = normalise_error_handler(
|
|
175
|
-
|
|
228
|
+
'handleUnseenRoutes',
|
|
176
229
|
config.prerender.handleUnseenRoutes,
|
|
177
230
|
({ routes }) => {
|
|
178
231
|
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}
|
|
232
|
+
return `The following routes were marked as prerenderable, but were not prerendered because they were not found while crawling your app:\n${list}`;
|
|
233
|
+
}
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
const handle_invalid_url = normalise_error_handler(
|
|
237
|
+
'handleInvalidUrl',
|
|
238
|
+
config.prerender.handleInvalidUrl,
|
|
239
|
+
({ href, referrer }) => {
|
|
240
|
+
return `Invalid URL ${href}${referrer ? ` (linked from ${referrer})` : ''}`;
|
|
180
241
|
}
|
|
181
242
|
);
|
|
182
243
|
|
|
@@ -210,12 +271,73 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
210
271
|
|
|
211
272
|
const seen = new Set();
|
|
212
273
|
const written = new Set();
|
|
274
|
+
|
|
275
|
+
/** @type {Map<string, Promise<any>>} */
|
|
213
276
|
const remote_responses = new Map();
|
|
214
277
|
|
|
278
|
+
/** @type {null | { clear: () => void; update: (path: string) => void; updated: number }} */
|
|
279
|
+
let progress = null;
|
|
280
|
+
|
|
281
|
+
if (is_tty) {
|
|
282
|
+
// Where possible, provide progress feedback by showing the path we're
|
|
283
|
+
// currently requesting, then clearing the line once the response comes in.
|
|
284
|
+
// This avoids the wall of text that happens when you prerender
|
|
285
|
+
// many pages and log each response
|
|
286
|
+
let current = false;
|
|
287
|
+
let mid_line = false;
|
|
288
|
+
const stdout_write = process.stdout.write;
|
|
289
|
+
const stderr_write = process.stderr.write;
|
|
290
|
+
|
|
291
|
+
/** @type {ProxyHandler<typeof stdout_write>} */
|
|
292
|
+
const track_output = {
|
|
293
|
+
apply(target, this_arg, args) {
|
|
294
|
+
const chunk = args[0];
|
|
295
|
+
if (chunk.length > 0) {
|
|
296
|
+
current = false;
|
|
297
|
+
mid_line =
|
|
298
|
+
typeof chunk === 'string' ? !chunk.endsWith('\n') : chunk[chunk.length - 1] !== 10;
|
|
299
|
+
}
|
|
300
|
+
return Reflect.apply(target, this_arg, args);
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
process.stdout.write = new Proxy(stdout_write, track_output);
|
|
305
|
+
process.stderr.write = new Proxy(stderr_write, track_output);
|
|
306
|
+
|
|
307
|
+
progress = {
|
|
308
|
+
clear: () => {
|
|
309
|
+
// If app code writes to stdout or stderr, don't move the cursor to clear
|
|
310
|
+
// the previous progress log, because that will corrupt things
|
|
311
|
+
if (!current) return;
|
|
312
|
+
|
|
313
|
+
moveCursor(process.stdout, 0, -1);
|
|
314
|
+
clearLine(process.stdout, 0);
|
|
315
|
+
},
|
|
316
|
+
|
|
317
|
+
update: (path) => {
|
|
318
|
+
if (mid_line) {
|
|
319
|
+
// app output ended mid-line — start a fresh one rather than appending to it
|
|
320
|
+
stdout_write.call(process.stdout, '\n');
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
stdout_write.call(process.stdout, `crawling ${path}\n`);
|
|
324
|
+
current = true;
|
|
325
|
+
mid_line = false;
|
|
326
|
+
},
|
|
327
|
+
|
|
328
|
+
updated: 0
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
console.log('');
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/** @type {Set<string>} */
|
|
335
|
+
const resolved_route_ids = new Set();
|
|
336
|
+
|
|
215
337
|
/** @type {Map<string, Set<string>>} */
|
|
216
338
|
const expected_hashlinks = new Map();
|
|
217
339
|
|
|
218
|
-
/** @type {Map<string, string
|
|
340
|
+
/** @type {Map<string, Set<string>>} */
|
|
219
341
|
const actual_hashlinks = new Map();
|
|
220
342
|
|
|
221
343
|
/**
|
|
@@ -249,13 +371,28 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
249
371
|
/** @type {Map<string, import('types').PrerenderDependency>} */
|
|
250
372
|
const dependencies = new Map();
|
|
251
373
|
|
|
252
|
-
|
|
374
|
+
if (progress) {
|
|
375
|
+
progress.clear();
|
|
376
|
+
progress.update(decoded);
|
|
377
|
+
|
|
378
|
+
if (Date.now() - progress.updated > 50) {
|
|
379
|
+
progress.updated = Date.now();
|
|
380
|
+
|
|
381
|
+
// without this, the update will rarely be visible, and progress will appear stuck
|
|
382
|
+
await new Promise((f) => setTimeout(f, 0));
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
const request = new Request(prerender_origin + encoded);
|
|
387
|
+
|
|
388
|
+
const response = await server.respond(request, {
|
|
253
389
|
getClientAddress() {
|
|
254
390
|
throw new Error('Cannot read clientAddress during prerendering');
|
|
255
391
|
},
|
|
256
392
|
prerendering: {
|
|
257
393
|
dependencies,
|
|
258
|
-
remote_responses
|
|
394
|
+
remote_responses,
|
|
395
|
+
resolved_route_ids
|
|
259
396
|
},
|
|
260
397
|
read: (file) => {
|
|
261
398
|
// stuff we just wrote
|
|
@@ -287,6 +424,10 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
287
424
|
});
|
|
288
425
|
}
|
|
289
426
|
|
|
427
|
+
if (response.status >= 400) {
|
|
428
|
+
log_response(response.status, request);
|
|
429
|
+
}
|
|
430
|
+
|
|
290
431
|
const body = Buffer.from(await response.arrayBuffer());
|
|
291
432
|
|
|
292
433
|
const category = decoded.startsWith(remote_prefix) ? 'data' : 'pages';
|
|
@@ -331,17 +472,25 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
331
472
|
const headers = Object.fromEntries(response.headers);
|
|
332
473
|
|
|
333
474
|
// if it's a 200 HTML response, crawl it. Skip error responses, as we don't save those
|
|
334
|
-
if (
|
|
335
|
-
|
|
475
|
+
if (
|
|
476
|
+
response.ok &&
|
|
477
|
+
config.prerender.crawl &&
|
|
478
|
+
matches_content_type(headers['content-type'], 'text/html')
|
|
479
|
+
) {
|
|
480
|
+
const { ids, hrefs, invalid } = crawl(body.toString(), decoded);
|
|
336
481
|
|
|
337
|
-
|
|
482
|
+
for (const href of invalid) {
|
|
483
|
+
handle_invalid_url({ href, referrer: decoded });
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
actual_hashlinks.set(decoded, new Set(ids));
|
|
338
487
|
|
|
339
488
|
/** @param {string} href */
|
|
340
489
|
const removePrerenderOrigin = (href) => {
|
|
341
|
-
if (href.startsWith(
|
|
342
|
-
if (href ===
|
|
343
|
-
if (href.at(
|
|
344
|
-
return href.slice(
|
|
490
|
+
if (href.startsWith(prerender_origin)) {
|
|
491
|
+
if (href === prerender_origin) return '/';
|
|
492
|
+
if (href.at(prerender_origin.length) !== '/') return href;
|
|
493
|
+
return href.slice(prerender_origin.length);
|
|
345
494
|
}
|
|
346
495
|
return href;
|
|
347
496
|
};
|
|
@@ -384,7 +533,13 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
384
533
|
const headers = Object.fromEntries(response.headers);
|
|
385
534
|
|
|
386
535
|
const type = headers['content-type'];
|
|
387
|
-
const is_html = response_type === REDIRECT || type
|
|
536
|
+
const is_html = response_type === REDIRECT || matches_content_type(type, 'text/html');
|
|
537
|
+
|
|
538
|
+
if (!is_html && response.status === 200 && decoded.slice(config.paths.base.length + 1) === '') {
|
|
539
|
+
throw new Error(
|
|
540
|
+
`Cannot prerender a root +server.js that returns a non-HTML response - static hosts always serve an HTML file for \`${config.paths.base || '/'}\``
|
|
541
|
+
);
|
|
542
|
+
}
|
|
388
543
|
|
|
389
544
|
const file = output_filename(decoded, is_html);
|
|
390
545
|
const dest = `${config.outDir}/output/prerendered/${category}/${file}`;
|
|
@@ -405,9 +560,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
405
560
|
}
|
|
406
561
|
|
|
407
562
|
if (!headers['x-sveltekit-normalize']) {
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
log.warn(`${response.status} ${decoded} -> ${location}`);
|
|
563
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
411
564
|
|
|
412
565
|
writeFileSync(
|
|
413
566
|
dest,
|
|
@@ -453,9 +606,8 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
453
606
|
);
|
|
454
607
|
}
|
|
455
608
|
|
|
456
|
-
|
|
609
|
+
mkdirSync(dir, { recursive: true });
|
|
457
610
|
|
|
458
|
-
log.info(`${response.status} ${decoded}`);
|
|
459
611
|
writeFileSync(dest, body);
|
|
460
612
|
written.add(file);
|
|
461
613
|
|
|
@@ -471,7 +623,12 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
471
623
|
|
|
472
624
|
prerendered.paths.push(decoded);
|
|
473
625
|
} else if (response_type !== OK) {
|
|
474
|
-
handle_http_error({
|
|
626
|
+
handle_http_error({
|
|
627
|
+
status: response.status,
|
|
628
|
+
path: decoded,
|
|
629
|
+
referrer,
|
|
630
|
+
referenceType
|
|
631
|
+
});
|
|
475
632
|
}
|
|
476
633
|
|
|
477
634
|
manifest.assets.add(file);
|
|
@@ -495,12 +652,10 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
495
652
|
}
|
|
496
653
|
}
|
|
497
654
|
|
|
498
|
-
// the user's remote function modules may reference
|
|
499
|
-
//
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
internal.set_manifest(manifest);
|
|
503
|
-
internal.set_read_implementation((file) => createReadableStream(`${out}/server/${file}`));
|
|
655
|
+
// the user's remote function modules may reference `read` or the `manifest` at the top-level
|
|
656
|
+
// so we need to set them before evaluating those modules to avoid potential runtime errors
|
|
657
|
+
set_manifest(manifest);
|
|
658
|
+
set_read_implementation((file) => createReadableStream(`${out}/server/${file}`));
|
|
504
659
|
|
|
505
660
|
/** @type {Array<import('types').RemotePrerenderInternals>} */
|
|
506
661
|
const prerender_functions = [];
|
|
@@ -554,14 +709,10 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
554
709
|
}
|
|
555
710
|
}
|
|
556
711
|
|
|
557
|
-
const transport = (await internal.get_hooks()).transport ?? {};
|
|
558
712
|
for (const internals of prerender_functions) {
|
|
559
713
|
if (internals.has_arg) {
|
|
560
714
|
for (const arg of (await internals.inputs?.()) ?? []) {
|
|
561
|
-
void enqueue(
|
|
562
|
-
null,
|
|
563
|
-
remote_prefix + internals.id + '/' + stringify_remote_arg(arg, transport)
|
|
564
|
-
);
|
|
715
|
+
void enqueue(null, remote_prefix + internals.id + '/' + stringify_remote_arg(arg));
|
|
565
716
|
}
|
|
566
717
|
} else {
|
|
567
718
|
void enqueue(null, remote_prefix + internals.id);
|
|
@@ -569,6 +720,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
569
720
|
}
|
|
570
721
|
|
|
571
722
|
await q.done();
|
|
723
|
+
progress?.clear();
|
|
572
724
|
|
|
573
725
|
// handle invalid fragment links
|
|
574
726
|
for (const [key, referrers] of expected_hashlinks) {
|
|
@@ -580,7 +732,7 @@ async function prerender({ hash, out, manifest_path, metadata, verbose, env, vit
|
|
|
580
732
|
// ignore fragment links to pages that were not prerendered
|
|
581
733
|
if (!hashlinks) continue;
|
|
582
734
|
|
|
583
|
-
if (!hashlinks.
|
|
735
|
+
if (!hashlinks.has(id) && !SPECIAL_HASHLINKS.has(id)) {
|
|
584
736
|
handle_missing_id({ id, path, referrers: Array.from(referrers) });
|
|
585
737
|
}
|
|
586
738
|
}
|
|
@@ -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;
|
|
@@ -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 `<?*>`
|