@sveltejs/kit 1.8.4 → 1.8.6
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/exports/vite/index.js +24 -20
- package/src/runtime/server/data/index.js +0 -2
- package/src/runtime/server/endpoint.js +2 -5
- package/src/runtime/server/fetch.js +4 -1
- package/src/runtime/server/index.js +5 -1
- package/src/runtime/server/page/index.js +9 -7
- package/src/runtime/server/page/respond_with_error.js +2 -7
- package/src/runtime/server/respond.js +13 -15
- package/src/runtime/server/utils.js +0 -5
- package/types/index.d.ts +2 -2
- package/types/internal.d.ts +8 -14
package/package.json
CHANGED
|
@@ -218,6 +218,21 @@ function kit({ svelte_config }) {
|
|
|
218
218
|
|
|
219
219
|
const generated = path.posix.join(kit.outDir, 'generated');
|
|
220
220
|
|
|
221
|
+
// This ensures that esm-env is inlined into the server output with the
|
|
222
|
+
// export conditions resolved correctly through Vite. This prevents adapters
|
|
223
|
+
// that bundle later on from resolving the export conditions incorrectly
|
|
224
|
+
// and for example include browser-only code in the server output
|
|
225
|
+
// because they for example use esbuild.build with `platform: 'browser'`
|
|
226
|
+
const noExternal = ['esm-env'];
|
|
227
|
+
|
|
228
|
+
// Vitest bypasses Vite when loading external modules, so we bundle
|
|
229
|
+
// when it is detected to keep our virtual modules working.
|
|
230
|
+
// See https://github.com/sveltejs/kit/pull/9172
|
|
231
|
+
// and https://vitest.dev/config/#deps-registernodeloader
|
|
232
|
+
if (process.env.TEST) {
|
|
233
|
+
noExternal.push('@sveltejs/kit');
|
|
234
|
+
}
|
|
235
|
+
|
|
221
236
|
// dev and preview config can be shared
|
|
222
237
|
/** @type {import('vite').UserConfig} */
|
|
223
238
|
const new_config = {
|
|
@@ -252,6 +267,9 @@ function kit({ svelte_config }) {
|
|
|
252
267
|
'$app',
|
|
253
268
|
'$env'
|
|
254
269
|
]
|
|
270
|
+
},
|
|
271
|
+
ssr: {
|
|
272
|
+
noExternal
|
|
255
273
|
}
|
|
256
274
|
};
|
|
257
275
|
|
|
@@ -267,19 +285,6 @@ function kit({ svelte_config }) {
|
|
|
267
285
|
__SVELTEKIT_EMBEDDED__: kit.embedded ? 'true' : 'false'
|
|
268
286
|
};
|
|
269
287
|
|
|
270
|
-
new_config.ssr = {
|
|
271
|
-
noExternal: [
|
|
272
|
-
// TODO document why this is necessary
|
|
273
|
-
'@sveltejs/kit',
|
|
274
|
-
// This ensures that esm-env is inlined into the server output with the
|
|
275
|
-
// export conditions resolved correctly through Vite. This prevents adapters
|
|
276
|
-
// that bundle later on to resolve the export conditions incorrectly
|
|
277
|
-
// and for example include browser-only code in the server output
|
|
278
|
-
// because they for example use esbuild.build with `platform: 'browser'`
|
|
279
|
-
'esm-env'
|
|
280
|
-
]
|
|
281
|
-
};
|
|
282
|
-
|
|
283
288
|
if (!secondary_build_started) {
|
|
284
289
|
manifest_data = (await sync.all(svelte_config, config_env.mode)).manifest_data;
|
|
285
290
|
}
|
|
@@ -290,13 +295,12 @@ function kit({ svelte_config }) {
|
|
|
290
295
|
__SVELTEKIT_EMBEDDED__: kit.embedded ? 'true' : 'false'
|
|
291
296
|
};
|
|
292
297
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
};
|
|
298
|
+
// These Kit dependencies are packaged as CommonJS, which means they must always be externalized.
|
|
299
|
+
// Without this, the tests will still pass but `pnpm dev` will fail in projects that link `@sveltejs/kit`.
|
|
300
|
+
/** @type {NonNullable<import('vite').UserConfig['ssr']>} */ (new_config.ssr).external = [
|
|
301
|
+
'cookie',
|
|
302
|
+
'set-cookie-parser'
|
|
303
|
+
];
|
|
300
304
|
}
|
|
301
305
|
|
|
302
306
|
warn_overridden_config(config, new_config);
|
|
@@ -4,12 +4,11 @@ import { method_not_allowed } from './utils.js';
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @param {import('types').RequestEvent} event
|
|
7
|
-
* @param {import('types').SSRRoute} route
|
|
8
7
|
* @param {import('types').SSREndpoint} mod
|
|
9
8
|
* @param {import('types').SSRState} state
|
|
10
9
|
* @returns {Promise<Response>}
|
|
11
10
|
*/
|
|
12
|
-
export async function render_endpoint(event,
|
|
11
|
+
export async function render_endpoint(event, mod, state) {
|
|
13
12
|
const method = /** @type {import('types').HttpMethod} */ (event.request.method);
|
|
14
13
|
|
|
15
14
|
let handler = mod[method];
|
|
@@ -29,7 +28,7 @@ export async function render_endpoint(event, route, mod, state) {
|
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
if (state.prerendering && !prerender) {
|
|
32
|
-
if (state.
|
|
31
|
+
if (state.depth > 0) {
|
|
33
32
|
// if request came from a prerendered page, bail
|
|
34
33
|
throw new Error(`${event.route.id} is not prerenderable`);
|
|
35
34
|
} else {
|
|
@@ -39,8 +38,6 @@ export async function render_endpoint(event, route, mod, state) {
|
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
40
|
|
|
42
|
-
state.initiator = route;
|
|
43
|
-
|
|
44
41
|
try {
|
|
45
42
|
const response = await handler(
|
|
46
43
|
/** @type {import('types').RequestEvent<Record<string, any>>} */ (event)
|
|
@@ -131,7 +131,10 @@ export function create_fetch({ event, options, manifest, state, get_cookie_heade
|
|
|
131
131
|
);
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
response = await respond(request, options, manifest,
|
|
134
|
+
response = await respond(request, options, manifest, {
|
|
135
|
+
...state,
|
|
136
|
+
depth: state.depth + 1
|
|
137
|
+
});
|
|
135
138
|
|
|
136
139
|
const set_cookie = response.headers.get('set-cookie');
|
|
137
140
|
if (set_cookie) {
|
|
@@ -16,9 +16,13 @@ import { respond_with_error } from './respond_with_error.js';
|
|
|
16
16
|
import { get_option } from '../../../utils/options.js';
|
|
17
17
|
import { get_data_json } from '../data/index.js';
|
|
18
18
|
|
|
19
|
+
/**
|
|
20
|
+
* The maximum request depth permitted before assuming we're stuck in an infinite loop
|
|
21
|
+
*/
|
|
22
|
+
const MAX_DEPTH = 10;
|
|
23
|
+
|
|
19
24
|
/**
|
|
20
25
|
* @param {import('types').RequestEvent} event
|
|
21
|
-
* @param {import('types').SSRRoute} route
|
|
22
26
|
* @param {import('types').PageNodeIndexes} page
|
|
23
27
|
* @param {import('types').SSROptions} options
|
|
24
28
|
* @param {import('types').SSRManifest} manifest
|
|
@@ -26,16 +30,14 @@ import { get_data_json } from '../data/index.js';
|
|
|
26
30
|
* @param {import('types').RequiredResolveOptions} resolve_opts
|
|
27
31
|
* @returns {Promise<Response>}
|
|
28
32
|
*/
|
|
29
|
-
export async function render_page(event,
|
|
30
|
-
if (state.
|
|
33
|
+
export async function render_page(event, page, options, manifest, state, resolve_opts) {
|
|
34
|
+
if (state.depth > MAX_DEPTH) {
|
|
31
35
|
// infinite request cycle detected
|
|
32
36
|
return text(`Not found: ${event.url.pathname}`, {
|
|
33
|
-
status: 404
|
|
37
|
+
status: 404 // TODO in some cases this should be 500. not sure how to differentiate
|
|
34
38
|
});
|
|
35
39
|
}
|
|
36
40
|
|
|
37
|
-
state.initiator = route;
|
|
38
|
-
|
|
39
41
|
if (is_action_json_request(event)) {
|
|
40
42
|
const node = await manifest._.nodes[page.leaf]();
|
|
41
43
|
return handle_action_json_request(event, options, node?.server);
|
|
@@ -322,7 +324,7 @@ export async function render_page(event, route, page, options, manifest, state,
|
|
|
322
324
|
fetched
|
|
323
325
|
});
|
|
324
326
|
} catch (e) {
|
|
325
|
-
// if we end up here, it means the data loaded
|
|
327
|
+
// if we end up here, it means the data loaded successfully
|
|
326
328
|
// but the page failed to render, or that a prerendering error occurred
|
|
327
329
|
return await respond_with_error({
|
|
328
330
|
event,
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { render_response } from './render.js';
|
|
2
2
|
import { load_data, load_server_data } from './load_data.js';
|
|
3
|
-
import {
|
|
4
|
-
handle_error_and_jsonify,
|
|
5
|
-
static_error_page,
|
|
6
|
-
redirect_response,
|
|
7
|
-
GENERIC_ERROR
|
|
8
|
-
} from '../utils.js';
|
|
3
|
+
import { handle_error_and_jsonify, static_error_page, redirect_response } from '../utils.js';
|
|
9
4
|
import { get_option } from '../../../utils/options.js';
|
|
10
5
|
import { HttpError, Redirect } from '../../control.js';
|
|
11
6
|
|
|
@@ -43,7 +38,7 @@ export async function respond_with_error({
|
|
|
43
38
|
const csr = get_option([default_layout], 'csr') ?? true;
|
|
44
39
|
|
|
45
40
|
if (ssr) {
|
|
46
|
-
state.
|
|
41
|
+
state.error = true;
|
|
47
42
|
|
|
48
43
|
const server_data_promise = load_server_data({
|
|
49
44
|
event,
|
|
@@ -5,7 +5,7 @@ import { render_page } from './page/index.js';
|
|
|
5
5
|
import { render_response } from './page/render.js';
|
|
6
6
|
import { respond_with_error } from './page/respond_with_error.js';
|
|
7
7
|
import { is_form_content_type } from '../../utils/http.js';
|
|
8
|
-
import {
|
|
8
|
+
import { handle_fatal_error, redirect_response } from './utils.js';
|
|
9
9
|
import {
|
|
10
10
|
decode_pathname,
|
|
11
11
|
decode_params,
|
|
@@ -38,7 +38,13 @@ const default_filter = () => false;
|
|
|
38
38
|
/** @type {import('types').RequiredResolveOptions['preload']} */
|
|
39
39
|
const default_preload = ({ type }) => type === 'js' || type === 'css';
|
|
40
40
|
|
|
41
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* @param {Request} request
|
|
43
|
+
* @param {import('types').SSROptions} options
|
|
44
|
+
* @param {import('types').SSRManifest} manifest
|
|
45
|
+
* @param {import('types').SSRState} state
|
|
46
|
+
* @returns {Promise<Response>}
|
|
47
|
+
*/
|
|
42
48
|
export async function respond(request, options, manifest, state) {
|
|
43
49
|
/** URL but stripped from the potential `/__data.json` suffix and its search param */
|
|
44
50
|
let url = new URL(request.url);
|
|
@@ -358,17 +364,9 @@ export async function respond(request, options, manifest, state) {
|
|
|
358
364
|
trailing_slash ?? 'never'
|
|
359
365
|
);
|
|
360
366
|
} else if (route.endpoint && (!route.page || is_endpoint_request(event))) {
|
|
361
|
-
response = await render_endpoint(event,
|
|
367
|
+
response = await render_endpoint(event, await route.endpoint(), state);
|
|
362
368
|
} else if (route.page) {
|
|
363
|
-
response = await render_page(
|
|
364
|
-
event,
|
|
365
|
-
route,
|
|
366
|
-
route.page,
|
|
367
|
-
options,
|
|
368
|
-
manifest,
|
|
369
|
-
state,
|
|
370
|
-
resolve_opts
|
|
371
|
-
);
|
|
369
|
+
response = await render_page(event, route.page, options, manifest, state, resolve_opts);
|
|
372
370
|
} else {
|
|
373
371
|
// a route will always have a page or an endpoint, but TypeScript
|
|
374
372
|
// doesn't know that
|
|
@@ -378,15 +376,15 @@ export async function respond(request, options, manifest, state) {
|
|
|
378
376
|
return response;
|
|
379
377
|
}
|
|
380
378
|
|
|
381
|
-
if (state.
|
|
379
|
+
if (state.error) {
|
|
382
380
|
return text('Internal Server Error', {
|
|
383
381
|
status: 500
|
|
384
382
|
});
|
|
385
383
|
}
|
|
386
384
|
|
|
387
385
|
// if this request came direct from the user, rather than
|
|
388
|
-
// via
|
|
389
|
-
if (
|
|
386
|
+
// via our own `fetch`, render a 404 page
|
|
387
|
+
if (state.depth === 0) {
|
|
390
388
|
return await respond_with_error({
|
|
391
389
|
event,
|
|
392
390
|
options,
|
|
@@ -16,11 +16,6 @@ export function is_pojo(body) {
|
|
|
16
16
|
return true;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
/** @type {import('types').SSRErrorPage} */
|
|
20
|
-
export const GENERIC_ERROR = {
|
|
21
|
-
id: '__error'
|
|
22
|
-
};
|
|
23
|
-
|
|
24
19
|
/**
|
|
25
20
|
* @param {Partial<Record<import('types').HttpMethod, any>>} mod
|
|
26
21
|
* @param {import('types').HttpMethod} method
|
package/types/index.d.ts
CHANGED
|
@@ -539,7 +539,7 @@ export interface KitConfig {
|
|
|
539
539
|
* Client-side navigation can be buggy if you deploy a new version of your app while people are using it. If the code for the new page is already loaded, it may have stale content; if it isn't, the app's route manifest may point to a JavaScript file that no longer exists.
|
|
540
540
|
* SvelteKit helps you solve this problem through version management.
|
|
541
541
|
* If SvelteKit encounters an error while loading the page and detects that a new version has been deployed (using the `name` specified here, which defaults to a timestamp of the build) it will fall back to traditional full-page navigation.
|
|
542
|
-
* Not all navigations will result in an error though, for example if the JavaScript for the next page is already loaded. If you still want to force a full-page navigation in these cases, use techniques such as setting the `
|
|
542
|
+
* Not all navigations will result in an error though, for example if the JavaScript for the next page is already loaded. If you still want to force a full-page navigation in these cases, use techniques such as setting the `pollInterval` and then using `beforeNavigate`:
|
|
543
543
|
* ```html
|
|
544
544
|
* /// +layout.svelte
|
|
545
545
|
* <script>
|
|
@@ -558,7 +558,7 @@ export interface KitConfig {
|
|
|
558
558
|
*/
|
|
559
559
|
version?: {
|
|
560
560
|
/**
|
|
561
|
-
* 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
|
|
561
|
+
* 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
|
|
562
562
|
*/
|
|
563
563
|
name?: string;
|
|
564
564
|
/**
|
package/types/internal.d.ts
CHANGED
|
@@ -157,15 +157,6 @@ export type RecursiveRequired<T> = {
|
|
|
157
157
|
|
|
158
158
|
export type RequiredResolveOptions = Required<ResolveOptions>;
|
|
159
159
|
|
|
160
|
-
export interface Respond {
|
|
161
|
-
(
|
|
162
|
-
request: Request,
|
|
163
|
-
options: SSROptions,
|
|
164
|
-
manifest: SSRManifest,
|
|
165
|
-
state: SSRState
|
|
166
|
-
): Promise<Response>;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
160
|
export interface RouteParam {
|
|
170
161
|
name: string;
|
|
171
162
|
matcher: string;
|
|
@@ -353,10 +344,6 @@ export interface SSROptions {
|
|
|
353
344
|
version_hash: string;
|
|
354
345
|
}
|
|
355
346
|
|
|
356
|
-
export interface SSRErrorPage {
|
|
357
|
-
id: '__error';
|
|
358
|
-
}
|
|
359
|
-
|
|
360
347
|
export interface PageNodeIndexes {
|
|
361
348
|
errors: Array<number | undefined>;
|
|
362
349
|
layouts: Array<number | undefined>;
|
|
@@ -381,7 +368,14 @@ export interface SSRRoute {
|
|
|
381
368
|
export interface SSRState {
|
|
382
369
|
fallback?: string;
|
|
383
370
|
getClientAddress(): string;
|
|
384
|
-
|
|
371
|
+
/**
|
|
372
|
+
* True if we're currently attempting to render an error page
|
|
373
|
+
*/
|
|
374
|
+
error: boolean;
|
|
375
|
+
/**
|
|
376
|
+
* Allows us to prevent `event.fetch` from making infinitely looping internal requests
|
|
377
|
+
*/
|
|
378
|
+
depth: number;
|
|
385
379
|
platform?: any;
|
|
386
380
|
prerendering?: PrerenderOptions;
|
|
387
381
|
/**
|