@sveltejs/kit 1.0.0-next.221 → 1.0.0-next.225

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/dist/ssr.js CHANGED
@@ -513,11 +513,12 @@ function escape(str, dict, unicode_encoder) {
513
513
  * branch: Array<import('./types').Loaded>;
514
514
  * options: import('types/internal').SSRRenderOptions;
515
515
  * $session: any;
516
- * page_config: { hydrate: boolean, router: boolean, ssr: boolean };
516
+ * page_config: { hydrate: boolean, router: boolean };
517
517
  * status: number;
518
- * error?: Error,
518
+ * error?: Error;
519
519
  * url: URL;
520
- * params: Record<string, string>
520
+ * params: Record<string, string>;
521
+ * ssr: boolean;
521
522
  * stuff: Record<string, any>;
522
523
  * }} opts
523
524
  */
@@ -530,11 +531,13 @@ async function render_response({
530
531
  error,
531
532
  url,
532
533
  params,
534
+ ssr,
533
535
  stuff
534
536
  }) {
535
537
  const css = new Set(options.manifest._.entry.css);
536
538
  const js = new Set(options.manifest._.entry.js);
537
- const styles = new Set();
539
+ /** @type {Map<string, string>} */
540
+ const styles = new Map();
538
541
 
539
542
  /** @type {Array<{ url: string, body: string, json: string }>} */
540
543
  const serialized_data = [];
@@ -548,11 +551,11 @@ async function render_response({
548
551
  error.stack = options.get_stack(error);
549
552
  }
550
553
 
551
- if (page_config.ssr) {
554
+ if (ssr) {
552
555
  branch.forEach(({ node, loaded, fetched, uses_credentials }) => {
553
556
  if (node.css) node.css.forEach((url) => css.add(url));
554
557
  if (node.js) node.js.forEach((url) => js.add(url));
555
- if (node.styles) node.styles.forEach((content) => styles.add(content));
558
+ if (node.styles) Object.entries(node.styles).forEach(([k, v]) => styles.set(k, v));
556
559
 
557
560
  // TODO probably better if `fetched` wasn't populated unless `hydrate`
558
561
  if (fetched && page_config.hydrate) serialized_data.push(...fetched);
@@ -613,94 +616,80 @@ async function render_response({
613
616
  rendered = { head: '', html: '', css: { code: '', map: null } };
614
617
  }
615
618
 
616
- const include_js = page_config.router || page_config.hydrate;
617
- if (!include_js) js.clear();
618
-
619
- // TODO strip the AMP stuff out of the build if not relevant
620
- const links = options.amp
621
- ? styles.size > 0 || rendered.css.code.length > 0
622
- ? `<style amp-custom>${Array.from(styles).concat(rendered.css.code).join('\n')}</style>`
623
- : ''
624
- : [
625
- // From https://web.dev/priority-hints/:
626
- // Generally, preloads will load in the order the parser gets to them for anything above "Medium" priority
627
- // Thus, we should list CSS first
628
- ...Array.from(css).map((dep) => `<link rel="stylesheet" href="${options.prefix}${dep}">`),
629
- ...Array.from(js).map((dep) => `<link rel="modulepreload" href="${options.prefix}${dep}">`)
630
- ].join('\n\t\t');
631
-
632
- /** @type {string} */
633
- let init = '';
619
+ let { head, html: body } = rendered;
620
+
621
+ const inlined_style = Array.from(styles.values()).join('\n');
634
622
 
635
623
  if (options.amp) {
636
- init = `
624
+ head += `
637
625
  <style amp-boilerplate>body{-webkit-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-moz-animation:-amp-start 8s steps(1,end) 0s 1 normal both;-ms-animation:-amp-start 8s steps(1,end) 0s 1 normal both;animation:-amp-start 8s steps(1,end) 0s 1 normal both}@-webkit-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-moz-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-ms-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@-o-keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}@keyframes -amp-start{from{visibility:hidden}to{visibility:visible}}</style>
638
626
  <noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
639
- <script async src="https://cdn.ampproject.org/v0.js"></script>`;
640
- init += options.service_worker
641
- ? '<script async custom-element="amp-install-serviceworker" src="https://cdn.ampproject.org/v0/amp-install-serviceworker-0.1.js"></script>'
642
- : '';
643
- } else if (include_js) {
644
- // prettier-ignore
645
- init = `<script type="module">
646
- import { start } from ${s(options.prefix + options.manifest._.entry.file)};
647
- start({
648
- target: ${options.target ? `document.querySelector(${s(options.target)})` : 'document.body'},
649
- paths: ${s(options.paths)},
650
- session: ${try_serialize($session, (error) => {
651
- throw new Error(`Failed to serialize session data: ${error.message}`);
652
- })},
653
- route: ${!!page_config.router},
654
- spa: ${!page_config.ssr},
655
- trailing_slash: ${s(options.trailing_slash)},
656
- hydrate: ${page_config.ssr && page_config.hydrate ? `{
657
- status: ${status},
658
- error: ${serialize_error(error)},
659
- nodes: [
660
- ${(branch || [])
661
- .map(({ node }) => `import(${s(options.prefix + node.entry)})`)
662
- .join(',\n\t\t\t\t\t\t')}
663
- ],
664
- url: new URL(${s(url.href)}),
665
- params: ${devalue(params)}
666
- }` : 'null'}
667
- });
668
- </script>`;
669
- }
627
+ <script async src="https://cdn.ampproject.org/v0.js"></script>
670
628
 
671
- if (options.service_worker && !options.amp) {
672
- init += `<script>
673
- if ('serviceWorker' in navigator) {
674
- navigator.serviceWorker.register('${options.service_worker}');
675
- }
676
- </script>`;
677
- }
678
-
679
- const head = [
680
- rendered.head,
681
- styles.size && !options.amp
682
- ? `<style data-svelte>${Array.from(styles).join('\n')}</style>`
683
- : '',
684
- links,
685
- init
686
- ].join('\n\n\t\t');
629
+ <style amp-custom>${inlined_style}\n${rendered.css.code}</style>`;
687
630
 
688
- let body = rendered.html;
689
- if (options.amp) {
690
631
  if (options.service_worker) {
632
+ head +=
633
+ '<script async custom-element="amp-install-serviceworker" src="https://cdn.ampproject.org/v0/amp-install-serviceworker-0.1.js"></script>';
634
+
691
635
  body += `<amp-install-serviceworker src="${options.service_worker}" layout="nodisplay"></amp-install-serviceworker>`;
692
636
  }
693
637
  } else {
694
- body += serialized_data
695
- .map(({ url, body, json }) => {
696
- let attributes = `type="application/json" data-type="svelte-data" data-url=${escape_html_attr(
697
- url
698
- )}`;
699
- if (body) attributes += ` data-body="${hash(body)}"`;
700
-
701
- return `<script ${attributes}>${json}</script>`;
702
- })
703
- .join('\n\n\t');
638
+ if (inlined_style) {
639
+ head += `\n\t<style${options.dev ? ' data-svelte' : ''}>${inlined_style}</style>`;
640
+ }
641
+ // prettier-ignore
642
+ head += Array.from(css)
643
+ .map((dep) => `\n\t<link${styles.has(dep) ? ' disabled' : ''} rel="stylesheet" href="${options.prefix + dep}">`)
644
+ .join('');
645
+
646
+ if (page_config.router || page_config.hydrate) {
647
+ head += Array.from(js)
648
+ .map((dep) => `\n\t<link rel="modulepreload" href="${options.prefix + dep}">`)
649
+ .join('');
650
+ // prettier-ignore
651
+ head += `
652
+ <script type="module">
653
+ import { start } from ${s(options.prefix + options.manifest._.entry.file)};
654
+ start({
655
+ target: ${options.target ? `document.querySelector(${s(options.target)})` : 'document.body'},
656
+ paths: ${s(options.paths)},
657
+ session: ${try_serialize($session, (error) => {
658
+ throw new Error(`Failed to serialize session data: ${error.message}`);
659
+ })},
660
+ route: ${!!page_config.router},
661
+ spa: ${!ssr},
662
+ trailing_slash: ${s(options.trailing_slash)},
663
+ hydrate: ${ssr && page_config.hydrate ? `{
664
+ status: ${status},
665
+ error: ${serialize_error(error)},
666
+ nodes: [
667
+ ${(branch || [])
668
+ .map(({ node }) => `import(${s(options.prefix + node.entry)})`)
669
+ .join(',\n\t\t\t\t\t\t')}
670
+ ],
671
+ url: new URL(${s(url.href)}),
672
+ params: ${devalue(params)}
673
+ }` : 'null'}
674
+ });
675
+ </script>${options.service_worker ? `
676
+ <script>
677
+ if ('serviceWorker' in navigator) {
678
+ navigator.serviceWorker.register('${options.service_worker}');
679
+ }
680
+ </script>` : ''}`;
681
+
682
+ body += serialized_data
683
+ .map(({ url, body, json }) => {
684
+ let attributes = `type="application/json" data-type="svelte-data" data-url=${escape_html_attr(
685
+ url
686
+ )}`;
687
+ if (body) attributes += ` data-body="${hash(body)}"`;
688
+
689
+ return `<script ${attributes}>${json}</script>`;
690
+ })
691
+ .join('\n\n\t');
692
+ }
704
693
  }
705
694
 
706
695
  /** @type {import('types/helper').ResponseHeaders} */
@@ -1150,9 +1139,18 @@ async function load_node({
1150
1139
  * $session: any;
1151
1140
  * status: number;
1152
1141
  * error: Error;
1142
+ * ssr: boolean;
1153
1143
  * }} opts
1154
1144
  */
1155
- async function respond_with_error({ request, options, state, $session, status, error }) {
1145
+ async function respond_with_error({
1146
+ request,
1147
+ options,
1148
+ state,
1149
+ $session,
1150
+ status,
1151
+ error,
1152
+ ssr
1153
+ }) {
1156
1154
  try {
1157
1155
  const default_layout = await options.manifest._.nodes[0](); // 0 is always the root layout
1158
1156
  const default_error = await options.manifest._.nodes[1](); // 1 is always the root error
@@ -1199,15 +1197,15 @@ async function respond_with_error({ request, options, state, $session, status, e
1199
1197
  $session,
1200
1198
  page_config: {
1201
1199
  hydrate: options.hydrate,
1202
- router: options.router,
1203
- ssr: options.ssr
1200
+ router: options.router
1204
1201
  },
1205
1202
  stuff: error_loaded.stuff,
1206
1203
  status,
1207
1204
  error,
1208
1205
  branch: [layout_loaded, error_loaded],
1209
1206
  url: request.url,
1210
- params
1207
+ params,
1208
+ ssr
1211
1209
  });
1212
1210
  } catch (err) {
1213
1211
  const error = coalesce_to_error(err);
@@ -1249,15 +1247,30 @@ function is_prerender_enabled(options, node, state) {
1249
1247
  * $session: any;
1250
1248
  * route: import('types/internal').SSRPage;
1251
1249
  * params: Record<string, string>;
1250
+ * ssr: boolean;
1252
1251
  * }} opts
1253
1252
  * @returns {Promise<ServerResponse | undefined>}
1254
1253
  */
1255
1254
  async function respond$1(opts) {
1256
- const { request, options, state, $session, route } = opts;
1255
+ const { request, options, state, $session, route, ssr } = opts;
1257
1256
 
1258
1257
  /** @type {Array<SSRNode | undefined>} */
1259
1258
  let nodes;
1260
1259
 
1260
+ if (!ssr) {
1261
+ return await render_response({
1262
+ ...opts,
1263
+ branch: [],
1264
+ page_config: {
1265
+ hydrate: true,
1266
+ router: true
1267
+ },
1268
+ status: 200,
1269
+ url: request.url,
1270
+ stuff: {}
1271
+ });
1272
+ }
1273
+
1261
1274
  try {
1262
1275
  nodes = await Promise.all(
1263
1276
  route.a.map((n) => options.manifest._.nodes[n] && options.manifest._.nodes[n]())
@@ -1273,7 +1286,8 @@ async function respond$1(opts) {
1273
1286
  state,
1274
1287
  $session,
1275
1288
  status: 500,
1276
- error
1289
+ error,
1290
+ ssr
1277
1291
  });
1278
1292
  }
1279
1293
 
@@ -1305,7 +1319,7 @@ async function respond$1(opts) {
1305
1319
 
1306
1320
  let stuff = {};
1307
1321
 
1308
- ssr: if (page_config.ssr) {
1322
+ ssr: if (ssr) {
1309
1323
  for (let i = 0; i < nodes.length; i += 1) {
1310
1324
  const node = nodes[i];
1311
1325
 
@@ -1368,7 +1382,6 @@ async function respond$1(opts) {
1368
1382
  }
1369
1383
 
1370
1384
  try {
1371
- // there's no fallthough on an error page, so we know it's not undefined
1372
1385
  const error_loaded = /** @type {import('./types').Loaded} */ (
1373
1386
  await load_node({
1374
1387
  ...opts,
@@ -1410,7 +1423,8 @@ async function respond$1(opts) {
1410
1423
  state,
1411
1424
  $session,
1412
1425
  status,
1413
- error
1426
+ error,
1427
+ ssr
1414
1428
  }),
1415
1429
  set_cookie_headers
1416
1430
  );
@@ -1460,8 +1474,14 @@ async function respond$1(opts) {
1460
1474
  * @param {SSRRenderOptions} options
1461
1475
  */
1462
1476
  function get_page_config(leaf, options) {
1477
+ // TODO remove for 1.0
1478
+ if ('ssr' in leaf) {
1479
+ throw new Error(
1480
+ '`export const ssr` has been removed — use the handle hook instead: https://kit.svelte.dev/docs#hooks-handle'
1481
+ );
1482
+ }
1483
+
1463
1484
  return {
1464
- ssr: 'ssr' in leaf ? !!leaf.ssr : options.ssr,
1465
1485
  router: 'router' in leaf ? !!leaf.router : options.router,
1466
1486
  hydrate: 'hydrate' in leaf ? !!leaf.hydrate : options.hydrate
1467
1487
  };
@@ -1484,9 +1504,10 @@ function with_cookies(response, set_cookie_headers) {
1484
1504
  * @param {RegExpExecArray} match
1485
1505
  * @param {import('types/internal').SSRRenderOptions} options
1486
1506
  * @param {import('types/internal').SSRRenderState} state
1507
+ * @param {boolean} ssr
1487
1508
  * @returns {Promise<import('types/hooks').ServerResponse | undefined>}
1488
1509
  */
1489
- async function render_page(request, route, match, options, state) {
1510
+ async function render_page(request, route, match, options, state, ssr) {
1490
1511
  if (state.initiator === route) {
1491
1512
  // infinite request cycle detected
1492
1513
  return {
@@ -1506,7 +1527,8 @@ async function render_page(request, route, match, options, state) {
1506
1527
  state,
1507
1528
  $session,
1508
1529
  route,
1509
- params
1530
+ params,
1531
+ ssr
1510
1532
  });
1511
1533
 
1512
1534
  if (response) {
@@ -1744,6 +1766,28 @@ async function respond(incoming, options, state = {}) {
1744
1766
  locals: {}
1745
1767
  };
1746
1768
 
1769
+ const { parameter, allowed } = options.method_override;
1770
+ const method_override = incoming.url.searchParams.get(parameter)?.toUpperCase();
1771
+
1772
+ if (method_override) {
1773
+ if (request.method.toUpperCase() === 'POST') {
1774
+ if (allowed.includes(method_override)) {
1775
+ request.method = method_override;
1776
+ } else {
1777
+ const verb = allowed.length === 0 ? 'enabled' : 'allowed';
1778
+ const body = `${parameter}=${method_override} is not ${verb}. See https://kit.svelte.dev/docs#configuration-methodoverride`;
1779
+
1780
+ return {
1781
+ status: 400,
1782
+ headers: {},
1783
+ body
1784
+ };
1785
+ }
1786
+ } else {
1787
+ throw new Error(`${parameter}=${method_override} is only allowed with POST requests`);
1788
+ }
1789
+ }
1790
+
1747
1791
  // TODO remove this for 1.0
1748
1792
  /**
1749
1793
  * @param {string} property
@@ -1761,20 +1805,25 @@ async function respond(incoming, options, state = {}) {
1761
1805
  print_error('path', 'pathname');
1762
1806
  print_error('query', 'searchParams');
1763
1807
 
1808
+ let ssr = true;
1809
+
1764
1810
  try {
1765
1811
  return await options.hooks.handle({
1766
1812
  request,
1767
- resolve: async (request) => {
1813
+ resolve: async (request, opts) => {
1814
+ if (opts && 'ssr' in opts) ssr = /** @type {boolean} */ (opts.ssr);
1815
+
1768
1816
  if (state.prerender && state.prerender.fallback) {
1769
1817
  return await render_response({
1770
1818
  url: request.url,
1771
1819
  params: request.params,
1772
1820
  options,
1773
1821
  $session: await options.hooks.getSession(request),
1822
+ page_config: { router: true, hydrate: true },
1774
1823
  stuff: {},
1775
- page_config: { ssr: false, router: true, hydrate: true },
1776
1824
  status: 200,
1777
- branch: []
1825
+ branch: [],
1826
+ ssr: false
1778
1827
  });
1779
1828
  }
1780
1829
 
@@ -1787,7 +1836,7 @@ async function respond(incoming, options, state = {}) {
1787
1836
  const response =
1788
1837
  route.type === 'endpoint'
1789
1838
  ? await render_endpoint(request, route, match)
1790
- : await render_page(request, route, match, options, state);
1839
+ : await render_page(request, route, match, options, state, ssr);
1791
1840
 
1792
1841
  if (response) {
1793
1842
  // inject ETags for 200 responses
@@ -1827,7 +1876,8 @@ async function respond(incoming, options, state = {}) {
1827
1876
  state,
1828
1877
  $session,
1829
1878
  status: 404,
1830
- error: new Error(`Not found: ${request.url.pathname}`)
1879
+ error: new Error(`Not found: ${request.url.pathname}`),
1880
+ ssr
1831
1881
  });
1832
1882
  }
1833
1883
  }
@@ -1845,7 +1895,8 @@ async function respond(incoming, options, state = {}) {
1845
1895
  state,
1846
1896
  $session,
1847
1897
  status: 500,
1848
- error
1898
+ error,
1899
+ ssr
1849
1900
  });
1850
1901
  } catch (/** @type {unknown} */ e) {
1851
1902
  const error = coalesce_to_error(e);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "1.0.0-next.221",
3
+ "version": "1.0.0-next.225",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/sveltejs/kit",
@@ -35,7 +35,7 @@
35
35
  "node-fetch": "^3.1.0",
36
36
  "port-authority": "^1.1.2",
37
37
  "rollup": "^2.60.2",
38
- "selfsigned": "^1.10.11",
38
+ "selfsigned": "^2.0.0",
39
39
  "sirv": "^2.0.0",
40
40
  "svelte": "^3.44.2",
41
41
  "svelte-check": "^2.2.10",
package/types/config.d.ts CHANGED
@@ -131,6 +131,11 @@ export interface Config {
131
131
  };
132
132
  host?: string;
133
133
  hydrate?: boolean;
134
+ inlineStyleThreshold?: number;
135
+ methodOverride?: {
136
+ parameter?: string;
137
+ allowed?: string[];
138
+ };
134
139
  package?: {
135
140
  dir?: string;
136
141
  emitTypes?: boolean;
@@ -154,7 +159,6 @@ export interface Config {
154
159
  register?: boolean;
155
160
  files?: (filepath: string) => boolean;
156
161
  };
157
- ssr?: boolean;
158
162
  target?: string;
159
163
  trailingSlash?: TrailingSlash;
160
164
  vite?: ViteConfig | (() => ViteConfig);
package/types/hooks.d.ts CHANGED
@@ -23,10 +23,14 @@ export interface GetSession<Locals = Record<string, any>, Body = unknown, Sessio
23
23
  (request: ServerRequest<Locals, Body>): MaybePromise<Session>;
24
24
  }
25
25
 
26
+ export interface ResolveOpts {
27
+ ssr?: boolean;
28
+ }
29
+
26
30
  export interface Handle<Locals = Record<string, any>, Body = unknown> {
27
31
  (input: {
28
32
  request: ServerRequest<Locals, Body>;
29
- resolve(request: ServerRequest<Locals, Body>): MaybePromise<ServerResponse>;
33
+ resolve(request: ServerRequest<Locals, Body>, opts?: ResolveOpts): MaybePromise<ServerResponse>;
30
34
  }): MaybePromise<ServerResponse>;
31
35
  }
32
36
 
@@ -35,7 +39,10 @@ export interface Handle<Locals = Record<string, any>, Body = unknown> {
35
39
  export interface InternalHandle<Locals = Record<string, any>, Body = unknown> {
36
40
  (input: {
37
41
  request: ServerRequest<Locals, Body>;
38
- resolve(request: ServerRequest<Locals, Body>): MaybePromise<ServerResponse | undefined>;
42
+ resolve(
43
+ request: ServerRequest<Locals, Body>,
44
+ opts?: ResolveOpts
45
+ ): MaybePromise<ServerResponse | undefined>;
39
46
  }): MaybePromise<ServerResponse | undefined>;
40
47
  }
41
48
 
package/types/index.d.ts CHANGED
@@ -13,5 +13,6 @@ export {
13
13
  Handle,
14
14
  HandleError,
15
15
  ServerRequest as Request,
16
- ServerResponse as Response
16
+ ServerResponse as Response,
17
+ ResolveOpts
17
18
  } from './hooks';
@@ -44,11 +44,9 @@ export interface Logger {
44
44
  }
45
45
 
46
46
  export interface SSRComponent {
47
- ssr?: boolean;
48
47
  router?: boolean;
49
48
  hydrate?: boolean;
50
49
  prerender?: boolean;
51
- preload?: any; // TODO remove for 1.0
52
50
  load: Load;
53
51
  default: {
54
52
  render(props: Record<string, any>): {
@@ -121,7 +119,7 @@ export interface SSRNode {
121
119
  /** external JS files */
122
120
  js: string[];
123
121
  /** inlined styles */
124
- styles: string[];
122
+ styles?: Record<string, string>;
125
123
  }
126
124
 
127
125
  export interface SSRRenderOptions {
@@ -133,6 +131,7 @@ export interface SSRRenderOptions {
133
131
  hooks: Hooks;
134
132
  hydrate: boolean;
135
133
  manifest: SSRManifest;
134
+ method_override: MethodOverride;
136
135
  paths: {
137
136
  base: string;
138
137
  assets: string;
@@ -143,7 +142,6 @@ export interface SSRRenderOptions {
143
142
  root: SSRComponent['default'];
144
143
  router: boolean;
145
144
  service_worker?: string;
146
- ssr: boolean;
147
145
  target: string;
148
146
  template({ head, body, assets }: { head: string; body: string; assets: string }): string;
149
147
  trailing_slash: TrailingSlash;
@@ -233,3 +231,7 @@ export type NormalizedLoadOutput = Either<
233
231
  >;
234
232
 
235
233
  export type TrailingSlash = 'never' | 'always' | 'ignore';
234
+ export interface MethodOverride {
235
+ parameter: string;
236
+ allowed: string[];
237
+ }