@sveltejs/kit 1.0.0-next.549 → 1.0.0-next.550

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.0.0-next.549",
3
+ "version": "1.0.0-next.550",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/sveltejs/kit",
@@ -283,11 +283,15 @@ export async function build_server(options, client) {
283
283
  /** @type {string[]} */
284
284
  const stylesheets = [];
285
285
 
286
+ /** @type {string[]} */
287
+ const fonts = [];
288
+
286
289
  if (node.component) {
287
290
  const entry = find_deps(client.vite_manifest, node.component, true);
288
291
 
289
292
  imported.push(...entry.imports);
290
293
  stylesheets.push(...entry.stylesheets);
294
+ fonts.push(...entry.fonts);
291
295
 
292
296
  exports.push(
293
297
  `export const component = async () => (await import('../${
@@ -302,6 +306,7 @@ export async function build_server(options, client) {
302
306
 
303
307
  imported.push(...entry.imports);
304
308
  stylesheets.push(...entry.stylesheets);
309
+ fonts.push(...entry.fonts);
305
310
 
306
311
  imports.push(`import * as shared from '../${vite_manifest[node.shared].file}';`);
307
312
  exports.push(`export { shared };`);
@@ -314,7 +319,8 @@ export async function build_server(options, client) {
314
319
 
315
320
  exports.push(
316
321
  `export const imports = ${s(imported)};`,
317
- `export const stylesheets = ${s(stylesheets)};`
322
+ `export const stylesheets = ${s(stylesheets)};`,
323
+ `export const fonts = ${s(fonts)};`
318
324
  );
319
325
 
320
326
  /** @type {string[]} */
@@ -45,6 +45,9 @@ export function find_deps(manifest, entry, add_dynamic_css) {
45
45
  /** @type {Set<string>} */
46
46
  const stylesheets = new Set();
47
47
 
48
+ /** @type {Set<string>} */
49
+ const fonts = new Set();
50
+
48
51
  /**
49
52
  * @param {string} current
50
53
  * @param {boolean} add_js
@@ -57,6 +60,14 @@ export function find_deps(manifest, entry, add_dynamic_css) {
57
60
 
58
61
  if (add_js) imports.add(chunk.file);
59
62
 
63
+ if (chunk.assets) {
64
+ for (const asset of chunk.assets) {
65
+ if (/\.(woff2?|ttf|otf)$/.test(asset)) {
66
+ fonts.add(asset);
67
+ }
68
+ }
69
+ }
70
+
60
71
  if (chunk.css) {
61
72
  chunk.css.forEach((file) => stylesheets.add(file));
62
73
  }
@@ -77,7 +88,8 @@ export function find_deps(manifest, entry, add_dynamic_css) {
77
88
  return {
78
89
  file: chunk.file,
79
90
  imports: Array.from(imports),
80
- stylesheets: Array.from(stylesheets)
91
+ stylesheets: Array.from(stylesheets),
92
+ fonts: Array.from(fonts)
81
93
  };
82
94
  }
83
95
 
@@ -65,7 +65,8 @@ export async function dev(vite, vite_config, svelte_config) {
65
65
  entry: {
66
66
  file: `/@fs${runtime_prefix}/client/start.js`,
67
67
  imports: [],
68
- stylesheets: []
68
+ stylesheets: [],
69
+ fonts: []
69
70
  },
70
71
  nodes: manifest_data.nodes.map((node, index) => {
71
72
  return async () => {
@@ -80,6 +81,7 @@ export async function dev(vite, vite_config, svelte_config) {
80
81
  // these are unused in dev, it's easier to include them
81
82
  result.imports = [];
82
83
  result.stylesheets = [];
84
+ result.fonts = [];
83
85
 
84
86
  if (node.component) {
85
87
  result.component = async () => {
@@ -20,11 +20,15 @@ import { Redirect } from '../control.js';
20
20
 
21
21
  /* global __SVELTEKIT_ADAPTER_NAME__ */
22
22
 
23
- /** @param {{ html: string }} opts */
23
+ /** @type {import('types').RequiredResolveOptions['transformPageChunk']} */
24
24
  const default_transform = ({ html }) => html;
25
25
 
26
+ /** @type {import('types').RequiredResolveOptions['filterSerializedResponseHeaders']} */
26
27
  const default_filter = () => false;
27
28
 
29
+ /** @type {import('types').RequiredResolveOptions['preload']} */
30
+ const default_preload = ({ type }) => type !== 'asset';
31
+
28
32
  /** @type {import('types').Respond} */
29
33
  export async function respond(request, options, state) {
30
34
  let url = new URL(request.url);
@@ -185,7 +189,8 @@ export async function respond(request, options, state) {
185
189
  /** @type {import('types').RequiredResolveOptions} */
186
190
  let resolve_opts = {
187
191
  transformPageChunk: default_transform,
188
- filterSerializedResponseHeaders: default_filter
192
+ filterSerializedResponseHeaders: default_filter,
193
+ preload: default_preload
189
194
  };
190
195
 
191
196
  /**
@@ -211,7 +216,8 @@ export async function respond(request, options, state) {
211
216
 
212
217
  resolve_opts = {
213
218
  transformPageChunk: opts.transformPageChunk || default_transform,
214
- filterSerializedResponseHeaders: opts.filterSerializedResponseHeaders || default_filter
219
+ filterSerializedResponseHeaders: opts.filterSerializedResponseHeaders || default_filter,
220
+ preload: opts.preload || default_preload
215
221
  };
216
222
  }
217
223
 
@@ -55,6 +55,7 @@ export async function render_response({
55
55
 
56
56
  const stylesheets = new Set(entry.stylesheets);
57
57
  const modulepreloads = new Set(entry.imports);
58
+ const fonts = new Set(options.manifest._.entry.fonts);
58
59
 
59
60
  /** @type {Set<string>} */
60
61
  const link_header_preloads = new Set();
@@ -129,6 +130,10 @@ export async function render_response({
129
130
  node.stylesheets.forEach((url) => stylesheets.add(url));
130
131
  }
131
132
 
133
+ if (node.fonts) {
134
+ node.fonts.forEach((url) => fonts.add(url));
135
+ }
136
+
132
137
  if (node.inline_styles) {
133
138
  Object.entries(await node.inline_styles()).forEach(([k, v]) => inline_styles.set(k, v));
134
139
  }
@@ -219,23 +224,43 @@ export async function render_response({
219
224
 
220
225
  for (const dep of stylesheets) {
221
226
  const path = prefixed(dep);
222
- const attributes = [];
223
227
 
224
- if (csp.style_needs_nonce) {
225
- attributes.push(`nonce="${csp.nonce}"`);
226
- }
228
+ if (resolve_opts.preload({ type: 'css', path })) {
229
+ const attributes = [];
230
+
231
+ if (csp.style_needs_nonce) {
232
+ attributes.push(`nonce="${csp.nonce}"`);
233
+ }
227
234
 
228
- if (inline_styles.has(dep)) {
229
- // don't load stylesheets that are already inlined
230
- // include them in disabled state so that Vite can detect them and doesn't try to add them
231
- attributes.push('disabled', 'media="(max-width: 0)"');
232
- } else {
233
- const preload_atts = ['rel="preload"', 'as="style"'].concat(attributes);
234
- link_header_preloads.add(`<${encodeURI(path)}>; ${preload_atts.join(';')}; nopush`);
235
+ if (inline_styles.has(dep)) {
236
+ // don't load stylesheets that are already inlined
237
+ // include them in disabled state so that Vite can detect them and doesn't try to add them
238
+ attributes.push('disabled', 'media="(max-width: 0)"');
239
+ } else {
240
+ const preload_atts = ['rel="preload"', 'as="style"'].concat(attributes);
241
+ link_header_preloads.add(`<${encodeURI(path)}>; ${preload_atts.join(';')}; nopush`);
242
+ }
243
+
244
+ attributes.unshift('rel="stylesheet"');
245
+ head += `\n\t\t<link href="${path}" ${attributes.join(' ')}>`;
235
246
  }
247
+ }
248
+
249
+ for (const dep of fonts) {
250
+ const path = prefixed(dep);
236
251
 
237
- attributes.unshift('rel="stylesheet"');
238
- head += `\n\t\t<link href="${path}" ${attributes.join(' ')}>`;
252
+ if (resolve_opts.preload({ type: 'font', path })) {
253
+ const ext = dep.slice(dep.lastIndexOf('.') + 1);
254
+ const attributes = [
255
+ 'rel="preload"',
256
+ 'as="font"',
257
+ `type="font/${ext}"`,
258
+ `href="${path}"`,
259
+ 'crossorigin'
260
+ ];
261
+
262
+ head += `\n\t\t<link ${attributes.join(' ')}>`;
263
+ }
239
264
  }
240
265
 
241
266
  if (page_config.csr) {
@@ -262,9 +287,12 @@ export async function render_response({
262
287
 
263
288
  for (const dep of modulepreloads) {
264
289
  const path = prefixed(dep);
265
- link_header_preloads.add(`<${encodeURI(path)}>; rel="modulepreload"; nopush`);
266
- if (state.prerendering) {
267
- head += `\n\t\t<link rel="modulepreload" href="${path}">`;
290
+
291
+ if (resolve_opts.preload({ type: 'js', path })) {
292
+ link_header_preloads.add(`<${encodeURI(path)}>; rel="modulepreload"; nopush`);
293
+ if (state.prerendering) {
294
+ head += `\n\t\t<link rel="modulepreload" href="${path}">`;
295
+ }
268
296
  }
269
297
  }
270
298
 
package/types/index.d.ts CHANGED
@@ -238,6 +238,12 @@ export interface KitConfig {
238
238
  };
239
239
  }
240
240
 
241
+ /**
242
+ * This function runs every time the SvelteKit server receives a [request](https://kit.svelte.dev/docs/web-standards#fetch-apis-request) and
243
+ * determines the [response](https://kit.svelte.dev/docs/web-standards#fetch-apis-response).
244
+ * It receives an `event` object representing the request and a function called `resolve`, which renders the route and generates a `Response`.
245
+ * This allows you to modify response headers or bodies, or bypass SvelteKit entirely (for implementing routes programmatically, for example).
246
+ */
241
247
  export interface Handle {
242
248
  (input: {
243
249
  event: RequestEvent;
@@ -590,8 +596,26 @@ export interface RequestHandler<
590
596
  }
591
597
 
592
598
  export interface ResolveOptions {
599
+ /**
600
+ * Applies custom transforms to HTML. If `done` is true, it's the final chunk. Chunks are not guaranteed to be well-formed HTML
601
+ * (they could include an element's opening tag but not its closing tag, for example)
602
+ * but they will always be split at sensible boundaries such as `%sveltekit.head%` or layout/page components.
603
+ * @param input the html chunk and the info if this is the last chunk
604
+ */
593
605
  transformPageChunk?(input: { html: string; done: boolean }): MaybePromise<string | undefined>;
606
+ /**
607
+ * Determines which headers should be included in serialized responses when a `load` function loads a resource with `fetch`.
608
+ * By default, none will be included.
609
+ * @param name header name
610
+ * @param value header value
611
+ */
594
612
  filterSerializedResponseHeaders?(name: string, value: string): boolean;
613
+ /**
614
+ * Determines what should be added to the `<head>` tag to preload it.
615
+ * By default, `js`, `css` and `font` files will be preloaded.
616
+ * @param input the type of the file and its path
617
+ */
618
+ preload?(input: { type: 'font' | 'css' | 'js' | 'asset'; path: string }): boolean;
595
619
  }
596
620
 
597
621
  export class Server {
@@ -616,6 +640,7 @@ export interface SSRManifest {
616
640
  file: string;
617
641
  imports: string[];
618
642
  stylesheets: string[];
643
+ fonts: string[];
619
644
  };
620
645
  nodes: SSRNodeLoader[];
621
646
  routes: SSRRoute[];
@@ -57,6 +57,7 @@ export interface BuildData {
57
57
  file: string;
58
58
  imports: string[];
59
59
  stylesheets: string[];
60
+ fonts: string[];
60
61
  };
61
62
  vite_manifest: import('vite').Manifest;
62
63
  };
@@ -255,6 +256,8 @@ export interface SSRNode {
255
256
  imports: string[];
256
257
  /** external CSS files */
257
258
  stylesheets: string[];
259
+ /** external font files */
260
+ fonts: string[];
258
261
  /** inlined styles */
259
262
  inline_styles?(): MaybePromise<Record<string, string>>;
260
263