@sveltejs/kit 1.15.5 → 1.15.7
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 +1 -1
- package/src/core/config/options.js +26 -10
- package/src/core/postbuild/prerender.js +17 -2
- package/src/exports/vite/build/build_server.js +1 -2
- package/src/exports/vite/dev/index.js +1 -2
- package/src/runtime/client/client.js +7 -5
- package/src/runtime/client/fetcher.js +5 -7
- package/src/runtime/client/utils.js +16 -11
- package/src/runtime/server/page/actions.js +12 -5
- package/src/runtime/server/page/render.js +8 -18
- package/src/runtime/server/respond.js +8 -1
- package/types/internal.d.ts +0 -2
package/package.json
CHANGED
|
@@ -162,7 +162,7 @@ export function create_builder({
|
|
|
162
162
|
relative_path: relativePath,
|
|
163
163
|
routes: subset
|
|
164
164
|
? subset.map((route) => /** @type {import('types').RouteData} */ (lookup.get(route)))
|
|
165
|
-
: route_data
|
|
165
|
+
: route_data.filter((route) => prerender_map.get(route.id) !== true)
|
|
166
166
|
});
|
|
167
167
|
},
|
|
168
168
|
|
|
@@ -201,17 +201,33 @@ const options = object(
|
|
|
201
201
|
return input;
|
|
202
202
|
}),
|
|
203
203
|
|
|
204
|
-
handleHttpError: validate(
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
204
|
+
handleHttpError: validate(
|
|
205
|
+
(/** @type {any} */ { message }) => {
|
|
206
|
+
throw new Error(
|
|
207
|
+
message +
|
|
208
|
+
`\nTo suppress or handle this error, implement \`handleHttpError\` in https://kit.svelte.dev/docs/configuration#prerender`
|
|
209
|
+
);
|
|
210
|
+
},
|
|
211
|
+
(input, keypath) => {
|
|
212
|
+
if (typeof input === 'function') return input;
|
|
213
|
+
if (['fail', 'warn', 'ignore'].includes(input)) return input;
|
|
214
|
+
throw new Error(`${keypath} should be "fail", "warn", "ignore" or a custom function`);
|
|
215
|
+
}
|
|
216
|
+
),
|
|
209
217
|
|
|
210
|
-
handleMissingId: validate(
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
218
|
+
handleMissingId: validate(
|
|
219
|
+
(/** @type {any} */ { message }) => {
|
|
220
|
+
throw new Error(
|
|
221
|
+
message +
|
|
222
|
+
`\nTo suppress or handle this error, implement \`handleMissingId\` in https://kit.svelte.dev/docs/configuration#prerender`
|
|
223
|
+
);
|
|
224
|
+
},
|
|
225
|
+
(input, keypath) => {
|
|
226
|
+
if (typeof input === 'function') return input;
|
|
227
|
+
if (['fail', 'warn', 'ignore'].includes(input)) return input;
|
|
228
|
+
throw new Error(`${keypath} should be "fail", "warn", "ignore" or a custom function`);
|
|
229
|
+
}
|
|
230
|
+
),
|
|
215
231
|
|
|
216
232
|
origin: validate('http://sveltekit-prerender', (input, keypath) => {
|
|
217
233
|
assert_string(input, keypath);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
1
|
+
import { existsSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import { pathToFileURL } from 'node:url';
|
|
4
4
|
import { installPolyfills } from '../../exports/node/polyfills.js';
|
|
@@ -338,7 +338,22 @@ async function prerender({ out, manifest_path, metadata, verbose, env }) {
|
|
|
338
338
|
}
|
|
339
339
|
|
|
340
340
|
if (response.status === 200) {
|
|
341
|
-
|
|
341
|
+
if (existsSync(dest) && statSync(dest).isDirectory()) {
|
|
342
|
+
throw new Error(
|
|
343
|
+
`Cannot save ${decoded} as it is already a directory. See https://kit.svelte.dev/docs/page-options#prerender-route-conflicts for more information`
|
|
344
|
+
);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const dir = dirname(dest);
|
|
348
|
+
|
|
349
|
+
if (existsSync(dir) && !statSync(dir).isDirectory()) {
|
|
350
|
+
const parent = decoded.split('/').slice(0, -1).join('/');
|
|
351
|
+
throw new Error(
|
|
352
|
+
`Cannot save ${decoded} as ${parent} is already a file. See https://kit.svelte.dev/docs/page-options#prerender-route-conflicts for more information`
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
mkdirp(dir);
|
|
342
357
|
|
|
343
358
|
log.info(`${response.status} ${decoded}`);
|
|
344
359
|
writeFileSync(dest, body);
|
|
@@ -57,8 +57,7 @@ export function build_server_nodes(out, kit, manifest_data, server_manifest, cli
|
|
|
57
57
|
exports.push(
|
|
58
58
|
`export const component = async () => (await import('../${
|
|
59
59
|
resolve_symlinks(server_manifest, node.component).chunk.file
|
|
60
|
-
}')).default
|
|
61
|
-
`export const file = '${entry.file}';` // TODO what is this?
|
|
60
|
+
}')).default;`
|
|
62
61
|
);
|
|
63
62
|
}
|
|
64
63
|
|
|
@@ -145,12 +145,11 @@ export async function dev(vite, vite_config, svelte_config) {
|
|
|
145
145
|
|
|
146
146
|
if (node.component) {
|
|
147
147
|
result.component = async () => {
|
|
148
|
-
const { module_node, module
|
|
148
|
+
const { module_node, module } = await resolve(
|
|
149
149
|
/** @type {string} */ (node.component)
|
|
150
150
|
);
|
|
151
151
|
|
|
152
152
|
module_nodes.push(module_node);
|
|
153
|
-
result.file = url.endsWith('.svelte') ? url : url + '?import'; // TODO what is this for?
|
|
154
153
|
|
|
155
154
|
return module.default;
|
|
156
155
|
};
|
|
@@ -1266,8 +1266,8 @@ export function create_client(app, target) {
|
|
|
1266
1266
|
const a = find_anchor(element, container);
|
|
1267
1267
|
if (!a) return;
|
|
1268
1268
|
|
|
1269
|
-
const { url, external } = get_link_info(a, base);
|
|
1270
|
-
if (external) return;
|
|
1269
|
+
const { url, external, download } = get_link_info(a, base);
|
|
1270
|
+
if (external || download) return;
|
|
1271
1271
|
|
|
1272
1272
|
const options = get_router_options(a);
|
|
1273
1273
|
|
|
@@ -1300,8 +1300,8 @@ export function create_client(app, target) {
|
|
|
1300
1300
|
observer.disconnect();
|
|
1301
1301
|
|
|
1302
1302
|
for (const a of container.querySelectorAll('a')) {
|
|
1303
|
-
const { url, external } = get_link_info(a, base);
|
|
1304
|
-
if (external) continue;
|
|
1303
|
+
const { url, external, download } = get_link_info(a, base);
|
|
1304
|
+
if (external || download) continue;
|
|
1305
1305
|
|
|
1306
1306
|
const options = get_router_options(a);
|
|
1307
1307
|
if (options.reload) continue;
|
|
@@ -1517,7 +1517,7 @@ export function create_client(app, target) {
|
|
|
1517
1517
|
const a = find_anchor(/** @type {Element} */ (event.composedPath()[0]), container);
|
|
1518
1518
|
if (!a) return;
|
|
1519
1519
|
|
|
1520
|
-
const { url, external, target } = get_link_info(a, base);
|
|
1520
|
+
const { url, external, target, download } = get_link_info(a, base);
|
|
1521
1521
|
if (!url) return;
|
|
1522
1522
|
|
|
1523
1523
|
// bail out before `beforeNavigate` if link opens in a different tab
|
|
@@ -1545,6 +1545,8 @@ export function create_client(app, target) {
|
|
|
1545
1545
|
)
|
|
1546
1546
|
return;
|
|
1547
1547
|
|
|
1548
|
+
if (download) return;
|
|
1549
|
+
|
|
1548
1550
|
// Ignore the following but fire beforeNavigate
|
|
1549
1551
|
if (external || options.reload) {
|
|
1550
1552
|
if (before_navigate({ url, type: 'link' })) {
|
|
@@ -29,14 +29,12 @@ if (DEV) {
|
|
|
29
29
|
// We use just the filename as the method name sometimes does not appear on the CI.
|
|
30
30
|
const url = input instanceof Request ? input.url : input.toString();
|
|
31
31
|
const stack_array = /** @type {string} */ (new Error().stack).split('\n');
|
|
32
|
-
// We need to do
|
|
33
|
-
// across events and for example traces a `fetch` call triggered from a button
|
|
34
|
-
// to the creation of the event listener and the element creation itself,
|
|
32
|
+
// We need to do a cutoff because Safari and Firefox maintain the stack
|
|
33
|
+
// across events and for example traces a `fetch` call triggered from a button
|
|
34
|
+
// back to the creation of the event listener and the element creation itself,
|
|
35
35
|
// where at some point client.js will show up, leading to false positives.
|
|
36
|
-
const
|
|
37
|
-
const stack = stack_array
|
|
38
|
-
.slice(0, firefox_cutoff !== -1 ? firefox_cutoff : undefined)
|
|
39
|
-
.join('\n');
|
|
36
|
+
const cutoff = stack_array.findIndex((a) => a.includes('load@') || a.includes('at load'));
|
|
37
|
+
const stack = stack_array.slice(0, cutoff + 2).join('\n');
|
|
40
38
|
|
|
41
39
|
const heuristic = can_inspect_stack_trace
|
|
42
40
|
? stack.includes('src/runtime/client/client.js')
|
|
@@ -133,10 +133,11 @@ export function get_link_info(a, base) {
|
|
|
133
133
|
!url ||
|
|
134
134
|
!!target ||
|
|
135
135
|
is_external_url(url, base) ||
|
|
136
|
-
(a.getAttribute('rel') || '').split(/\s+/).includes('external')
|
|
137
|
-
a.hasAttribute('download');
|
|
136
|
+
(a.getAttribute('rel') || '').split(/\s+/).includes('external');
|
|
138
137
|
|
|
139
|
-
|
|
138
|
+
const download = url?.origin === location.origin && a.hasAttribute('download');
|
|
139
|
+
|
|
140
|
+
return { url, external, target, download };
|
|
140
141
|
}
|
|
141
142
|
|
|
142
143
|
/**
|
|
@@ -231,14 +232,18 @@ export function create_updated_store() {
|
|
|
231
232
|
|
|
232
233
|
if (interval) timeout = setTimeout(check, interval);
|
|
233
234
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
235
|
+
try {
|
|
236
|
+
const res = await fetch(`${assets}/${__SVELTEKIT_APP_VERSION_FILE__}`, {
|
|
237
|
+
headers: {
|
|
238
|
+
pragma: 'no-cache',
|
|
239
|
+
'cache-control': 'no-cache'
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
if (!res.ok) {
|
|
244
|
+
return false;
|
|
238
245
|
}
|
|
239
|
-
});
|
|
240
246
|
|
|
241
|
-
if (res.ok) {
|
|
242
247
|
const data = await res.json();
|
|
243
248
|
const updated = data.version !== version;
|
|
244
249
|
|
|
@@ -248,8 +253,8 @@ export function create_updated_store() {
|
|
|
248
253
|
}
|
|
249
254
|
|
|
250
255
|
return updated;
|
|
251
|
-
}
|
|
252
|
-
|
|
256
|
+
} catch {
|
|
257
|
+
return false;
|
|
253
258
|
}
|
|
254
259
|
}
|
|
255
260
|
|
|
@@ -72,11 +72,7 @@ export async function handle_action_json_request(event, options, server) {
|
|
|
72
72
|
const err = normalize_error(e);
|
|
73
73
|
|
|
74
74
|
if (err instanceof Redirect) {
|
|
75
|
-
return
|
|
76
|
-
type: 'redirect',
|
|
77
|
-
status: err.status,
|
|
78
|
-
location: err.location
|
|
79
|
-
});
|
|
75
|
+
return action_json_redirect(err);
|
|
80
76
|
}
|
|
81
77
|
|
|
82
78
|
return action_json(
|
|
@@ -100,6 +96,17 @@ function check_incorrect_fail_use(error) {
|
|
|
100
96
|
: error;
|
|
101
97
|
}
|
|
102
98
|
|
|
99
|
+
/**
|
|
100
|
+
* @param {import('types').Redirect} redirect
|
|
101
|
+
*/
|
|
102
|
+
export function action_json_redirect(redirect) {
|
|
103
|
+
return action_json({
|
|
104
|
+
type: 'redirect',
|
|
105
|
+
status: redirect.status,
|
|
106
|
+
location: redirect.location
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
103
110
|
/**
|
|
104
111
|
* @param {import('types').ActionResult} data
|
|
105
112
|
* @param {ResponseInit} [init]
|
|
@@ -95,23 +95,12 @@ export async function render_response({
|
|
|
95
95
|
|
|
96
96
|
// if appropriate, use relative paths for greater portability
|
|
97
97
|
if (paths.relative !== false && !state.prerendering?.fallback) {
|
|
98
|
-
const segments = event.url.pathname.slice(paths.base.length).split('/');
|
|
98
|
+
const segments = event.url.pathname.slice(paths.base.length).split('/').slice(2);
|
|
99
99
|
|
|
100
|
-
|
|
101
|
-
// if we're on `/my-base-path`, relative links need to start `./my-base-path` rather than `.`
|
|
102
|
-
base = `./${paths.base.split('/').at(-1)}`;
|
|
100
|
+
base = segments.map(() => '..').join('/') || '.';
|
|
103
101
|
|
|
104
|
-
|
|
105
|
-
}
|
|
106
|
-
base =
|
|
107
|
-
segments
|
|
108
|
-
.slice(2)
|
|
109
|
-
.map(() => '..')
|
|
110
|
-
.join('/') || '.';
|
|
111
|
-
|
|
112
|
-
// resolve e.g. '../..' against current location, then remove trailing slash
|
|
113
|
-
base_expression = `new URL(${s(base)}, location).pathname.slice(0, -1)`;
|
|
114
|
-
}
|
|
102
|
+
// resolve e.g. '../..' against current location, then remove trailing slash
|
|
103
|
+
base_expression = `new URL(${s(base)}, location).pathname.slice(0, -1)`;
|
|
115
104
|
|
|
116
105
|
if (!paths.assets || (paths.assets[0] === '/' && paths.assets !== SVELTE_KIT_ASSETS)) {
|
|
117
106
|
assets = base;
|
|
@@ -303,10 +292,9 @@ export async function render_response({
|
|
|
303
292
|
const blocks = [];
|
|
304
293
|
|
|
305
294
|
const properties = [
|
|
306
|
-
`env: ${s(public_env)}`,
|
|
307
295
|
paths.assets && `assets: ${s(paths.assets)}`,
|
|
308
296
|
`base: ${base_expression}`,
|
|
309
|
-
`
|
|
297
|
+
`env: ${s(public_env)}`
|
|
310
298
|
].filter(Boolean);
|
|
311
299
|
|
|
312
300
|
if (chunks) {
|
|
@@ -329,7 +317,9 @@ export async function render_response({
|
|
|
329
317
|
${properties.join(',\n\t\t\t\t\t\t')}
|
|
330
318
|
};`);
|
|
331
319
|
|
|
332
|
-
const args = [`app`,
|
|
320
|
+
const args = [`app`, `element`];
|
|
321
|
+
|
|
322
|
+
blocks.push(`const element = document.currentScript.parentElement;`);
|
|
333
323
|
|
|
334
324
|
if (page_config.ssr) {
|
|
335
325
|
const serialized = { form: 'null', error: 'null' };
|
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
} from '../../utils/exports.js';
|
|
27
27
|
import { get_option } from '../../utils/options.js';
|
|
28
28
|
import { error, json, text } from '../../exports/index.js';
|
|
29
|
+
import { action_json_redirect, is_action_json_request } from './page/actions.js';
|
|
29
30
|
|
|
30
31
|
/* global __SVELTEKIT_ADAPTER_NAME__ */
|
|
31
32
|
|
|
@@ -175,7 +176,11 @@ export async function respond(request, options, manifest, state) {
|
|
|
175
176
|
try {
|
|
176
177
|
// determine whether we need to redirect to add/remove a trailing slash
|
|
177
178
|
if (route && !is_data_request) {
|
|
178
|
-
if
|
|
179
|
+
// if `paths.base === '/a/b/c`, then the root route is `/a/b/c/`,
|
|
180
|
+
// regardless of the `trailingSlash` route option
|
|
181
|
+
if (url.pathname === base || url.pathname === base + '/') {
|
|
182
|
+
trailing_slash = 'always';
|
|
183
|
+
} else if (route.page) {
|
|
179
184
|
const nodes = await Promise.all([
|
|
180
185
|
// we use == here rather than === because [undefined] serializes as "[null]"
|
|
181
186
|
...route.page.layouts.map((n) => (n == undefined ? n : manifest._.nodes[n]())),
|
|
@@ -309,6 +314,8 @@ export async function respond(request, options, manifest, state) {
|
|
|
309
314
|
if (e instanceof Redirect) {
|
|
310
315
|
const response = is_data_request
|
|
311
316
|
? redirect_json_response(e)
|
|
317
|
+
: route?.page && is_action_json_request(event)
|
|
318
|
+
? action_json_redirect(e)
|
|
312
319
|
: redirect_response(e.status, e.location);
|
|
313
320
|
add_cookies_to_headers(response.headers, Object.values(cookies_to_add));
|
|
314
321
|
return response;
|
package/types/internal.d.ts
CHANGED
|
@@ -290,8 +290,6 @@ export interface SSRNode {
|
|
|
290
290
|
component: SSRComponentLoader;
|
|
291
291
|
/** index into the `components` array in client/manifest.js */
|
|
292
292
|
index: number;
|
|
293
|
-
/** client-side module URL for this component */
|
|
294
|
-
file: string;
|
|
295
293
|
/** external JS files */
|
|
296
294
|
imports: string[];
|
|
297
295
|
/** external CSS files */
|