@sveltejs/kit 1.5.2 → 1.5.5
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 +1 -1
- package/src/core/adapt/builder.js +8 -23
- package/src/core/postbuild/fallback.js +40 -29
- package/src/exports/node/polyfills.js +7 -2
- package/src/exports/vite/index.js +9 -1
- package/src/runtime/app/stores.js +18 -3
- package/src/runtime/client/client.js +26 -10
- package/src/runtime/server/page/render.js +26 -1
- package/src/runtime/server/utils.js +1 -1
- package/types/ambient.d.ts +7 -1
- package/types/index.d.ts +3 -2
package/package.json
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import { fork } from 'node:child_process';
|
|
2
1
|
import { existsSync, statSync, createReadStream, createWriteStream } from 'node:fs';
|
|
3
2
|
import { pipeline } from 'node:stream';
|
|
4
|
-
import { fileURLToPath } from 'node:url';
|
|
5
3
|
import { promisify } from 'node:util';
|
|
6
4
|
import zlib from 'node:zlib';
|
|
7
5
|
import glob from 'tiny-glob';
|
|
@@ -9,6 +7,8 @@ import { copy, rimraf, mkdirp } from '../../utils/filesystem.js';
|
|
|
9
7
|
import { generate_manifest } from '../generate_manifest/index.js';
|
|
10
8
|
import { get_route_segments } from '../../utils/routing.js';
|
|
11
9
|
import { get_env } from '../../exports/vite/utils.js';
|
|
10
|
+
import generate_fallback from '../postbuild/fallback.js';
|
|
11
|
+
import { write } from '../sync/utils.js';
|
|
12
12
|
|
|
13
13
|
const pipe = promisify(pipeline);
|
|
14
14
|
|
|
@@ -142,31 +142,16 @@ export function create_builder({
|
|
|
142
142
|
}
|
|
143
143
|
},
|
|
144
144
|
|
|
145
|
-
generateFallback(dest) {
|
|
146
|
-
// do prerendering in a subprocess so any dangling stuff gets killed upon completion
|
|
147
|
-
const script = fileURLToPath(new URL('../postbuild/fallback.js', import.meta.url));
|
|
148
|
-
|
|
145
|
+
async generateFallback(dest) {
|
|
149
146
|
const manifest_path = `${config.kit.outDir}/output/server/manifest-full.js`;
|
|
150
|
-
|
|
151
147
|
const env = get_env(config.kit.env, 'production');
|
|
152
148
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
[dest, manifest_path, JSON.stringify({ ...env.private, ...env.public })],
|
|
157
|
-
{
|
|
158
|
-
stdio: 'inherit'
|
|
159
|
-
}
|
|
160
|
-
);
|
|
161
|
-
|
|
162
|
-
child.on('exit', (code) => {
|
|
163
|
-
if (code) {
|
|
164
|
-
reject(new Error(`Could not create a fallback page — failed with code ${code}`));
|
|
165
|
-
} else {
|
|
166
|
-
fulfil(undefined);
|
|
167
|
-
}
|
|
168
|
-
});
|
|
149
|
+
const fallback = await generate_fallback({
|
|
150
|
+
manifest_path,
|
|
151
|
+
env: { ...env.private, ...env.public }
|
|
169
152
|
});
|
|
153
|
+
|
|
154
|
+
write(dest, fallback);
|
|
170
155
|
},
|
|
171
156
|
|
|
172
157
|
generateManifest: ({ relativePath, routes: subset }) => {
|
|
@@ -1,43 +1,54 @@
|
|
|
1
|
-
import { readFileSync
|
|
2
|
-
import {
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
|
-
import { mkdirp } from '../../utils/filesystem.js';
|
|
5
4
|
import { installPolyfills } from '../../exports/node/polyfills.js';
|
|
6
5
|
import { load_config } from '../config/index.js';
|
|
6
|
+
import { forked } from '../../utils/fork.js';
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
export default forked(import.meta.url, generate_fallback);
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
|
|
10
|
+
/**
|
|
11
|
+
* @param {{
|
|
12
|
+
* manifest_path: string;
|
|
13
|
+
* env: Record<string, string>
|
|
14
|
+
* }} opts
|
|
15
|
+
*/
|
|
16
|
+
async function generate_fallback({ manifest_path, env }) {
|
|
17
|
+
/** @type {import('types').ValidatedKitConfig} */
|
|
18
|
+
const config = (await load_config()).kit;
|
|
12
19
|
|
|
13
|
-
installPolyfills();
|
|
20
|
+
installPolyfills();
|
|
14
21
|
|
|
15
|
-
const server_root = join(config.outDir, 'output');
|
|
22
|
+
const server_root = join(config.outDir, 'output');
|
|
16
23
|
|
|
17
|
-
/** @type {import('types').ServerInternalModule} */
|
|
18
|
-
const { set_building } = await import(pathToFileURL(`${server_root}/server/internal.js`).href);
|
|
24
|
+
/** @type {import('types').ServerInternalModule} */
|
|
25
|
+
const { set_building } = await import(pathToFileURL(`${server_root}/server/internal.js`).href);
|
|
19
26
|
|
|
20
|
-
/** @type {import('types').ServerModule} */
|
|
21
|
-
const { Server } = await import(pathToFileURL(`${server_root}/server/index.js`).href);
|
|
27
|
+
/** @type {import('types').ServerModule} */
|
|
28
|
+
const { Server } = await import(pathToFileURL(`${server_root}/server/index.js`).href);
|
|
22
29
|
|
|
23
|
-
/** @type {import('types').SSRManifest} */
|
|
24
|
-
const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;
|
|
30
|
+
/** @type {import('types').SSRManifest} */
|
|
31
|
+
const manifest = (await import(pathToFileURL(manifest_path).href)).manifest;
|
|
25
32
|
|
|
26
|
-
set_building(true);
|
|
33
|
+
set_building(true);
|
|
27
34
|
|
|
28
|
-
const server = new Server(manifest);
|
|
29
|
-
await server.init({ env
|
|
35
|
+
const server = new Server(manifest);
|
|
36
|
+
await server.init({ env });
|
|
30
37
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
});
|
|
38
|
+
const response = await server.respond(new Request(config.prerender.origin + '/[fallback]'), {
|
|
39
|
+
getClientAddress: () => {
|
|
40
|
+
throw new Error('Cannot read clientAddress during prerendering');
|
|
41
|
+
},
|
|
42
|
+
prerendering: {
|
|
43
|
+
fallback: true,
|
|
44
|
+
dependencies: new Map()
|
|
45
|
+
},
|
|
46
|
+
read: (file) => readFileSync(join(config.files.assets, file))
|
|
47
|
+
});
|
|
41
48
|
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
if (response.ok) {
|
|
50
|
+
return await response.text();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
throw new Error(`Could not create a fallback page — failed with status ${response.status}`);
|
|
54
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { ReadableStream, TransformStream, WritableStream } from 'node:stream/web';
|
|
2
|
+
import buffer from 'node:buffer';
|
|
2
3
|
import { webcrypto as crypto } from 'node:crypto';
|
|
3
|
-
import { fetch, Response, Request, Headers, FormData } from 'undici';
|
|
4
|
+
import { fetch, Response, Request, Headers, FormData, File as UndiciFile } from 'undici';
|
|
5
|
+
|
|
6
|
+
// @ts-expect-error
|
|
7
|
+
const File = buffer.File ?? UndiciFile;
|
|
4
8
|
|
|
5
9
|
/** @type {Record<string, any>} */
|
|
6
10
|
const globals = {
|
|
@@ -12,7 +16,8 @@ const globals = {
|
|
|
12
16
|
ReadableStream,
|
|
13
17
|
TransformStream,
|
|
14
18
|
WritableStream,
|
|
15
|
-
FormData
|
|
19
|
+
FormData,
|
|
20
|
+
File
|
|
16
21
|
};
|
|
17
22
|
|
|
18
23
|
// exported for dev/preview and node environments
|
|
@@ -632,7 +632,15 @@ export function set_assets(path) {
|
|
|
632
632
|
// CLI args
|
|
633
633
|
mode: vite_config_env.mode,
|
|
634
634
|
logLevel: vite_config.logLevel,
|
|
635
|
-
clearScreen: vite_config.clearScreen
|
|
635
|
+
clearScreen: vite_config.clearScreen,
|
|
636
|
+
build: {
|
|
637
|
+
minify: vite_config.build.minify,
|
|
638
|
+
assetsInlineLimit: vite_config.build.assetsInlineLimit,
|
|
639
|
+
sourcemap: vite_config.build.sourcemap
|
|
640
|
+
},
|
|
641
|
+
optimizeDeps: {
|
|
642
|
+
force: vite_config.optimizeDeps.force
|
|
643
|
+
}
|
|
636
644
|
})
|
|
637
645
|
);
|
|
638
646
|
|
|
@@ -23,7 +23,7 @@ export const getStores = () => {
|
|
|
23
23
|
export const page = {
|
|
24
24
|
/** @param {(value: any) => void} fn */
|
|
25
25
|
subscribe(fn) {
|
|
26
|
-
const store = getStores().page;
|
|
26
|
+
const store = __SVELTEKIT_DEV__ ? get_store('page') : getStores().page;
|
|
27
27
|
return store.subscribe(fn);
|
|
28
28
|
}
|
|
29
29
|
};
|
|
@@ -31,7 +31,7 @@ export const page = {
|
|
|
31
31
|
/** @type {typeof import('$app/stores').navigating} */
|
|
32
32
|
export const navigating = {
|
|
33
33
|
subscribe(fn) {
|
|
34
|
-
const store = getStores().navigating;
|
|
34
|
+
const store = __SVELTEKIT_DEV__ ? get_store('navigating') : getStores().navigating;
|
|
35
35
|
return store.subscribe(fn);
|
|
36
36
|
}
|
|
37
37
|
};
|
|
@@ -39,7 +39,7 @@ export const navigating = {
|
|
|
39
39
|
/** @type {typeof import('$app/stores').updated} */
|
|
40
40
|
export const updated = {
|
|
41
41
|
subscribe(fn) {
|
|
42
|
-
const store = getStores().updated;
|
|
42
|
+
const store = __SVELTEKIT_DEV__ ? get_store('updated') : getStores().updated;
|
|
43
43
|
|
|
44
44
|
if (browser) {
|
|
45
45
|
updated.check = store.check;
|
|
@@ -55,3 +55,18 @@ export const updated = {
|
|
|
55
55
|
);
|
|
56
56
|
}
|
|
57
57
|
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @template {keyof ReturnType<typeof getStores>} Name
|
|
61
|
+
* @param {Name} name
|
|
62
|
+
* @returns {ReturnType<typeof getStores>[Name]}
|
|
63
|
+
*/
|
|
64
|
+
function get_store(name) {
|
|
65
|
+
try {
|
|
66
|
+
return getStores()[name];
|
|
67
|
+
} catch (e) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
`Cannot subscribe to '${name}' store on the server outside of a Svelte component, as it is bound to the current request via component context. This prevents state from leaking between users.`
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -221,14 +221,8 @@ export function create_client({ target }) {
|
|
|
221
221
|
});
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
/** @param {
|
|
225
|
-
async function preload_data(
|
|
226
|
-
const intent = get_navigation_intent(url, false);
|
|
227
|
-
|
|
228
|
-
if (!intent) {
|
|
229
|
-
throw new Error(`Attempted to preload a URL that does not belong to this app: ${url}`);
|
|
230
|
-
}
|
|
231
|
-
|
|
224
|
+
/** @param {import('./types').NavigationIntent} intent */
|
|
225
|
+
async function preload_data(intent) {
|
|
232
226
|
load_cache = {
|
|
233
227
|
id: intent.id,
|
|
234
228
|
promise: load_route(intent).then((result) => {
|
|
@@ -1261,7 +1255,23 @@ export function create_client({ target }) {
|
|
|
1261
1255
|
|
|
1262
1256
|
if (!options.reload) {
|
|
1263
1257
|
if (priority <= options.preload_data) {
|
|
1264
|
-
|
|
1258
|
+
const intent = get_navigation_intent(/** @type {URL} */ (url), false);
|
|
1259
|
+
if (intent) {
|
|
1260
|
+
if (__SVELTEKIT_DEV__) {
|
|
1261
|
+
preload_data(intent).then((result) => {
|
|
1262
|
+
if (result.type === 'loaded' && result.state.error) {
|
|
1263
|
+
console.warn(
|
|
1264
|
+
`Preloading data for ${intent.url.pathname} failed with the following error: ${result.state.error.message}\n` +
|
|
1265
|
+
'If this error is transient, you can ignore it. Otherwise, consider disabling preloading for this route. ' +
|
|
1266
|
+
'This route was preloaded due to a data-sveltekit-preload-data attribute. ' +
|
|
1267
|
+
'See https://kit.svelte.dev/docs/link-options for more info'
|
|
1268
|
+
);
|
|
1269
|
+
}
|
|
1270
|
+
});
|
|
1271
|
+
} else {
|
|
1272
|
+
preload_data(intent);
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1265
1275
|
} else if (priority <= options.preload_code) {
|
|
1266
1276
|
preload_code(get_url_path(/** @type {URL} */ (url)));
|
|
1267
1277
|
}
|
|
@@ -1347,7 +1357,13 @@ export function create_client({ target }) {
|
|
|
1347
1357
|
|
|
1348
1358
|
preload_data: async (href) => {
|
|
1349
1359
|
const url = new URL(href, get_base_uri(document));
|
|
1350
|
-
|
|
1360
|
+
const intent = get_navigation_intent(url, false);
|
|
1361
|
+
|
|
1362
|
+
if (!intent) {
|
|
1363
|
+
throw new Error(`Attempted to preload a URL that does not belong to this app: ${url}`);
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
await preload_data(intent);
|
|
1351
1367
|
},
|
|
1352
1368
|
|
|
1353
1369
|
preload_code,
|
|
@@ -113,7 +113,32 @@ export async function render_response({
|
|
|
113
113
|
form: form_value
|
|
114
114
|
};
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
if (__SVELTEKIT_DEV__) {
|
|
117
|
+
const fetch = globalThis.fetch;
|
|
118
|
+
let warned = false;
|
|
119
|
+
globalThis.fetch = (info, init) => {
|
|
120
|
+
if (typeof info === 'string' && !/^\w+:\/\//.test(info)) {
|
|
121
|
+
throw new Error(
|
|
122
|
+
`Cannot call \`fetch\` eagerly during server side rendering with relative URL (${info}) — put your \`fetch\` calls inside \`onMount\` or a \`load\` function instead`
|
|
123
|
+
);
|
|
124
|
+
} else if (!warned) {
|
|
125
|
+
console.warn(
|
|
126
|
+
`Avoid calling \`fetch\` eagerly during server side rendering — put your \`fetch\` calls inside \`onMount\` or a \`load\` function instead`
|
|
127
|
+
);
|
|
128
|
+
warned = true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return fetch(info, init);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
rendered = options.root.render(props);
|
|
136
|
+
} finally {
|
|
137
|
+
globalThis.fetch = fetch;
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
rendered = options.root.render(props);
|
|
141
|
+
}
|
|
117
142
|
|
|
118
143
|
for (const { node } of branch) {
|
|
119
144
|
if (node.imports) {
|
|
@@ -41,7 +41,7 @@ export function method_not_allowed(mod, method) {
|
|
|
41
41
|
export function allowed_methods(mod) {
|
|
42
42
|
const allowed = [];
|
|
43
43
|
|
|
44
|
-
for (const method
|
|
44
|
+
for (const method of ['GET', 'POST', 'PUT', 'PATCH', 'DELETE']) {
|
|
45
45
|
if (method in mod) allowed.push(method);
|
|
46
46
|
}
|
|
47
47
|
|
package/types/ambient.d.ts
CHANGED
|
@@ -292,16 +292,22 @@ declare module '$app/stores' {
|
|
|
292
292
|
|
|
293
293
|
/**
|
|
294
294
|
* A readable store whose value contains page data.
|
|
295
|
+
*
|
|
296
|
+
* On the server, this store can only be subscribed to during component initialization. In the browser, it can be subscribed to at any time.
|
|
295
297
|
*/
|
|
296
298
|
export const page: Readable<Page>;
|
|
297
299
|
/**
|
|
298
300
|
* A readable store.
|
|
299
301
|
* When navigating starts, its value is a `Navigation` object with `from`, `to`, `type` and (if `type === 'popstate'`) `delta` properties.
|
|
300
302
|
* When navigating finishes, its value reverts to `null`.
|
|
303
|
+
*
|
|
304
|
+
* On the server, this store can only be subscribed to during component initialization. In the browser, it can be subscribed to at any time.
|
|
301
305
|
*/
|
|
302
306
|
export const navigating: Readable<Navigation | null>;
|
|
303
307
|
/**
|
|
304
|
-
*
|
|
308
|
+
* A readable store whose initial value is `false`. If [`version.pollInterval`](https://kit.svelte.dev/docs/configuration#version) is a non-zero value, SvelteKit will poll for new versions of the app and update the store value to `true` when it detects one. `updated.check()` will force an immediate check, regardless of polling.
|
|
309
|
+
*
|
|
310
|
+
* On the server, this store can only be subscribed to during component initialization. In the browser, it can be subscribed to at any time.
|
|
305
311
|
*/
|
|
306
312
|
export const updated: Readable<boolean> & { check(): Promise<boolean> };
|
|
307
313
|
|
package/types/index.d.ts
CHANGED
|
@@ -304,6 +304,8 @@ export interface KitConfig {
|
|
|
304
304
|
* > When `mode` is `'auto'`, SvelteKit will use nonces for dynamically rendered pages and hashes for prerendered pages. Using nonces with prerendered pages is insecure and therefore forbidden.
|
|
305
305
|
*
|
|
306
306
|
* > Note that most [Svelte transitions](https://svelte.dev/tutorial/transition) work by creating an inline `<style>` element. If you use these in your app, you must either leave the `style-src` directive unspecified or add `unsafe-inline`.
|
|
307
|
+
*
|
|
308
|
+
* If this level of configuration is insufficient and you have more dynamic requirements, you can use the [`handle` hook](https://kit.svelte.dev/docs/hooks#server-hooks-handle) to roll your own CSP.
|
|
307
309
|
*/
|
|
308
310
|
csp?: {
|
|
309
311
|
/**
|
|
@@ -542,8 +544,7 @@ export interface KitConfig {
|
|
|
542
544
|
*/
|
|
543
545
|
version?: {
|
|
544
546
|
/**
|
|
545
|
-
* The current app version string.
|
|
546
|
-
* @default Date.now().toString()
|
|
547
|
+
* The current app version string. If specified, this must be deterministic (e.g. a commit ref rather than `Math.random()` or Date.now().toString()`), otherwise defaults to a timestamp of the build
|
|
547
548
|
*/
|
|
548
549
|
name?: string;
|
|
549
550
|
/**
|