@sveltejs/kit 2.50.2 → 2.51.0

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": "2.50.2",
3
+ "version": "2.51.0",
4
4
  "description": "SvelteKit is the fastest way to build Svelte apps",
5
5
  "keywords": [
6
6
  "framework",
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "devDependencies": {
36
36
  "@opentelemetry/api": "^1.0.0",
37
- "@playwright/test": "1.56.0",
37
+ "@playwright/test": "1.58.2",
38
38
  "@sveltejs/vite-plugin-svelte": "^6.0.0-next.3",
39
39
  "@types/connect": "^3.4.38",
40
40
  "@types/node": "^18.19.119",
@@ -62,10 +62,8 @@ export function get_tsconfig(kit) {
62
62
  config_relative('vite.config.js'),
63
63
  config_relative('vite.config.ts')
64
64
  ]);
65
- // TODO(v2): find a better way to include all src files. We can't just use routes/lib only because
66
- // people might have other folders/files in src that they want included.
67
- const src_includes = [kit.files.routes, kit.files.lib, path.resolve('src')].filter((dir) => {
68
- const relative = path.relative(path.resolve('src'), dir);
65
+ const src_includes = [kit.files.routes, kit.files.lib, kit.files.src].filter((dir) => {
66
+ const relative = path.relative(kit.files.src, dir);
69
67
  return !relative || relative.startsWith('..');
70
68
  });
71
69
  for (const dir of src_includes) {
@@ -76,10 +74,14 @@ export function get_tsconfig(kit) {
76
74
 
77
75
  // Test folder is a special case - we advocate putting tests in a top-level test folder
78
76
  // and it's not configurable (should we make it?)
79
- const test_folder = project_relative('tests');
77
+ const test_folder = project_relative('test');
80
78
  include.add(config_relative(`${test_folder}/**/*.js`));
81
79
  include.add(config_relative(`${test_folder}/**/*.ts`));
82
80
  include.add(config_relative(`${test_folder}/**/*.svelte`));
81
+ const tests_folder = project_relative('tests');
82
+ include.add(config_relative(`${tests_folder}/**/*.js`));
83
+ include.add(config_relative(`${tests_folder}/**/*.ts`));
84
+ include.add(config_relative(`${tests_folder}/**/*.svelte`));
83
85
 
84
86
  const exclude = [config_relative('node_modules/**')];
85
87
  // Add service worker to exclude list so that worker types references in it don't spill over into the rest of the app
@@ -1200,6 +1200,19 @@ export interface NavigationTarget<
1200
1200
  * The URL that is navigated to
1201
1201
  */
1202
1202
  url: URL;
1203
+ /**
1204
+ * The scroll position associated with this navigation.
1205
+ *
1206
+ * For the `from` target, this is the scroll position at the moment of navigation.
1207
+ *
1208
+ * For the `to` target, this represents the scroll position that will be or was restored:
1209
+ * - In `beforeNavigate` and `onNavigate`, this is only available for `popstate` navigations (back/forward button)
1210
+ * and will be `null` for other navigation types, since the final scroll position isn't known
1211
+ * ahead of time.
1212
+ * - In `afterNavigate`, this is always the scroll position that was applied after the navigation
1213
+ * completed.
1214
+ */
1215
+ scroll: { x: number; y: number } | null;
1203
1216
  }
1204
1217
 
1205
1218
  /**
@@ -1249,7 +1262,7 @@ export interface NavigationEnter extends NavigationBase {
1249
1262
  delta?: undefined;
1250
1263
 
1251
1264
  /**
1252
- * Dispatched `Event` object when navigation occured by `popstate` or `link`.
1265
+ * Dispatched `Event` object when navigation occurred by `popstate` or `link`.
1253
1266
  */
1254
1267
  event?: undefined;
1255
1268
  }
@@ -40,7 +40,7 @@ import {
40
40
  } from './module_ids.js';
41
41
  import { import_peer } from '../../utils/import.js';
42
42
  import { compact } from '../../utils/array.js';
43
- import { should_ignore } from './static_analysis/utils.js';
43
+ import { should_ignore, has_children } from './static_analysis/utils.js';
44
44
 
45
45
  const cwd = posixify(process.cwd());
46
46
 
@@ -112,10 +112,8 @@ const warning_preprocessor = {
112
112
  if (!filename) return;
113
113
 
114
114
  const basename = path.basename(filename);
115
- const has_children =
116
- content.includes('<slot') || (isSvelte5Plus() && content.includes('{@render'));
117
115
 
118
- if (basename.startsWith('+layout.') && !has_children) {
116
+ if (basename.startsWith('+layout.') && !has_children(content, isSvelte5Plus())) {
119
117
  const message =
120
118
  `\n${colors.bold().red(path.relative('.', filename))}\n` +
121
119
  `\`<slot />\`${isSvelte5Plus() ? ' or `{@render ...}` tag' : ''}` +
@@ -1,3 +1,20 @@
1
+ /**
2
+ * Check if content has children rendering (slot, @render, or children prop forwarding)
3
+ * @param {string} content - The markup content
4
+ * @param {boolean} is_svelte_5_plus - Whether the project uses Svelte 5+
5
+ * @returns {boolean}
6
+ */
7
+ export function has_children(content, is_svelte_5_plus) {
8
+ return (
9
+ content.includes('<slot') ||
10
+ (is_svelte_5_plus &&
11
+ (content.includes('{@render') ||
12
+ // children may be forwarded to a child component as a prop
13
+ content.includes('{children}') ||
14
+ content.includes('children={')))
15
+ );
16
+ }
17
+
1
18
  /**
2
19
  * Check if a match position is within a comment or a string
3
20
  * @param {string} content - The full content
@@ -605,7 +605,8 @@ async function initialize(result, target, hydrate) {
605
605
  to: {
606
606
  params: current.params,
607
607
  route: { id: current.route?.id ?? null },
608
- url: new URL(location.href)
608
+ url: new URL(location.href),
609
+ scroll: scroll_positions[current_history_index] ?? scroll_state()
609
610
  },
610
611
  willUnload: false,
611
612
  type: 'enter',
@@ -1463,12 +1464,13 @@ function get_page_key(url) {
1463
1464
  * intent?: import('./types.js').NavigationIntent;
1464
1465
  * delta?: number;
1465
1466
  * event?: PopStateEvent | MouseEvent;
1467
+ * scroll?: { x: number, y: number };
1466
1468
  * }} opts
1467
1469
  */
1468
- function _before_navigate({ url, type, intent, delta, event }) {
1470
+ function _before_navigate({ url, type, intent, delta, event, scroll }) {
1469
1471
  let should_block = false;
1470
1472
 
1471
- const nav = create_navigation(current, intent, url, type);
1473
+ const nav = create_navigation(current, intent, url, type, scroll ?? null);
1472
1474
 
1473
1475
  if (delta !== undefined) {
1474
1476
  nav.navigation.delta = delta;
@@ -1543,6 +1545,7 @@ async function navigate({
1543
1545
  type,
1544
1546
  delta: popped?.delta,
1545
1547
  intent,
1548
+ scroll: popped?.scroll,
1546
1549
  // @ts-ignore
1547
1550
  event
1548
1551
  });
@@ -1808,6 +1811,11 @@ async function navigate({
1808
1811
 
1809
1812
  nav.fulfil(undefined);
1810
1813
 
1814
+ // Update to.scroll to the actual scroll position after navigation completed
1815
+ if (nav.navigation.to) {
1816
+ nav.navigation.to.scroll = scroll_state();
1817
+ }
1818
+
1811
1819
  after_navigate_callbacks.forEach((fn) =>
1812
1820
  fn(/** @type {import('@sveltejs/kit').AfterNavigate} */ (nav.navigation))
1813
1821
  );
@@ -3013,20 +3021,12 @@ function reset_focus(url, scroll = null) {
3013
3021
  const history_state = history.state;
3014
3022
 
3015
3023
  resetting_focus = true;
3016
- location.replace(`#${id}`);
3024
+ location.replace(new URL(`#${id}`, location.href));
3017
3025
 
3018
- // if we're using hash routing, we need to restore the original hash after
3019
- // setting the focus with `location.replace()`. Although we're calling
3020
- // `location.replace()` again, the focus won't shift to the new hash
3021
- // unless there's an element with the ID `/pathname#hash`, etc.
3022
- if (app.hash) {
3023
- location.replace(url.hash);
3024
- }
3025
-
3026
- // but Firefox has a bug that sets the history state to `null` so we
3027
- // need to restore it after.
3028
- // See https://bugzilla.mozilla.org/show_bug.cgi?id=1199924
3029
- history.replaceState(history_state, '', url.hash);
3026
+ // Firefox has a bug that sets the history state to `null` so we need to
3027
+ // restore it after. See https://bugzilla.mozilla.org/show_bug.cgi?id=1199924
3028
+ // This is also needed to restore the original hash if we're using hash routing
3029
+ history.replaceState(history_state, '', url);
3030
3030
 
3031
3031
  // Scroll management has already happened earlier so we need to restore
3032
3032
  // the scroll position after setting the sequential focus navigation starting point
@@ -3102,8 +3102,9 @@ function reset_focus(url, scroll = null) {
3102
3102
  * @param {import('./types.js').NavigationIntent | undefined} intent
3103
3103
  * @param {URL | null} url
3104
3104
  * @param {T} type
3105
+ * @param {{ x: number, y: number } | null} [target_scroll] The scroll position for the target (for popstate navigations)
3105
3106
  */
3106
- function create_navigation(current, intent, url, type) {
3107
+ function create_navigation(current, intent, url, type, target_scroll = null) {
3107
3108
  /** @type {(value: any) => void} */
3108
3109
  let fulfil;
3109
3110
 
@@ -3123,12 +3124,14 @@ function create_navigation(current, intent, url, type) {
3123
3124
  from: {
3124
3125
  params: current.params,
3125
3126
  route: { id: current.route?.id ?? null },
3126
- url: current.url
3127
+ url: current.url,
3128
+ scroll: scroll_state()
3127
3129
  },
3128
3130
  to: url && {
3129
3131
  params: intent?.params ?? null,
3130
3132
  route: { id: intent?.route?.id ?? null },
3131
- url
3133
+ url,
3134
+ scroll: target_scroll
3132
3135
  },
3133
3136
  willUnload: !intent,
3134
3137
  type,
@@ -55,7 +55,12 @@ export function create_fetch({ event, options, manifest, state, get_cookie_heade
55
55
  request.headers.delete('origin');
56
56
  }
57
57
 
58
- if (url.origin !== event.url.origin) {
58
+ const decoded = decodeURIComponent(url.pathname);
59
+
60
+ if (
61
+ url.origin !== event.url.origin ||
62
+ (paths.base && decoded !== paths.base && !decoded.startsWith(`${paths.base}/`))
63
+ ) {
59
64
  // Allow cookie passthrough for "credentials: same-origin" and "credentials: include"
60
65
  // if SvelteKit is serving my.domain.com:
61
66
  // - domain.com WILL NOT receive cookies
@@ -77,7 +82,6 @@ export function create_fetch({ event, options, manifest, state, get_cookie_heade
77
82
  // handle fetch requests for static assets. e.g. prebaked data, etc.
78
83
  // we need to support everything the browser's fetch supports
79
84
  const prefix = paths.assets || paths.base;
80
- const decoded = decodeURIComponent(url.pathname);
81
85
  const filename = (
82
86
  decoded.startsWith(prefix) ? decoded.slice(prefix.length) : decoded
83
87
  ).slice(1);
@@ -53,21 +53,30 @@ class BaseProvider {
53
53
  /** @type {import('types').CspDirectives} */
54
54
  #directives;
55
55
 
56
- /** @type {import('types').Csp.Source[]} */
56
+ /** @type {Set<import('types').Csp.Source>} */
57
57
  #script_src;
58
58
 
59
- /** @type {import('types').Csp.Source[]} */
59
+ /** @type {Set<import('types').Csp.Source>} */
60
60
  #script_src_elem;
61
61
 
62
- /** @type {import('types').Csp.Source[]} */
62
+ /** @type {Set<import('types').Csp.Source>} */
63
63
  #style_src;
64
64
 
65
- /** @type {import('types').Csp.Source[]} */
65
+ /** @type {Set<import('types').Csp.Source>} */
66
66
  #style_src_attr;
67
67
 
68
- /** @type {import('types').Csp.Source[]} */
68
+ /** @type {Set<import('types').Csp.Source>} */
69
69
  #style_src_elem;
70
70
 
71
+ /** @type {boolean} */
72
+ script_needs_nonce;
73
+
74
+ /** @type {boolean} */
75
+ style_needs_nonce;
76
+
77
+ /** @type {boolean} */
78
+ script_needs_hash;
79
+
71
80
  /** @type {string} */
72
81
  #nonce;
73
82
 
@@ -82,11 +91,11 @@ class BaseProvider {
82
91
 
83
92
  const d = this.#directives;
84
93
 
85
- this.#script_src = [];
86
- this.#script_src_elem = [];
87
- this.#style_src = [];
88
- this.#style_src_attr = [];
89
- this.#style_src_elem = [];
94
+ this.#script_src = new Set();
95
+ this.#script_src_elem = new Set();
96
+ this.#style_src = new Set();
97
+ this.#style_src_attr = new Set();
98
+ this.#style_src_elem = new Set();
90
99
 
91
100
  const effective_script_src = d['script-src'] || d['default-src'];
92
101
  const script_src_elem = d['script-src-elem'];
@@ -162,6 +171,7 @@ class BaseProvider {
162
171
 
163
172
  this.script_needs_nonce = this.#script_needs_csp && !this.#use_hashes;
164
173
  this.style_needs_nonce = this.#style_needs_csp && !this.#use_hashes;
174
+ this.script_needs_hash = this.#script_needs_csp && this.#use_hashes;
165
175
 
166
176
  this.#nonce = nonce;
167
177
  }
@@ -174,11 +184,23 @@ class BaseProvider {
174
184
  const source = this.#use_hashes ? `sha256-${sha256(content)}` : `nonce-${this.#nonce}`;
175
185
 
176
186
  if (this.#script_src_needs_csp) {
177
- this.#script_src.push(source);
187
+ this.#script_src.add(source);
178
188
  }
179
189
 
180
190
  if (this.#script_src_elem_needs_csp) {
181
- this.#script_src_elem.push(source);
191
+ this.#script_src_elem.add(source);
192
+ }
193
+ }
194
+
195
+ /** @param {`sha256-${string}`[]} hashes */
196
+ add_script_hashes(hashes) {
197
+ for (const hash of hashes) {
198
+ if (this.#script_src_needs_csp) {
199
+ this.#script_src.add(hash);
200
+ }
201
+ if (this.#script_src_elem_needs_csp) {
202
+ this.#script_src_elem.add(hash);
203
+ }
182
204
  }
183
205
  }
184
206
 
@@ -190,11 +212,11 @@ class BaseProvider {
190
212
  const source = this.#use_hashes ? `sha256-${sha256(content)}` : `nonce-${this.#nonce}`;
191
213
 
192
214
  if (this.#style_src_needs_csp) {
193
- this.#style_src.push(source);
215
+ this.#style_src.add(source);
194
216
  }
195
217
 
196
218
  if (this.#style_src_attr_needs_csp) {
197
- this.#style_src_attr.push(source);
219
+ this.#style_src_attr.add(source);
198
220
  }
199
221
 
200
222
  if (this.#style_src_elem_needs_csp) {
@@ -207,13 +229,13 @@ class BaseProvider {
207
229
  if (
208
230
  d['style-src-elem'] &&
209
231
  !d['style-src-elem'].includes(sha256_empty_comment_hash) &&
210
- !this.#style_src_elem.includes(sha256_empty_comment_hash)
232
+ !this.#style_src_elem.has(sha256_empty_comment_hash)
211
233
  ) {
212
- this.#style_src_elem.push(sha256_empty_comment_hash);
234
+ this.#style_src_elem.add(sha256_empty_comment_hash);
213
235
  }
214
236
 
215
237
  if (source !== sha256_empty_comment_hash) {
216
- this.#style_src_elem.push(source);
238
+ this.#style_src_elem.add(source);
217
239
  }
218
240
  }
219
241
  }
@@ -230,35 +252,35 @@ class BaseProvider {
230
252
 
231
253
  const directives = { ...this.#directives };
232
254
 
233
- if (this.#style_src.length > 0) {
255
+ if (this.#style_src.size > 0) {
234
256
  directives['style-src'] = [
235
257
  ...(directives['style-src'] || directives['default-src'] || []),
236
258
  ...this.#style_src
237
259
  ];
238
260
  }
239
261
 
240
- if (this.#style_src_attr.length > 0) {
262
+ if (this.#style_src_attr.size > 0) {
241
263
  directives['style-src-attr'] = [
242
264
  ...(directives['style-src-attr'] || []),
243
265
  ...this.#style_src_attr
244
266
  ];
245
267
  }
246
268
 
247
- if (this.#style_src_elem.length > 0) {
269
+ if (this.#style_src_elem.size > 0) {
248
270
  directives['style-src-elem'] = [
249
271
  ...(directives['style-src-elem'] || []),
250
272
  ...this.#style_src_elem
251
273
  ];
252
274
  }
253
275
 
254
- if (this.#script_src.length > 0) {
276
+ if (this.#script_src.size > 0) {
255
277
  directives['script-src'] = [
256
278
  ...(directives['script-src'] || directives['default-src'] || []),
257
279
  ...this.#script_src
258
280
  ];
259
281
  }
260
282
 
261
- if (this.#script_src_elem.length > 0) {
283
+ if (this.#script_src_elem.size > 0) {
262
284
  directives['script-src-elem'] = [
263
285
  ...(directives['script-src-elem'] || []),
264
286
  ...this.#script_src_elem
@@ -351,6 +373,10 @@ export class Csp {
351
373
  this.report_only_provider = new CspReportOnlyProvider(use_hashes, reportOnly, this.nonce);
352
374
  }
353
375
 
376
+ get script_needs_hash() {
377
+ return this.csp_provider.script_needs_hash || this.report_only_provider.script_needs_hash;
378
+ }
379
+
354
380
  get script_needs_nonce() {
355
381
  return this.csp_provider.script_needs_nonce || this.report_only_provider.script_needs_nonce;
356
382
  }
@@ -365,6 +391,12 @@ export class Csp {
365
391
  this.report_only_provider.add_script(content);
366
392
  }
367
393
 
394
+ /** @param {`sha256-${string}`[]} hashes */
395
+ add_script_hashes(hashes) {
396
+ this.csp_provider.add_script_hashes(hashes);
397
+ this.report_only_provider.add_script_hashes(hashes);
398
+ }
399
+
368
400
  /** @param {string} content */
369
401
  add_style(content) {
370
402
  this.csp_provider.add_style(content);
@@ -1,5 +1,5 @@
1
1
  import { text } from '@sveltejs/kit';
2
- import { Redirect } from '@sveltejs/kit/internal';
2
+ import { HttpError, Redirect } from '@sveltejs/kit/internal';
3
3
  import { compact } from '../../../utils/array.js';
4
4
  import { get_status, normalize_error } from '../../../utils/error.js';
5
5
  import { add_data_suffix } from '../../pathname.js';
@@ -357,6 +357,11 @@ export async function render_page(
357
357
  ssr === false ? server_data_serializer(event, event_state, options) : data_serializer
358
358
  });
359
359
  } catch (e) {
360
+ // a remote function could have thrown a redirect during render
361
+ if (e instanceof Redirect) {
362
+ return redirect_response(e.status, e.location);
363
+ }
364
+
360
365
  // if we end up here, it means the data loaded successfully
361
366
  // but the page failed to render, or that a prerendering error occurred
362
367
  return await respond_with_error({
@@ -365,7 +370,7 @@ export async function render_page(
365
370
  options,
366
371
  manifest,
367
372
  state,
368
- status: 500,
373
+ status: e instanceof HttpError ? e.status : 500,
369
374
  error: e,
370
375
  resolve_opts
371
376
  });
@@ -80,17 +80,11 @@ export async function render_response({
80
80
  */
81
81
  const link_headers = new Set();
82
82
 
83
- /**
84
- * `<link>` tags that are added to prerendered responses
85
- * (note that stylesheets are always added, prerendered or not)
86
- * @type {Set<string>}
87
- */
88
- const link_tags = new Set();
89
-
90
83
  /** @type {Map<string, string>} */
91
84
  // TODO if we add a client entry point one day, we will need to include inline_styles with the entry, otherwise stylesheets will be linked even if they are below inlineStyleThreshold
92
85
  const inline_styles = new Map();
93
86
 
87
+ /** @type {ReturnType<typeof options.root.render>} */
94
88
  let rendered;
95
89
 
96
90
  const form_value =
@@ -110,6 +104,10 @@ export async function render_response({
110
104
  */
111
105
  let base_expression = s(paths.base);
112
106
 
107
+ const csp = new Csp(options.csp, {
108
+ prerender: !!state.prerendering
109
+ });
110
+
113
111
  // if appropriate, use relative paths for greater portability
114
112
  if (paths.relative) {
115
113
  if (!state.prerendering?.fallback) {
@@ -177,7 +175,8 @@ export async function render_response({
177
175
  page: props.page
178
176
  }
179
177
  ]
180
- ])
178
+ ]),
179
+ csp: csp.script_needs_nonce ? { nonce: csp.nonce } : { hash: csp.script_needs_hash }
181
180
  };
182
181
 
183
182
  const fetch = globalThis.fetch;
@@ -227,9 +226,15 @@ export async function render_response({
227
226
  paths.reset();
228
227
  }
229
228
 
230
- const { head, html, css } = options.async ? await rendered : rendered;
229
+ const { head, html, css, hashes } = /** @type {ReturnType<typeof options.root.render>} */ (
230
+ options.async ? await rendered : rendered
231
+ );
232
+
233
+ if (hashes) {
234
+ csp.add_script_hashes(hashes.script);
235
+ }
231
236
 
232
- return { head, html, css };
237
+ return { head, html, css, hashes };
233
238
  });
234
239
  } finally {
235
240
  if (DEV) {
@@ -256,16 +261,12 @@ export async function render_response({
256
261
  }
257
262
  }
258
263
  } else {
259
- rendered = { head: '', html: '', css: { code: '', map: null } };
264
+ rendered = { head: '', html: '', css: { code: '', map: null }, hashes: { script: [] } };
260
265
  }
261
266
 
262
- let head = '';
267
+ const head = new Head(rendered.head, !!state.prerendering);
263
268
  let body = rendered.html;
264
269
 
265
- const csp = new Csp(options.csp, {
266
- prerender: !!state.prerendering
267
- });
268
-
269
270
  /** @param {string} path */
270
271
  const prefixed = (path) => {
271
272
  if (path.startsWith('/')) {
@@ -283,12 +284,10 @@ export async function render_response({
283
284
  : Array.from(inline_styles.values()).join('\n');
284
285
 
285
286
  if (style) {
286
- const attributes = DEV ? [' data-sveltekit'] : [];
287
- if (csp.style_needs_nonce) attributes.push(` nonce="${csp.nonce}"`);
288
-
287
+ const attributes = DEV ? ['data-sveltekit'] : [];
288
+ if (csp.style_needs_nonce) attributes.push(`nonce="${csp.nonce}"`);
289
289
  csp.add_style(style);
290
-
291
- head += `\n\t<style${attributes.join('')}>${style}</style>`;
290
+ head.add_style(style, attributes);
292
291
  }
293
292
 
294
293
  for (const dep of stylesheets) {
@@ -306,7 +305,7 @@ export async function render_response({
306
305
  }
307
306
  }
308
307
 
309
- head += `\n\t\t<link href="${path}" ${attributes.join(' ')}>`;
308
+ head.add_stylesheet(path, attributes);
310
309
  }
311
310
 
312
311
  for (const dep of fonts) {
@@ -315,7 +314,7 @@ export async function render_response({
315
314
  if (resolve_opts.preload({ type: 'font', path })) {
316
315
  const ext = dep.slice(dep.lastIndexOf('.') + 1);
317
316
 
318
- link_tags.add(`<link rel="preload" as="font" type="font/${ext}" href="${path}" crossorigin>`);
317
+ head.add_link_tag(path, ['rel="preload"', 'as="font"', `type="font/${ext}"`, 'crossorigin']);
319
318
 
320
319
  link_headers.add(
321
320
  `<${encodeURI(path)}>; rel="preload"; as="font"; type="font/${ext}"; crossorigin; nopush`
@@ -351,19 +350,13 @@ export async function render_response({
351
350
  link_headers.add(`<${encodeURI(path)}>; rel="modulepreload"; nopush`);
352
351
 
353
352
  if (options.preload_strategy !== 'modulepreload') {
354
- head += `\n\t\t<link rel="preload" as="script" crossorigin="anonymous" href="${path}">`;
353
+ head.add_script_preload(path);
355
354
  } else {
356
- link_tags.add(`<link rel="modulepreload" href="${path}">`);
355
+ head.add_link_tag(path, ['rel="modulepreload"']);
357
356
  }
358
357
  }
359
358
  }
360
359
 
361
- if (state.prerendering && link_tags.size > 0) {
362
- head += Array.from(link_tags)
363
- .map((tag) => `\n\t\t${tag}`)
364
- .join('');
365
- }
366
-
367
360
  // prerender a `/path/to/page/__route.js` module
368
361
  if (manifest._.client.routes && state.prerendering && !state.prerendering.fallback) {
369
362
  const pathname = add_resolution_suffix(event.url.pathname);
@@ -581,19 +574,15 @@ export async function render_response({
581
574
 
582
575
  if (state.prerendering) {
583
576
  // TODO read headers set with setHeaders and convert into http-equiv where possible
584
- const http_equiv = [];
585
-
586
577
  const csp_headers = csp.csp_provider.get_meta();
587
578
  if (csp_headers) {
588
- http_equiv.push(csp_headers);
579
+ head.add_http_equiv(csp_headers);
589
580
  }
590
581
 
591
582
  if (state.prerendering.cache) {
592
- http_equiv.push(`<meta http-equiv="cache-control" content="${state.prerendering.cache}">`);
593
- }
594
-
595
- if (http_equiv.length > 0) {
596
- head = http_equiv.join('\n') + head;
583
+ head.add_http_equiv(
584
+ `<meta http-equiv="cache-control" content="${state.prerendering.cache}">`
585
+ );
597
586
  }
598
587
  } else {
599
588
  const csp_header = csp.csp_provider.get_header();
@@ -610,11 +599,8 @@ export async function render_response({
610
599
  }
611
600
  }
612
601
 
613
- // add the content after the script/css links so the link elements are parsed first
614
- head += rendered.head;
615
-
616
602
  const html = options.templates.app({
617
- head,
603
+ head: head.build(),
618
604
  body,
619
605
  assets,
620
606
  nonce: /** @type {string} */ (csp.nonce),
@@ -672,3 +658,78 @@ export async function render_response({
672
658
  }
673
659
  );
674
660
  }
661
+
662
+ class Head {
663
+ #rendered;
664
+ #prerendering;
665
+ /** @type {string[]} */
666
+ #http_equiv = [];
667
+ /** @type {string[]} */
668
+ #link_tags = [];
669
+ /** @type {string[]} */
670
+ #script_preloads = [];
671
+ /** @type {string[]} */
672
+ #style_tags = [];
673
+ /** @type {string[]} */
674
+ #stylesheet_links = [];
675
+
676
+ /**
677
+ * @param {string} rendered
678
+ * @param {boolean} prerendering
679
+ */
680
+ constructor(rendered, prerendering) {
681
+ this.#rendered = rendered;
682
+ this.#prerendering = prerendering;
683
+ }
684
+
685
+ build() {
686
+ return [
687
+ ...this.#http_equiv,
688
+ ...this.#link_tags,
689
+ ...this.#script_preloads,
690
+ this.#rendered,
691
+ ...this.#style_tags,
692
+ ...this.#stylesheet_links
693
+ ].join('\n\t\t');
694
+ }
695
+
696
+ /**
697
+ * @param {string} style
698
+ * @param {string[]} attributes
699
+ */
700
+ add_style(style, attributes) {
701
+ this.#style_tags.push(
702
+ `<style${attributes.length ? ' ' + attributes.join(' ') : ''}>${style}</style>`
703
+ );
704
+ }
705
+
706
+ /**
707
+ * @param {string} href
708
+ * @param {string[]} attributes
709
+ */
710
+ add_stylesheet(href, attributes) {
711
+ this.#stylesheet_links.push(`<link href="${href}" ${attributes.join(' ')}>`);
712
+ }
713
+
714
+ /** @param {string} href */
715
+ add_script_preload(href) {
716
+ this.#script_preloads.push(
717
+ `<link rel="preload" as="script" crossorigin="anonymous" href="${href}">`
718
+ );
719
+ }
720
+
721
+ /**
722
+ * @param {string} href
723
+ * @param {string[]} attributes
724
+ */
725
+ add_link_tag(href, attributes) {
726
+ if (!this.#prerendering) return;
727
+ this.#link_tags.push(`<link href="${href}" ${attributes.join(' ')}>`);
728
+ }
729
+
730
+ /** @param {string} tag */
731
+ add_http_equiv(tag) {
732
+ if (!this.#prerendering) return;
733
+ this.#http_equiv.push(tag);
734
+ }
735
+ }
@@ -176,7 +176,7 @@ export class InternalServer extends Server {
176
176
  request: Request,
177
177
  options: RequestOptions & {
178
178
  prerendering?: PrerenderOptions;
179
- read: (file: string) => Buffer;
179
+ read: (file: string) => NonSharedBuffer;
180
180
  /** A hook called before `handle` during dev, so that `AsyncLocalStorage` can be populated. */
181
181
  before_handle?: (event: RequestEvent, config: any, prerender: PrerenderOption) => void;
182
182
  emulator?: Emulator;
@@ -381,7 +381,7 @@ export interface SSRComponent {
381
381
  default: {
382
382
  render(
383
383
  props: Record<string, any>,
384
- opts: { context: Map<any, any> }
384
+ opts: { context: Map<any, any>; csp?: { nonce?: string; hash?: boolean } }
385
385
  ): {
386
386
  html: string;
387
387
  head: string;
@@ -389,6 +389,10 @@ export interface SSRComponent {
389
389
  code: string;
390
390
  map: any; // TODO
391
391
  };
392
+ /** Until we require all Svelte versions that support hashes, this might not be defined */
393
+ hashes?: {
394
+ script: Array<`sha256-${string}`>;
395
+ };
392
396
  };
393
397
  };
394
398
  }
@@ -525,9 +529,9 @@ export interface SSRState {
525
529
  * prerender option is inherited by the endpoint, unless overridden.
526
530
  */
527
531
  prerender_default?: PrerenderOption;
528
- read?: (file: string) => Buffer;
532
+ read?: (file: string) => NonSharedBuffer;
529
533
  /**
530
- * Used to setup `__SVELTEKIT_TRACK__` which checks if a used feature is supported.
534
+ * Used to set up `__SVELTEKIT_TRACK__` which checks if a used feature is supported.
531
535
  * E.g. if `read` from `$app/server` is used, it checks whether the route's config is compatible.
532
536
  */
533
537
  before_handle?: (event: RequestEvent, config: any, prerender: PrerenderOption) => void;
package/src/version.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // generated during release, do not modify
2
2
 
3
3
  /** @type {string} */
4
- export const VERSION = '2.50.2';
4
+ export const VERSION = '2.51.0';
package/types/index.d.ts CHANGED
@@ -1175,6 +1175,19 @@ declare module '@sveltejs/kit' {
1175
1175
  * The URL that is navigated to
1176
1176
  */
1177
1177
  url: URL;
1178
+ /**
1179
+ * The scroll position associated with this navigation.
1180
+ *
1181
+ * For the `from` target, this is the scroll position at the moment of navigation.
1182
+ *
1183
+ * For the `to` target, this represents the scroll position that will be or was restored:
1184
+ * - In `beforeNavigate` and `onNavigate`, this is only available for `popstate` navigations (back/forward button)
1185
+ * and will be `null` for other navigation types, since the final scroll position isn't known
1186
+ * ahead of time.
1187
+ * - In `afterNavigate`, this is always the scroll position that was applied after the navigation
1188
+ * completed.
1189
+ */
1190
+ scroll: { x: number; y: number } | null;
1178
1191
  }
1179
1192
 
1180
1193
  /**
@@ -1224,7 +1237,7 @@ declare module '@sveltejs/kit' {
1224
1237
  delta?: undefined;
1225
1238
 
1226
1239
  /**
1227
- * Dispatched `Event` object when navigation occured by `popstate` or `link`.
1240
+ * Dispatched `Event` object when navigation occurred by `popstate` or `link`.
1228
1241
  */
1229
1242
  event?: undefined;
1230
1243
  }
@@ -2510,7 +2523,7 @@ declare module '@sveltejs/kit' {
2510
2523
  default: {
2511
2524
  render(
2512
2525
  props: Record<string, any>,
2513
- opts: { context: Map<any, any> }
2526
+ opts: { context: Map<any, any>; csp?: { nonce?: string; hash?: boolean } }
2514
2527
  ): {
2515
2528
  html: string;
2516
2529
  head: string;
@@ -2518,6 +2531,10 @@ declare module '@sveltejs/kit' {
2518
2531
  code: string;
2519
2532
  map: any; // TODO
2520
2533
  };
2534
+ /** Until we require all Svelte versions that support hashes, this might not be defined */
2535
+ hashes?: {
2536
+ script: Array<`sha256-${string}`>;
2537
+ };
2521
2538
  };
2522
2539
  };
2523
2540
  }
@@ -217,6 +217,6 @@
217
217
  null,
218
218
  null
219
219
  ],
220
- "mappings": "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",
220
+ "mappings": "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",
221
221
  "ignoreList": []
222
222
  }