@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/assets/kit.js CHANGED
@@ -544,11 +544,12 @@ const s = JSON.stringify;
544
544
  * branch: Array<import('./types').Loaded>;
545
545
  * options: import('types/internal').SSRRenderOptions;
546
546
  * $session: any;
547
- * page_config: { hydrate: boolean, router: boolean, ssr: boolean };
547
+ * page_config: { hydrate: boolean, router: boolean };
548
548
  * status: number;
549
- * error?: Error,
549
+ * error?: Error;
550
550
  * url: URL;
551
- * params: Record<string, string>
551
+ * params: Record<string, string>;
552
+ * ssr: boolean;
552
553
  * stuff: Record<string, any>;
553
554
  * }} opts
554
555
  */
@@ -561,11 +562,13 @@ async function render_response({
561
562
  error,
562
563
  url,
563
564
  params,
565
+ ssr,
564
566
  stuff
565
567
  }) {
566
568
  const css = new Set(options.manifest._.entry.css);
567
569
  const js = new Set(options.manifest._.entry.js);
568
- const styles = new Set();
570
+ /** @type {Map<string, string>} */
571
+ const styles = new Map();
569
572
 
570
573
  /** @type {Array<{ url: string, body: string, json: string }>} */
571
574
  const serialized_data = [];
@@ -579,11 +582,11 @@ async function render_response({
579
582
  error.stack = options.get_stack(error);
580
583
  }
581
584
 
582
- if (page_config.ssr) {
585
+ if (ssr) {
583
586
  branch.forEach(({ node, loaded, fetched, uses_credentials }) => {
584
587
  if (node.css) node.css.forEach((url) => css.add(url));
585
588
  if (node.js) node.js.forEach((url) => js.add(url));
586
- if (node.styles) node.styles.forEach((content) => styles.add(content));
589
+ if (node.styles) Object.entries(node.styles).forEach(([k, v]) => styles.set(k, v));
587
590
 
588
591
  // TODO probably better if `fetched` wasn't populated unless `hydrate`
589
592
  if (fetched && page_config.hydrate) serialized_data.push(...fetched);
@@ -644,94 +647,80 @@ async function render_response({
644
647
  rendered = { head: '', html: '', css: { code: '', map: null } };
645
648
  }
646
649
 
647
- const include_js = page_config.router || page_config.hydrate;
648
- if (!include_js) js.clear();
649
-
650
- // TODO strip the AMP stuff out of the build if not relevant
651
- const links = options.amp
652
- ? styles.size > 0 || rendered.css.code.length > 0
653
- ? `<style amp-custom>${Array.from(styles).concat(rendered.css.code).join('\n')}</style>`
654
- : ''
655
- : [
656
- // From https://web.dev/priority-hints/:
657
- // Generally, preloads will load in the order the parser gets to them for anything above "Medium" priority
658
- // Thus, we should list CSS first
659
- ...Array.from(css).map((dep) => `<link rel="stylesheet" href="${options.prefix}${dep}">`),
660
- ...Array.from(js).map((dep) => `<link rel="modulepreload" href="${options.prefix}${dep}">`)
661
- ].join('\n\t\t');
662
-
663
- /** @type {string} */
664
- let init = '';
650
+ let { head, html: body } = rendered;
651
+
652
+ const inlined_style = Array.from(styles.values()).join('\n');
665
653
 
666
654
  if (options.amp) {
667
- init = `
655
+ head += `
668
656
  <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>
669
657
  <noscript><style amp-boilerplate>body{-webkit-animation:none;-moz-animation:none;-ms-animation:none;animation:none}</style></noscript>
670
- <script async src="https://cdn.ampproject.org/v0.js"></script>`;
671
- init += options.service_worker
672
- ? '<script async custom-element="amp-install-serviceworker" src="https://cdn.ampproject.org/v0/amp-install-serviceworker-0.1.js"></script>'
673
- : '';
674
- } else if (include_js) {
675
- // prettier-ignore
676
- init = `<script type="module">
677
- import { start } from ${s(options.prefix + options.manifest._.entry.file)};
678
- start({
679
- target: ${options.target ? `document.querySelector(${s(options.target)})` : 'document.body'},
680
- paths: ${s(options.paths)},
681
- session: ${try_serialize($session, (error) => {
682
- throw new Error(`Failed to serialize session data: ${error.message}`);
683
- })},
684
- route: ${!!page_config.router},
685
- spa: ${!page_config.ssr},
686
- trailing_slash: ${s(options.trailing_slash)},
687
- hydrate: ${page_config.ssr && page_config.hydrate ? `{
688
- status: ${status},
689
- error: ${serialize_error(error)},
690
- nodes: [
691
- ${(branch || [])
692
- .map(({ node }) => `import(${s(options.prefix + node.entry)})`)
693
- .join(',\n\t\t\t\t\t\t')}
694
- ],
695
- url: new URL(${s(url.href)}),
696
- params: ${devalue(params)}
697
- }` : 'null'}
698
- });
699
- </script>`;
700
- }
658
+ <script async src="https://cdn.ampproject.org/v0.js"></script>
701
659
 
702
- if (options.service_worker && !options.amp) {
703
- init += `<script>
704
- if ('serviceWorker' in navigator) {
705
- navigator.serviceWorker.register('${options.service_worker}');
706
- }
707
- </script>`;
708
- }
709
-
710
- const head = [
711
- rendered.head,
712
- styles.size && !options.amp
713
- ? `<style data-svelte>${Array.from(styles).join('\n')}</style>`
714
- : '',
715
- links,
716
- init
717
- ].join('\n\n\t\t');
660
+ <style amp-custom>${inlined_style}\n${rendered.css.code}</style>`;
718
661
 
719
- let body = rendered.html;
720
- if (options.amp) {
721
662
  if (options.service_worker) {
663
+ head +=
664
+ '<script async custom-element="amp-install-serviceworker" src="https://cdn.ampproject.org/v0/amp-install-serviceworker-0.1.js"></script>';
665
+
722
666
  body += `<amp-install-serviceworker src="${options.service_worker}" layout="nodisplay"></amp-install-serviceworker>`;
723
667
  }
724
668
  } else {
725
- body += serialized_data
726
- .map(({ url, body, json }) => {
727
- let attributes = `type="application/json" data-type="svelte-data" data-url=${escape_html_attr(
728
- url
729
- )}`;
730
- if (body) attributes += ` data-body="${hash(body)}"`;
731
-
732
- return `<script ${attributes}>${json}</script>`;
733
- })
734
- .join('\n\n\t');
669
+ if (inlined_style) {
670
+ head += `\n\t<style${options.dev ? ' data-svelte' : ''}>${inlined_style}</style>`;
671
+ }
672
+ // prettier-ignore
673
+ head += Array.from(css)
674
+ .map((dep) => `\n\t<link${styles.has(dep) ? ' disabled' : ''} rel="stylesheet" href="${options.prefix + dep}">`)
675
+ .join('');
676
+
677
+ if (page_config.router || page_config.hydrate) {
678
+ head += Array.from(js)
679
+ .map((dep) => `\n\t<link rel="modulepreload" href="${options.prefix + dep}">`)
680
+ .join('');
681
+ // prettier-ignore
682
+ head += `
683
+ <script type="module">
684
+ import { start } from ${s(options.prefix + options.manifest._.entry.file)};
685
+ start({
686
+ target: ${options.target ? `document.querySelector(${s(options.target)})` : 'document.body'},
687
+ paths: ${s(options.paths)},
688
+ session: ${try_serialize($session, (error) => {
689
+ throw new Error(`Failed to serialize session data: ${error.message}`);
690
+ })},
691
+ route: ${!!page_config.router},
692
+ spa: ${!ssr},
693
+ trailing_slash: ${s(options.trailing_slash)},
694
+ hydrate: ${ssr && page_config.hydrate ? `{
695
+ status: ${status},
696
+ error: ${serialize_error(error)},
697
+ nodes: [
698
+ ${(branch || [])
699
+ .map(({ node }) => `import(${s(options.prefix + node.entry)})`)
700
+ .join(',\n\t\t\t\t\t\t')}
701
+ ],
702
+ url: new URL(${s(url.href)}),
703
+ params: ${devalue(params)}
704
+ }` : 'null'}
705
+ });
706
+ </script>${options.service_worker ? `
707
+ <script>
708
+ if ('serviceWorker' in navigator) {
709
+ navigator.serviceWorker.register('${options.service_worker}');
710
+ }
711
+ </script>` : ''}`;
712
+
713
+ body += serialized_data
714
+ .map(({ url, body, json }) => {
715
+ let attributes = `type="application/json" data-type="svelte-data" data-url=${escape_html_attr(
716
+ url
717
+ )}`;
718
+ if (body) attributes += ` data-body="${hash(body)}"`;
719
+
720
+ return `<script ${attributes}>${json}</script>`;
721
+ })
722
+ .join('\n\n\t');
723
+ }
735
724
  }
736
725
 
737
726
  /** @type {import('types/helper').ResponseHeaders} */
@@ -1220,9 +1209,18 @@ async function load_node({
1220
1209
  * $session: any;
1221
1210
  * status: number;
1222
1211
  * error: Error;
1212
+ * ssr: boolean;
1223
1213
  * }} opts
1224
1214
  */
1225
- async function respond_with_error({ request, options, state, $session, status, error }) {
1215
+ async function respond_with_error({
1216
+ request,
1217
+ options,
1218
+ state,
1219
+ $session,
1220
+ status,
1221
+ error,
1222
+ ssr
1223
+ }) {
1226
1224
  try {
1227
1225
  const default_layout = await options.manifest._.nodes[0](); // 0 is always the root layout
1228
1226
  const default_error = await options.manifest._.nodes[1](); // 1 is always the root error
@@ -1269,15 +1267,15 @@ async function respond_with_error({ request, options, state, $session, status, e
1269
1267
  $session,
1270
1268
  page_config: {
1271
1269
  hydrate: options.hydrate,
1272
- router: options.router,
1273
- ssr: options.ssr
1270
+ router: options.router
1274
1271
  },
1275
1272
  stuff: error_loaded.stuff,
1276
1273
  status,
1277
1274
  error,
1278
1275
  branch: [layout_loaded, error_loaded],
1279
1276
  url: request.url,
1280
- params
1277
+ params,
1278
+ ssr
1281
1279
  });
1282
1280
  } catch (err) {
1283
1281
  const error = coalesce_to_error(err);
@@ -1319,15 +1317,30 @@ function is_prerender_enabled(options, node, state) {
1319
1317
  * $session: any;
1320
1318
  * route: import('types/internal').SSRPage;
1321
1319
  * params: Record<string, string>;
1320
+ * ssr: boolean;
1322
1321
  * }} opts
1323
1322
  * @returns {Promise<ServerResponse | undefined>}
1324
1323
  */
1325
1324
  async function respond$1(opts) {
1326
- const { request, options, state, $session, route } = opts;
1325
+ const { request, options, state, $session, route, ssr } = opts;
1327
1326
 
1328
1327
  /** @type {Array<SSRNode | undefined>} */
1329
1328
  let nodes;
1330
1329
 
1330
+ if (!ssr) {
1331
+ return await render_response({
1332
+ ...opts,
1333
+ branch: [],
1334
+ page_config: {
1335
+ hydrate: true,
1336
+ router: true
1337
+ },
1338
+ status: 200,
1339
+ url: request.url,
1340
+ stuff: {}
1341
+ });
1342
+ }
1343
+
1331
1344
  try {
1332
1345
  nodes = await Promise.all(
1333
1346
  route.a.map((n) => options.manifest._.nodes[n] && options.manifest._.nodes[n]())
@@ -1343,7 +1356,8 @@ async function respond$1(opts) {
1343
1356
  state,
1344
1357
  $session,
1345
1358
  status: 500,
1346
- error
1359
+ error,
1360
+ ssr
1347
1361
  });
1348
1362
  }
1349
1363
 
@@ -1375,7 +1389,7 @@ async function respond$1(opts) {
1375
1389
 
1376
1390
  let stuff = {};
1377
1391
 
1378
- ssr: if (page_config.ssr) {
1392
+ ssr: if (ssr) {
1379
1393
  for (let i = 0; i < nodes.length; i += 1) {
1380
1394
  const node = nodes[i];
1381
1395
 
@@ -1438,7 +1452,6 @@ async function respond$1(opts) {
1438
1452
  }
1439
1453
 
1440
1454
  try {
1441
- // there's no fallthough on an error page, so we know it's not undefined
1442
1455
  const error_loaded = /** @type {import('./types').Loaded} */ (
1443
1456
  await load_node({
1444
1457
  ...opts,
@@ -1480,7 +1493,8 @@ async function respond$1(opts) {
1480
1493
  state,
1481
1494
  $session,
1482
1495
  status,
1483
- error
1496
+ error,
1497
+ ssr
1484
1498
  }),
1485
1499
  set_cookie_headers
1486
1500
  );
@@ -1530,8 +1544,14 @@ async function respond$1(opts) {
1530
1544
  * @param {SSRRenderOptions} options
1531
1545
  */
1532
1546
  function get_page_config(leaf, options) {
1547
+ // TODO remove for 1.0
1548
+ if ('ssr' in leaf) {
1549
+ throw new Error(
1550
+ '`export const ssr` has been removed — use the handle hook instead: https://kit.svelte.dev/docs#hooks-handle'
1551
+ );
1552
+ }
1553
+
1533
1554
  return {
1534
- ssr: 'ssr' in leaf ? !!leaf.ssr : options.ssr,
1535
1555
  router: 'router' in leaf ? !!leaf.router : options.router,
1536
1556
  hydrate: 'hydrate' in leaf ? !!leaf.hydrate : options.hydrate
1537
1557
  };
@@ -1554,9 +1574,10 @@ function with_cookies(response, set_cookie_headers) {
1554
1574
  * @param {RegExpExecArray} match
1555
1575
  * @param {import('types/internal').SSRRenderOptions} options
1556
1576
  * @param {import('types/internal').SSRRenderState} state
1577
+ * @param {boolean} ssr
1557
1578
  * @returns {Promise<import('types/hooks').ServerResponse | undefined>}
1558
1579
  */
1559
- async function render_page(request, route, match, options, state) {
1580
+ async function render_page(request, route, match, options, state, ssr) {
1560
1581
  if (state.initiator === route) {
1561
1582
  // infinite request cycle detected
1562
1583
  return {
@@ -1576,7 +1597,8 @@ async function render_page(request, route, match, options, state) {
1576
1597
  state,
1577
1598
  $session,
1578
1599
  route,
1579
- params
1600
+ params,
1601
+ ssr
1580
1602
  });
1581
1603
 
1582
1604
  if (response) {
@@ -1814,6 +1836,28 @@ async function respond(incoming, options, state = {}) {
1814
1836
  locals: {}
1815
1837
  };
1816
1838
 
1839
+ const { parameter, allowed } = options.method_override;
1840
+ const method_override = incoming.url.searchParams.get(parameter)?.toUpperCase();
1841
+
1842
+ if (method_override) {
1843
+ if (request.method.toUpperCase() === 'POST') {
1844
+ if (allowed.includes(method_override)) {
1845
+ request.method = method_override;
1846
+ } else {
1847
+ const verb = allowed.length === 0 ? 'enabled' : 'allowed';
1848
+ const body = `${parameter}=${method_override} is not ${verb}. See https://kit.svelte.dev/docs#configuration-methodoverride`;
1849
+
1850
+ return {
1851
+ status: 400,
1852
+ headers: {},
1853
+ body
1854
+ };
1855
+ }
1856
+ } else {
1857
+ throw new Error(`${parameter}=${method_override} is only allowed with POST requests`);
1858
+ }
1859
+ }
1860
+
1817
1861
  // TODO remove this for 1.0
1818
1862
  /**
1819
1863
  * @param {string} property
@@ -1831,20 +1875,25 @@ async function respond(incoming, options, state = {}) {
1831
1875
  print_error('path', 'pathname');
1832
1876
  print_error('query', 'searchParams');
1833
1877
 
1878
+ let ssr = true;
1879
+
1834
1880
  try {
1835
1881
  return await options.hooks.handle({
1836
1882
  request,
1837
- resolve: async (request) => {
1883
+ resolve: async (request, opts) => {
1884
+ if (opts && 'ssr' in opts) ssr = /** @type {boolean} */ (opts.ssr);
1885
+
1838
1886
  if (state.prerender && state.prerender.fallback) {
1839
1887
  return await render_response({
1840
1888
  url: request.url,
1841
1889
  params: request.params,
1842
1890
  options,
1843
1891
  $session: await options.hooks.getSession(request),
1892
+ page_config: { router: true, hydrate: true },
1844
1893
  stuff: {},
1845
- page_config: { ssr: false, router: true, hydrate: true },
1846
1894
  status: 200,
1847
- branch: []
1895
+ branch: [],
1896
+ ssr: false
1848
1897
  });
1849
1898
  }
1850
1899
 
@@ -1857,7 +1906,7 @@ async function respond(incoming, options, state = {}) {
1857
1906
  const response =
1858
1907
  route.type === 'endpoint'
1859
1908
  ? await render_endpoint(request, route, match)
1860
- : await render_page(request, route, match, options, state);
1909
+ : await render_page(request, route, match, options, state, ssr);
1861
1910
 
1862
1911
  if (response) {
1863
1912
  // inject ETags for 200 responses
@@ -1897,7 +1946,8 @@ async function respond(incoming, options, state = {}) {
1897
1946
  state,
1898
1947
  $session,
1899
1948
  status: 404,
1900
- error: new Error(`Not found: ${request.url.pathname}`)
1949
+ error: new Error(`Not found: ${request.url.pathname}`),
1950
+ ssr
1901
1951
  });
1902
1952
  }
1903
1953
  }
@@ -1915,7 +1965,8 @@ async function respond(incoming, options, state = {}) {
1915
1965
  state,
1916
1966
  $session,
1917
1967
  status: 500,
1918
- error
1968
+ error,
1969
+ ssr
1919
1970
  });
1920
1971
  } catch (/** @type {unknown} */ e) {
1921
1972
  const error = coalesce_to_error(e);
@@ -2,8 +2,6 @@ import { getContext } from 'svelte';
2
2
  import { browser } from './env.js';
3
3
  import '../env.js';
4
4
 
5
- const ssr = !browser;
6
-
7
5
  // TODO remove this (for 1.0? after 1.0?)
8
6
  let warned = false;
9
7
  function stores() {
@@ -59,9 +57,9 @@ const navigating = {
59
57
  /** @param {string} verb */
60
58
  const throw_error = (verb) => {
61
59
  throw new Error(
62
- ssr
63
- ? `Can only ${verb} session store in browser`
64
- : `Cannot ${verb} session store before subscribing`
60
+ browser
61
+ ? `Cannot ${verb} session store before subscribing`
62
+ : `Can only ${verb} session store in browser`
65
63
  );
66
64
  };
67
65
 
@@ -70,7 +68,7 @@ const session = {
70
68
  subscribe(fn) {
71
69
  const store = getStores().session;
72
70
 
73
- if (!ssr) {
71
+ if (browser) {
74
72
  session.set = store.set;
75
73
  session.update = store.update;
76
74
  }