@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "1.15.5",
3
+ "version": "1.15.7",
4
4
  "description": "The fastest way to build Svelte apps",
5
5
  "repository": {
6
6
  "type": "git",
@@ -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('fail', (input, keypath) => {
205
- if (typeof input === 'function') return input;
206
- if (['fail', 'warn', 'ignore'].includes(input)) return input;
207
- throw new Error(`${keypath} should be "fail", "warn", "ignore" or a custom function`);
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('fail', (input, keypath) => {
211
- if (typeof input === 'function') return input;
212
- if (['fail', 'warn', 'ignore'].includes(input)) return input;
213
- throw new Error(`${keypath} should be "fail", "warn", "ignore" or a custom function`);
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
- mkdirp(dirname(dest));
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, url } = await resolve(
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 some Firefox-specific cutoff because it (impressively) maintains the stack
33
- // across events and for example traces a `fetch` call triggered from a button back
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 firefox_cutoff = stack_array.findIndex((a) => a.includes('*listen@'));
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
- return { url, external, target };
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
- const res = await fetch(`${assets}/${__SVELTEKIT_APP_VERSION_FILE__}`, {
235
- headers: {
236
- pragma: 'no-cache',
237
- 'cache-control': 'no-cache'
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
- } else {
252
- throw new Error(`Version check failed: ${res.status}`);
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 action_json({
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
- if (segments.length === 1 && paths.base !== '') {
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
- base_expression = `new URL(${s(base)}, location).pathname`;
105
- } else {
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
- `element: document.currentScript.parentElement`
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`, `${global}.element`];
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 (route.page) {
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;
@@ -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 */