@sveltejs/kit 1.0.0-next.211 → 1.0.0-next.215

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
@@ -598,7 +598,7 @@ async function render_response({
598
598
  navigating: writable(null),
599
599
  session
600
600
  },
601
- page: { url, params },
601
+ page: { url, params, status, error },
602
602
  components: branch.map(({ node }) => node.module.default)
603
603
  };
604
604
 
@@ -1,4 +1,4 @@
1
- import { router as router$1 } from '../internal/singletons.js';
1
+ import { renderer, router as router$1 } from '../internal/singletons.js';
2
2
  import { g as get_base_uri } from '../chunks/utils.js';
3
3
 
4
4
  const router = /** @type {import('../client/router').Router} */ (router$1);
@@ -12,11 +12,21 @@ function guard(name) {
12
12
  };
13
13
  }
14
14
 
15
+ const disableScrollHandling = import.meta.env.SSR
16
+ ? guard('disableScrollHandling')
17
+ : disableScrollHandling_;
15
18
  const goto = import.meta.env.SSR ? guard('goto') : goto_;
16
19
  const invalidate = import.meta.env.SSR ? guard('invalidate') : invalidate_;
17
20
  const prefetch = import.meta.env.SSR ? guard('prefetch') : prefetch_;
18
21
  const prefetchRoutes = import.meta.env.SSR ? guard('prefetchRoutes') : prefetchRoutes_;
19
22
 
23
+ /**
24
+ * @type {import('$app/navigation').goto}
25
+ */
26
+ async function disableScrollHandling_() {
27
+ renderer.disable_scroll_handling();
28
+ }
29
+
20
30
  /**
21
31
  * @type {import('$app/navigation').goto}
22
32
  */
@@ -52,4 +62,4 @@ async function prefetchRoutes_(pathnames) {
52
62
  await Promise.all(promises);
53
63
  }
54
64
 
55
- export { goto, invalidate, prefetch, prefetchRoutes };
65
+ export { disableScrollHandling, goto, invalidate, prefetch, prefetchRoutes };
@@ -57,7 +57,7 @@ const navigating = {
57
57
  };
58
58
 
59
59
  /** @param {string} verb */
60
- const error = (verb) => {
60
+ const throw_error = (verb) => {
61
61
  throw new Error(
62
62
  ssr
63
63
  ? `Can only ${verb} session store in browser`
@@ -77,8 +77,8 @@ const session = {
77
77
 
78
78
  return store.subscribe(fn);
79
79
  },
80
- set: () => error('set'),
81
- update: () => error('update')
80
+ set: () => throw_error('set'),
81
+ update: () => throw_error('update')
82
82
  };
83
83
 
84
84
  export { getStores, navigating, page, session, stores };
@@ -1,9 +1,18 @@
1
1
  /** @type {import('./router').Router?} */
2
2
  let router;
3
3
 
4
- /** @param {import('./router').Router?} _ */
5
- function init(_) {
6
- router = _;
4
+ /** @type {import('./renderer').Renderer} */
5
+ let renderer;
6
+
7
+ /**
8
+ * @param {{
9
+ * router: import('./router').Router?;
10
+ * renderer: import('./renderer').Renderer;
11
+ * }} opts
12
+ */
13
+ function init(opts) {
14
+ router = opts.router;
15
+ renderer = opts.renderer;
7
16
  }
8
17
 
9
- export { init, router };
18
+ export { init, renderer, router };
@@ -162,16 +162,17 @@ class Router {
162
162
 
163
163
  if (!this.owns(url)) return;
164
164
 
165
- const noscroll = a.hasAttribute('sveltekit:noscroll');
165
+ // Check if new url only differs by hash
166
+ if (url.href.split('#')[0] === location.href.split('#')[0]) {
167
+ // Call `pushState` to add url to history so going back works.
168
+ // Also make a delay, otherwise the browser default behaviour would not kick in
169
+ setTimeout(() => history.pushState({}, '', url.href));
170
+ return;
171
+ }
166
172
 
167
- const i1 = url_string.indexOf('#');
168
- const i2 = location.href.indexOf('#');
169
- const u1 = i1 >= 0 ? url_string.substring(0, i1) : url_string;
170
- const u2 = i2 >= 0 ? location.href.substring(0, i2) : location.href;
171
173
  history.pushState({}, '', url.href);
172
- if (u1 === u2) {
173
- window.dispatchEvent(new HashChangeEvent('hashchange'));
174
- }
174
+
175
+ const noscroll = a.hasAttribute('sveltekit:noscroll');
175
176
  this._navigate(url, noscroll ? scroll_state() : null, false, [], url.hash);
176
177
  event.preventDefault();
177
178
  });
@@ -466,6 +467,8 @@ class Renderer {
466
467
  this.session_id = 1;
467
468
  this.invalid = new Set();
468
469
  this.invalidating = null;
470
+ this.autoscroll = true;
471
+ this.updating = false;
469
472
 
470
473
  /** @type {import('./types').NavigationState} */
471
474
  this.current = {
@@ -508,6 +511,16 @@ class Renderer {
508
511
  ready = true;
509
512
  }
510
513
 
514
+ disable_scroll_handling() {
515
+ if (import.meta.env.DEV && this.started && !this.updating) {
516
+ throw new Error('Can only disable scroll handling during navigation');
517
+ }
518
+
519
+ if (this.updating || !this.started) {
520
+ this.autoscroll = false;
521
+ }
522
+ }
523
+
511
524
  /**
512
525
  * @param {{
513
526
  * status: number;
@@ -563,7 +576,7 @@ class Renderer {
563
576
 
564
577
  result = error_args
565
578
  ? await this._load_error(error_args)
566
- : await this._get_navigation_result_from_branch({ url, params, branch });
579
+ : await this._get_navigation_result_from_branch({ url, params, branch, status, error });
567
580
  } catch (e) {
568
581
  if (error) throw e;
569
582
 
@@ -637,6 +650,8 @@ class Renderer {
637
650
  }
638
651
  }
639
652
 
653
+ this.updating = true;
654
+
640
655
  if (this.started) {
641
656
  this.current = navigation_result.state;
642
657
 
@@ -655,26 +670,9 @@ class Renderer {
655
670
  document.body.focus();
656
671
  }
657
672
 
658
- const old_page_y_offset = Math.round(pageYOffset);
659
- const old_max_page_y_offset = document.documentElement.scrollHeight - innerHeight;
660
-
661
673
  await 0;
662
674
 
663
- const new_page_y_offset = Math.round(pageYOffset);
664
- const new_max_page_y_offset = document.documentElement.scrollHeight - innerHeight;
665
-
666
- // After `await 0`, the `onMount()` function in the component executed.
667
- // Check if no scrolling happened on mount.
668
- const no_scroll_happened =
669
- // In most cases, we can compare whether `pageYOffset` changed between navigation
670
- new_page_y_offset === Math.min(old_page_y_offset, new_max_page_y_offset) ||
671
- // But if the page is scrolled to/near the bottom, the browser would also scroll
672
- // to/near the bottom of the new page on navigation. Since we can't detect when this
673
- // behaviour happens, we naively compare by the y offset from the bottom of the page.
674
- old_max_page_y_offset - old_page_y_offset === new_max_page_y_offset - new_page_y_offset;
675
-
676
- // If there was no scrolling, we run on our custom scroll handling
677
- if (no_scroll_happened) {
675
+ if (this.autoscroll) {
678
676
  const deep_linked = hash && document.getElementById(hash.slice(1));
679
677
  if (scroll) {
680
678
  scrollTo(scroll.x, scroll.y);
@@ -694,6 +692,8 @@ class Renderer {
694
692
 
695
693
  this.loading.promise = null;
696
694
  this.loading.id = null;
695
+ this.autoscroll = true;
696
+ this.updating = false;
697
697
 
698
698
  if (!this.router) return;
699
699
 
@@ -800,9 +800,11 @@ class Renderer {
800
800
  * url: URL;
801
801
  * params: Record<string, string>;
802
802
  * branch: Array<import('./types').BranchNode | undefined>;
803
+ * status: number;
804
+ * error?: Error;
803
805
  * }} opts
804
806
  */
805
- async _get_navigation_result_from_branch({ url, params, branch }) {
807
+ async _get_navigation_result_from_branch({ url, params, branch, status, error }) {
806
808
  const filtered = /** @type {import('./types').BranchNode[] } */ (branch.filter(Boolean));
807
809
  const redirect = filtered.find((f) => f.loaded && f.loaded.redirect);
808
810
 
@@ -826,7 +828,7 @@ class Renderer {
826
828
  }
827
829
 
828
830
  if (!this.current.url || url.href !== this.current.url.href) {
829
- result.props.page = { url, params };
831
+ result.props.page = { url, params, status, error };
830
832
 
831
833
  // TODO remove this for 1.0
832
834
  /**
@@ -1120,12 +1122,12 @@ class Renderer {
1120
1122
  }
1121
1123
  }
1122
1124
 
1123
- return await this._get_navigation_result_from_branch({ url, params, branch });
1125
+ return await this._get_navigation_result_from_branch({ url, params, branch, status, error });
1124
1126
  }
1125
1127
 
1126
1128
  /**
1127
1129
  * @param {{
1128
- * status?: number;
1130
+ * status: number;
1129
1131
  * error: Error;
1130
1132
  * url: URL;
1131
1133
  * }} opts
@@ -1153,7 +1155,7 @@ class Renderer {
1153
1155
  })
1154
1156
  ];
1155
1157
 
1156
- return await this._get_navigation_result_from_branch({ url, params, branch });
1158
+ return await this._get_navigation_result_from_branch({ url, params, branch, status, error });
1157
1159
  }
1158
1160
  }
1159
1161
 
@@ -1200,7 +1202,7 @@ async function start({ paths, target, session, route, spa, trailing_slash, hydra
1200
1202
  })
1201
1203
  : null;
1202
1204
 
1203
- init(router);
1205
+ init({ router, renderer });
1204
1206
  set_paths(paths);
1205
1207
 
1206
1208
  if (hydrate) await renderer.start(hydrate);
@@ -4540,14 +4540,16 @@ function find_deps(node, deps) {
4540
4540
  }
4541
4541
  }
4542
4542
 
4543
- /** @typedef {{
4543
+ /**
4544
+ * @typedef {{
4544
4545
  * cwd: string,
4545
4546
  * port: number,
4546
4547
  * host?: string,
4547
4548
  * https: boolean,
4548
4549
  * config: import('types/config').ValidatedConfig
4549
- * }} Options */
4550
- /** @typedef {import('types/internal').SSRComponent} SSRComponent */
4550
+ * }} Options
4551
+ * @typedef {import('types/internal').SSRComponent} SSRComponent
4552
+ */
4551
4553
 
4552
4554
  /** @param {Options} opts */
4553
4555
  async function dev({ cwd, port, host, https, config }) {
@@ -4590,6 +4592,13 @@ async function dev({ cwd, port, host, https, config }) {
4590
4592
  $lib: config.kit.files.lib
4591
4593
  }
4592
4594
  },
4595
+ build: {
4596
+ rollupOptions: {
4597
+ // Vite dependency crawler needs an explicit JS entry point
4598
+ // eventhough server otherwise works without it
4599
+ input: path__default.resolve(`${output}/runtime/internal/start.js`)
4600
+ }
4601
+ },
4593
4602
  plugins: [
4594
4603
  svelte({
4595
4604
  extensions: config.extensions,
@@ -686,6 +686,9 @@ function comparator(a, b) {
686
686
  if (!b_sub_part) return -1;
687
687
 
688
688
  if (a_sub_part.rest && b_sub_part.rest) {
689
+ if (a.is_page !== b.is_page) {
690
+ return a.is_page ? 1 : -1;
691
+ }
689
692
  // sort alphabetically
690
693
  return a_sub_part.content < b_sub_part.content ? -1 : 1;
691
694
  }
@@ -1,11 +1,11 @@
1
- import fs__default, { writeFileSync } from 'fs';
1
+ import fs__default from 'fs';
2
2
  import path__default from 'path';
3
- import { p as print_config_conflicts, c as copy_assets, b as posixify, r as resolve_entry, a as rimraf, m as mkdirp } from '../cli.js';
3
+ import { p as print_config_conflicts, c as copy_assets, b as posixify, r as resolve_entry, m as mkdirp, a as rimraf } from '../cli.js';
4
4
  import { d as deep_merge, a as create_app, c as create_manifest_data } from './index2.js';
5
5
  import { S as SVELTE_KIT } from './constants.js';
6
6
  import { g as generate_manifest } from './index4.js';
7
- import { s } from './misc.js';
8
7
  import vite from 'vite';
8
+ import { s } from './misc.js';
9
9
  import { svelte } from '@sveltejs/vite-plugin-svelte';
10
10
  import 'sade';
11
11
  import 'child_process';
@@ -249,11 +249,12 @@ async function build_client({
249
249
  * @param {{
250
250
  * runtime: string,
251
251
  * hooks: string,
252
- * config: import('types/config').ValidatedConfig
252
+ * config: import('types/config').ValidatedConfig,
253
+ * has_service_worker: boolean
253
254
  * }} opts
254
255
  * @returns
255
256
  */
256
- const template = ({ config, hooks, runtime }) => `
257
+ const template = ({ config, hooks, runtime, has_service_worker }) => `
257
258
  import { respond } from '${runtime}';
258
259
  import root from './generated/root.svelte';
259
260
  import { set_paths, assets, base } from './runtime/paths.js';
@@ -309,11 +310,7 @@ export class App {
309
310
  prerender: ${config.kit.prerender.enabled},
310
311
  read,
311
312
  root,
312
- service_worker: ${
313
- config.kit.files.serviceWorker && config.kit.serviceWorker.register
314
- ? "'/service-worker.js'"
315
- : 'null'
316
- },
313
+ service_worker: ${has_service_worker ? "'/service-worker.js'" : 'null'},
317
314
  router: ${s(config.kit.router)},
318
315
  ssr: ${s(config.kit.ssr)},
319
316
  target: ${s(config.kit.target)},
@@ -356,12 +353,25 @@ export class App {
356
353
  * manifest_data: import('types/internal').ManifestData
357
354
  * build_dir: string;
358
355
  * output_dir: string;
356
+ * service_worker_entry_file: string | null;
357
+ * service_worker_register: boolean;
359
358
  * }} options
360
359
  * @param {string} runtime
360
+ * @param {{ vite_manifest: import('vite').Manifest, assets: import('rollup').OutputAsset[] }} client
361
361
  */
362
362
  async function build_server(
363
- { cwd, assets_base, config, manifest_data, build_dir, output_dir },
364
- runtime
363
+ {
364
+ cwd,
365
+ assets_base,
366
+ config,
367
+ manifest_data,
368
+ build_dir,
369
+ output_dir,
370
+ service_worker_entry_file,
371
+ service_worker_register
372
+ },
373
+ runtime,
374
+ client
365
375
  ) {
366
376
  let hooks_file = resolve_entry(config.kit.files.hooks);
367
377
  if (!hooks_file || !fs__default.existsSync(hooks_file)) {
@@ -407,7 +417,8 @@ async function build_server(
407
417
  template({
408
418
  config,
409
419
  hooks: app_relative(hooks_file),
410
- runtime
420
+ runtime,
421
+ has_service_worker: service_worker_register && !!service_worker_entry_file
411
422
  })
412
423
  );
413
424
 
@@ -482,10 +493,42 @@ async function build_server(
482
493
  }
483
494
  });
484
495
 
496
+ /** @type {import('vite').Manifest} */
497
+ const vite_manifest = JSON.parse(fs__default.readFileSync(`${output_dir}/server/manifest.json`, 'utf-8'));
498
+
499
+ const styles_lookup = new Map();
500
+ if (config.kit.amp) {
501
+ client.assets.forEach((asset) => {
502
+ if (asset.fileName.endsWith('.css')) {
503
+ styles_lookup.set(asset.fileName, asset.source);
504
+ }
505
+ });
506
+ }
507
+
508
+ mkdirp(`${output_dir}/server/nodes`);
509
+ manifest_data.components.forEach((component, i) => {
510
+ const file = `${output_dir}/server/nodes/${i}.js`;
511
+
512
+ const js = new Set();
513
+ const css = new Set();
514
+ find_deps(component, client.vite_manifest, js, css);
515
+
516
+ const styles = config.kit.amp && Array.from(css).map((file) => styles_lookup.get(file));
517
+
518
+ const node = `import * as module from '../${vite_manifest[component].file}';
519
+ export { module };
520
+ export const entry = '${client.vite_manifest[component].file}';
521
+ export const js = ${JSON.stringify(Array.from(js))};
522
+ export const css = ${JSON.stringify(Array.from(css))};
523
+ ${styles ? `export const styles = ${s(styles)}` : ''}
524
+ `.replace(/^\t\t\t/gm, '');
525
+
526
+ fs__default.writeFileSync(file, node);
527
+ });
528
+
485
529
  return {
486
530
  chunks,
487
- /** @type {import('vite').Manifest} */
488
- vite_manifest: JSON.parse(fs__default.readFileSync(`${output_dir}/server/manifest.json`, 'utf-8')),
531
+ vite_manifest,
489
532
  methods: get_methods(cwd, chunks, manifest_data)
490
533
  };
491
534
  }
@@ -564,37 +607,7 @@ async function build(config, { cwd = process.cwd(), runtime = './kit.js' } = {})
564
607
  };
565
608
 
566
609
  const client = await build_client(options);
567
- const server = await build_server(options, runtime);
568
-
569
- const styles_lookup = new Map();
570
- if (options.config.kit.amp) {
571
- client.assets.forEach((asset) => {
572
- if (asset.fileName.endsWith('.css')) {
573
- styles_lookup.set(asset.fileName, asset.source);
574
- }
575
- });
576
- }
577
-
578
- mkdirp(`${output_dir}/server/nodes`);
579
- options.manifest_data.components.forEach((component, i) => {
580
- const file = `${output_dir}/server/nodes/${i}.js`;
581
-
582
- const js = new Set();
583
- const css = new Set();
584
- find_deps(component, client.vite_manifest, js, css);
585
-
586
- const styles = config.kit.amp && Array.from(css).map((file) => styles_lookup.get(file));
587
-
588
- const node = `import * as module from '../${server.vite_manifest[component].file}';
589
- export { module };
590
- export const entry = '${client.vite_manifest[component].file}';
591
- export const js = ${JSON.stringify(Array.from(js))};
592
- export const css = ${JSON.stringify(Array.from(css))};
593
- ${styles ? `export const styles = ${s(styles)}` : ''}
594
- `.replace(/^\t\t\t/gm, '');
595
-
596
- writeFileSync(file, node);
597
- });
610
+ const server = await build_server(options, runtime, client);
598
611
 
599
612
  if (options.service_worker_entry_file) {
600
613
  if (config.kit.paths.assets) {
@@ -270,7 +270,7 @@ async function prerender({ cwd, out, log, config, build_data, fallback, all }) {
270
270
 
271
271
  const rendered = await app.render(
272
272
  {
273
- url: `${config.kit.protocol || 'sveltekit'}://${config.kit.host || 'prerender'}${path}`,
273
+ url: `${config.kit.protocol || 'http'}://${config.kit.host || 'prerender'}${path}`,
274
274
  method: 'GET',
275
275
  headers: {},
276
276
  rawBody: null
@@ -417,7 +417,7 @@ async function prerender({ cwd, out, log, config, build_data, fallback, all }) {
417
417
  if (fallback) {
418
418
  const rendered = await app.render(
419
419
  {
420
- url: `${config.kit.host || 'sveltekit'}://${config.kit.host || 'prerender'}/[fallback]`,
420
+ url: `${config.kit.protocol || 'http'}://${config.kit.host || 'prerender'}/[fallback]`,
421
421
  method: 'GET',
422
422
  headers: {},
423
423
  rawBody: null
package/dist/cli.js CHANGED
@@ -887,7 +887,7 @@ async function launch(port, https) {
887
887
  exec(`${cmd} ${https ? 'https' : 'http'}://localhost:${port}`);
888
888
  }
889
889
 
890
- const prog = sade('svelte-kit').version('1.0.0-next.211');
890
+ const prog = sade('svelte-kit').version('1.0.0-next.215');
891
891
 
892
892
  prog
893
893
  .command('dev')
@@ -1039,7 +1039,7 @@ async function check_port(port) {
1039
1039
  function welcome({ port, host, https, open, loose, allow, cwd }) {
1040
1040
  if (open) launch(port, https);
1041
1041
 
1042
- console.log($.bold().cyan(`\n SvelteKit v${'1.0.0-next.211'}\n`));
1042
+ console.log($.bold().cyan(`\n SvelteKit v${'1.0.0-next.215'}\n`));
1043
1043
 
1044
1044
  const protocol = https ? 'https:' : 'http:';
1045
1045
  const exposed = typeof host !== 'undefined' && host !== 'localhost' && host !== '127.0.0.1';
package/dist/ssr.js CHANGED
@@ -567,7 +567,7 @@ async function render_response({
567
567
  navigating: writable(null),
568
568
  session
569
569
  },
570
- page: { url, params },
570
+ page: { url, params, status, error },
571
571
  components: branch.map(({ node }) => node.module.default)
572
572
  };
573
573
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltejs/kit",
3
- "version": "1.0.0-next.211",
3
+ "version": "1.0.0-next.215",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/sveltejs/kit",
@@ -15,6 +15,7 @@
15
15
  "vite": "^2.7.2"
16
16
  },
17
17
  "devDependencies": {
18
+ "@playwright/test": "^1.17.1",
18
19
  "@rollup/plugin-replace": "^3.0.0",
19
20
  "@types/amphtml-validator": "^1.0.1",
20
21
  "@types/cookie": "^0.4.1",
@@ -24,6 +25,7 @@
24
25
  "@types/sade": "^1.7.3",
25
26
  "amphtml-validator": "^1.0.35",
26
27
  "cookie": "^0.4.1",
28
+ "cross-env": "^7.0.3",
27
29
  "devalue": "^2.0.1",
28
30
  "eslint": "^8.3.0",
29
31
  "kleur": "^4.1.4",
@@ -85,6 +87,10 @@
85
87
  "test": "npm run test:unit && npm run test:packaging && npm run test:integration",
86
88
  "test:unit": "uvu src \"(spec\\.js|test[\\\\/]index\\.js)\" -i packaging",
87
89
  "test:packaging": "uvu src/packaging \"(spec\\.js|test[\\\\/]index\\.js)\"",
88
- "test:integration": "uvu test test.js"
90
+ "test:integration": "pnpm test:integration:amp && pnpm test:integration:basics && pnpm test:integration:options && pnpm test:integration:options-2",
91
+ "test:integration:amp": "cd test/apps/amp && pnpm test",
92
+ "test:integration:basics": "cd test/apps/basics && pnpm test",
93
+ "test:integration:options": "cd test/apps/options && pnpm test",
94
+ "test:integration:options-2": "cd test/apps/options-2 && pnpm test"
89
95
  }
90
96
  }
@@ -26,6 +26,11 @@ declare module '$app/env' {
26
26
  }
27
27
 
28
28
  declare module '$app/navigation' {
29
+ /**
30
+ * Disable SvelteKit's built-in scroll handling for the current navigation, in case you need to manually control the scroll position.
31
+ * This is generally discouraged, since it breaks user expectations.
32
+ */
33
+ export function disableScrollHandling(): void;
29
34
  /**
30
35
  * Returns a Promise that resolves when SvelteKit navigates (or fails to navigate, in which case the promise rejects) to the specified href.
31
36
  *
@@ -93,6 +98,8 @@ declare module '$app/stores' {
93
98
  page: Readable<{
94
99
  url: URL;
95
100
  params: Record<string, string>;
101
+ status: number;
102
+ error: Error | null;
96
103
  }>;
97
104
  session: Writable<Session>;
98
105
  };
@@ -103,6 +110,8 @@ declare module '$app/stores' {
103
110
  export const page: Readable<{
104
111
  url: URL;
105
112
  params: Record<string, string>;
113
+ status: number;
114
+ error: Error | null;
106
115
  }>;
107
116
  /**
108
117
  * A readable store.