@sveltejs/kit 1.0.0-next.464 → 1.0.0-next.467

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.464",
3
+ "version": "1.0.0-next.467",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/sveltejs/kit",
@@ -38,7 +38,7 @@
38
38
  "svelte-preprocess": "^4.10.6",
39
39
  "typescript": "^4.8.2",
40
40
  "uvu": "^0.5.3",
41
- "vite": "^3.1.0-beta.1"
41
+ "vite": "^3.1.0-beta.2"
42
42
  },
43
43
  "peerDependencies": {
44
44
  "svelte": "^3.44.0",
@@ -80,10 +80,10 @@ export function create_client({ target, base, trailing_slash }) {
80
80
  };
81
81
 
82
82
  const callbacks = {
83
- /** @type {Array<(opts: { from: URL, to: URL | null, cancel: () => void }) => void>} */
83
+ /** @type {Array<(navigation: import('types').Navigation & { cancel: () => void }) => void>} */
84
84
  before_navigate: [],
85
85
 
86
- /** @type {Array<(opts: { from: URL | null, to: URL }) => void>} */
86
+ /** @type {Array<(navigation: import('types').Navigation) => void>} */
87
87
  after_navigate: []
88
88
  };
89
89
 
@@ -142,8 +142,11 @@ export function create_client({ target, base, trailing_slash }) {
142
142
 
143
143
  function invalidate() {
144
144
  if (!invalidating) {
145
+ const url = new URL(location.href);
146
+
145
147
  invalidating = Promise.resolve().then(async () => {
146
- await update(new URL(location.href), []);
148
+ const intent = get_navigation_intent(url);
149
+ await update(intent, url, []);
147
150
 
148
151
  invalidating = null;
149
152
  force_invalidation = false;
@@ -177,7 +180,8 @@ export function create_client({ target, base, trailing_slash }) {
177
180
  replaceState
178
181
  },
179
182
  accepted: () => {},
180
- blocked: () => {}
183
+ blocked: () => {},
184
+ type: 'goto'
181
185
  });
182
186
  }
183
187
 
@@ -197,14 +201,13 @@ export function create_client({ target, base, trailing_slash }) {
197
201
 
198
202
  /**
199
203
  * Returns `true` if update completes, `false` if it is aborted
204
+ * @param {import('./types').NavigationIntent | undefined} intent
200
205
  * @param {URL} url
201
206
  * @param {string[]} redirect_chain
202
207
  * @param {{hash?: string, scroll: { x: number, y: number } | null, keepfocus: boolean, details: { replaceState: boolean, state: any } | null}} [opts]
203
208
  * @param {() => void} [callback]
204
209
  */
205
- async function update(url, redirect_chain, opts, callback) {
206
- const intent = get_navigation_intent(url);
207
-
210
+ async function update(intent, url, redirect_chain, opts, callback) {
208
211
  const current_token = (token = {});
209
212
  let navigation_result = intent && (await load_route(intent));
210
213
 
@@ -395,7 +398,16 @@ export function create_client({ target, base, trailing_slash }) {
395
398
  });
396
399
  }
397
400
 
398
- const navigation = { from: null, to: new URL(location.href) };
401
+ /** @type {import('types').Navigation} */
402
+ const navigation = {
403
+ from: null,
404
+ to: add_url_properties('to', {
405
+ params: current.params,
406
+ routeId: current.route?.id ?? null,
407
+ url: new URL(location.href)
408
+ }),
409
+ type: 'load'
410
+ };
399
411
  callbacks.after_navigate.forEach((fn) => fn(navigation));
400
412
 
401
413
  started = true;
@@ -409,7 +421,7 @@ export function create_client({ target, base, trailing_slash }) {
409
421
  * branch: Array<import('./types').BranchNode | undefined>;
410
422
  * status: number;
411
423
  * error: HttpError | Error | null;
412
- * routeId: string | null;
424
+ * route: import('types').CSRRoute | null;
413
425
  * validation_errors?: Record<string, any> | null;
414
426
  * }} opts
415
427
  */
@@ -419,7 +431,7 @@ export function create_client({ target, base, trailing_slash }) {
419
431
  branch,
420
432
  status,
421
433
  error,
422
- routeId,
434
+ route,
423
435
  validation_errors
424
436
  }) {
425
437
  const filtered = /** @type {import('./types').BranchNode[] } */ (branch.filter(Boolean));
@@ -432,6 +444,7 @@ export function create_client({ target, base, trailing_slash }) {
432
444
  params,
433
445
  branch,
434
446
  error,
447
+ route,
435
448
  session_id
436
449
  },
437
450
  props: {
@@ -466,7 +479,7 @@ export function create_client({ target, base, trailing_slash }) {
466
479
  result.props.page = {
467
480
  error,
468
481
  params,
469
- routeId,
482
+ routeId: route && route.id,
470
483
  status,
471
484
  url,
472
485
  // The whole page store is updated, but this way the object reference stays the same
@@ -842,7 +855,7 @@ export function create_client({ target, base, trailing_slash }) {
842
855
  branch: branch.slice(0, j + 1).concat(error_loaded),
843
856
  status,
844
857
  error,
845
- routeId: route.id
858
+ route
846
859
  });
847
860
  } catch (e) {
848
861
  continue;
@@ -868,7 +881,7 @@ export function create_client({ target, base, trailing_slash }) {
868
881
  branch,
869
882
  status: 200,
870
883
  error: null,
871
- routeId: route.id
884
+ route
872
885
  });
873
886
  }
874
887
 
@@ -937,7 +950,7 @@ export function create_client({ target, base, trailing_slash }) {
937
950
  branch: [root_layout, root_error],
938
951
  status,
939
952
  error,
940
- routeId
953
+ route: null
941
954
  });
942
955
  }
943
956
 
@@ -977,21 +990,54 @@ export function create_client({ target, base, trailing_slash }) {
977
990
  * replaceState: boolean;
978
991
  * state: any;
979
992
  * } | null;
993
+ * type: import('types').NavigationType;
994
+ * delta?: number;
980
995
  * accepted: () => void;
981
996
  * blocked: () => void;
982
997
  * }} opts
983
998
  */
984
- async function navigate({ url, scroll, keepfocus, redirect_chain, details, accepted, blocked }) {
985
- const from = current.url;
999
+ async function navigate({
1000
+ url,
1001
+ scroll,
1002
+ keepfocus,
1003
+ redirect_chain,
1004
+ details,
1005
+ type,
1006
+ delta,
1007
+ accepted,
1008
+ blocked
1009
+ }) {
986
1010
  let should_block = false;
987
1011
 
1012
+ const intent = get_navigation_intent(url);
1013
+
1014
+ /** @type {import('types').Navigation} */
988
1015
  const navigation = {
989
- from,
990
- to: url,
991
- cancel: () => (should_block = true)
1016
+ from: add_url_properties('from', {
1017
+ params: current.params,
1018
+ routeId: current.route?.id ?? null,
1019
+ url: current.url
1020
+ }),
1021
+ to: add_url_properties('to', {
1022
+ params: intent?.params ?? null,
1023
+ routeId: intent?.route.id ?? null,
1024
+ url
1025
+ }),
1026
+ type
1027
+ };
1028
+
1029
+ if (delta !== undefined) {
1030
+ navigation.delta = delta;
1031
+ }
1032
+
1033
+ const cancellable = {
1034
+ ...navigation,
1035
+ cancel: () => {
1036
+ should_block = true;
1037
+ }
992
1038
  };
993
1039
 
994
- callbacks.before_navigate.forEach((fn) => fn(navigation));
1040
+ callbacks.before_navigate.forEach((fn) => fn(cancellable));
995
1041
 
996
1042
  if (should_block) {
997
1043
  blocked();
@@ -1003,13 +1049,11 @@ export function create_client({ target, base, trailing_slash }) {
1003
1049
  accepted();
1004
1050
 
1005
1051
  if (started) {
1006
- stores.navigating.set({
1007
- from: current.url,
1008
- to: url
1009
- });
1052
+ stores.navigating.set(navigation);
1010
1053
  }
1011
1054
 
1012
1055
  await update(
1056
+ intent,
1013
1057
  url,
1014
1058
  redirect_chain,
1015
1059
  {
@@ -1018,9 +1062,7 @@ export function create_client({ target, base, trailing_slash }) {
1018
1062
  details
1019
1063
  },
1020
1064
  () => {
1021
- const navigation = { from, to: url };
1022
1065
  callbacks.after_navigate.forEach((fn) => fn(navigation));
1023
-
1024
1066
  stores.navigating.set(null);
1025
1067
  }
1026
1068
  );
@@ -1129,9 +1171,15 @@ export function create_client({ target, base, trailing_slash }) {
1129
1171
  addEventListener('beforeunload', (e) => {
1130
1172
  let should_block = false;
1131
1173
 
1174
+ /** @type {import('types').Navigation & { cancel: () => void }} */
1132
1175
  const navigation = {
1133
- from: current.url,
1176
+ from: add_url_properties('from', {
1177
+ params: current.params,
1178
+ routeId: current.route?.id ?? null,
1179
+ url: current.url
1180
+ }),
1134
1181
  to: null,
1182
+ type: 'unload',
1135
1183
  cancel: () => (should_block = true)
1136
1184
  };
1137
1185
 
@@ -1160,7 +1208,7 @@ export function create_client({ target, base, trailing_slash }) {
1160
1208
  /** @param {Event} event */
1161
1209
  const trigger_prefetch = (event) => {
1162
1210
  const { url, options } = find_anchor(event);
1163
- if (url && options.prefetch === '') {
1211
+ if (url && options.prefetch) {
1164
1212
  if (is_external_url(url)) return;
1165
1213
  prefetch(url);
1166
1214
  }
@@ -1210,7 +1258,7 @@ export function create_client({ target, base, trailing_slash }) {
1210
1258
  // 2. 'rel' attribute includes external
1211
1259
  const rel = (a.getAttribute('rel') || '').split(/\s+/);
1212
1260
 
1213
- if (a.hasAttribute('download') || rel.includes('external') || options.reload === '') {
1261
+ if (a.hasAttribute('download') || rel.includes('external') || options.reload) {
1214
1262
  return;
1215
1263
  }
1216
1264
 
@@ -1236,7 +1284,7 @@ export function create_client({ target, base, trailing_slash }) {
1236
1284
 
1237
1285
  navigate({
1238
1286
  url,
1239
- scroll: options.noscroll === '' ? scroll_state() : null,
1287
+ scroll: options.noscroll ? scroll_state() : null,
1240
1288
  keepfocus: false,
1241
1289
  redirect_chain: [],
1242
1290
  details: {
@@ -1244,7 +1292,8 @@ export function create_client({ target, base, trailing_slash }) {
1244
1292
  replaceState: url.href === location.href
1245
1293
  },
1246
1294
  accepted: () => event.preventDefault(),
1247
- blocked: () => event.preventDefault()
1295
+ blocked: () => event.preventDefault(),
1296
+ type: 'link'
1248
1297
  });
1249
1298
  });
1250
1299
 
@@ -1254,6 +1303,8 @@ export function create_client({ target, base, trailing_slash }) {
1254
1303
  // with history.go, which means we end up back here, hence this check
1255
1304
  if (event.state[INDEX_KEY] === current_history_index) return;
1256
1305
 
1306
+ const delta = event.state[INDEX_KEY] - current_history_index;
1307
+
1257
1308
  navigate({
1258
1309
  url: new URL(location.href),
1259
1310
  scroll: scroll_positions[event.state[INDEX_KEY]],
@@ -1264,9 +1315,10 @@ export function create_client({ target, base, trailing_slash }) {
1264
1315
  current_history_index = event.state[INDEX_KEY];
1265
1316
  },
1266
1317
  blocked: () => {
1267
- const delta = current_history_index - event.state[INDEX_KEY];
1268
- history.go(delta);
1269
- }
1318
+ history.go(-delta);
1319
+ },
1320
+ type: 'popstate',
1321
+ delta
1270
1322
  });
1271
1323
  }
1272
1324
  });
@@ -1351,7 +1403,7 @@ export function create_client({ target, base, trailing_slash }) {
1351
1403
  )
1352
1404
  : original_error,
1353
1405
  validation_errors,
1354
- routeId
1406
+ route: routes.find((route) => route.id === routeId) ?? null
1355
1407
  });
1356
1408
  } catch (e) {
1357
1409
  const error = normalize_error(e);
@@ -1406,3 +1458,37 @@ async function load_data(url, invalid) {
1406
1458
 
1407
1459
  return server_data;
1408
1460
  }
1461
+
1462
+ // TODO remove for 1.0
1463
+ const properties = [
1464
+ 'hash',
1465
+ 'href',
1466
+ 'host',
1467
+ 'hostname',
1468
+ 'origin',
1469
+ 'pathname',
1470
+ 'port',
1471
+ 'protocol',
1472
+ 'search',
1473
+ 'searchParams',
1474
+ 'toString',
1475
+ 'toJSON'
1476
+ ];
1477
+
1478
+ /**
1479
+ * @param {'from' | 'to'} type
1480
+ * @param {import('types').NavigationTarget} target
1481
+ */
1482
+ function add_url_properties(type, target) {
1483
+ for (const prop of properties) {
1484
+ Object.defineProperty(target, prop, {
1485
+ get() {
1486
+ throw new Error(
1487
+ `The navigation shape changed - ${type}.${prop} should now be ${type}.url.${prop}`
1488
+ );
1489
+ }
1490
+ });
1491
+ }
1492
+
1493
+ return target;
1494
+ }
@@ -81,10 +81,11 @@ export interface DataNode {
81
81
  uses: Uses;
82
82
  }
83
83
 
84
- export type NavigationState = {
84
+ export interface NavigationState {
85
85
  branch: Array<BranchNode | undefined>;
86
86
  error: HttpError | Error | null;
87
87
  params: Record<string, string>;
88
+ route: CSRRoute | null;
88
89
  session_id: number;
89
90
  url: URL;
90
- };
91
+ }
@@ -27,16 +27,14 @@ export function find_anchor(event) {
27
27
  /** @type {HTMLAnchorElement | SVGAElement | undefined} */
28
28
  let a;
29
29
 
30
- const options = {
31
- /** @type {string | null} */
32
- noscroll: null,
30
+ /** @type {boolean | null} */
31
+ let noscroll = null;
33
32
 
34
- /** @type {string | null} */
35
- prefetch: null,
33
+ /** @type {boolean | null} */
34
+ let prefetch = null;
36
35
 
37
- /** @type {string | null} */
38
- reload: null
39
- };
36
+ /** @type {boolean | null} */
37
+ let reload = null;
40
38
 
41
39
  for (const element of event.composedPath()) {
42
40
  if (!(element instanceof Element)) continue;
@@ -46,22 +44,43 @@ export function find_anchor(event) {
46
44
  a = /** @type {HTMLAnchorElement | SVGAElement} */ (element);
47
45
  }
48
46
 
49
- if (options.noscroll === null) {
50
- options.noscroll = element.getAttribute('data-sveltekit-noscroll');
51
- }
47
+ if (noscroll === null) noscroll = get_link_option(element, 'data-sveltekit-noscroll');
48
+ if (prefetch === null) prefetch = get_link_option(element, 'data-sveltekit-prefetch');
49
+ if (reload === null) reload = get_link_option(element, 'data-sveltekit-reload');
50
+ }
52
51
 
53
- if (options.prefetch === null) {
54
- options.prefetch = element.getAttribute('data-sveltekit-prefetch');
55
- }
52
+ const url = a && new URL(a instanceof SVGAElement ? a.href.baseVal : a.href, document.baseURI);
56
53
 
57
- if (options.reload === null) {
58
- options.reload = element.getAttribute('data-sveltekit-reload');
54
+ return {
55
+ a,
56
+ url,
57
+ options: {
58
+ noscroll,
59
+ prefetch,
60
+ reload
59
61
  }
60
- }
62
+ };
63
+ }
61
64
 
62
- const url = a && new URL(a instanceof SVGAElement ? a.href.baseVal : a.href, document.baseURI);
65
+ const warned = new WeakSet();
66
+
67
+ /**
68
+ * @param {Element} element
69
+ * @param {string} attribute
70
+ */
71
+ function get_link_option(element, attribute) {
72
+ const value = element.getAttribute(attribute);
73
+ if (value === null) return value;
74
+
75
+ if (value === '') return true;
76
+ if (value === 'off') return false;
77
+
78
+ if (__SVELTEKIT_DEV__ && !warned.has(element)) {
79
+ console.error(`Unexpected value for ${attribute} — should be "" or "off"`, element);
80
+ warned.add(element);
81
+ }
63
82
 
64
- return { a, url, options };
83
+ return false;
65
84
  }
66
85
 
67
86
  /** @param {any} value */
@@ -63,7 +63,7 @@ export function create_fetch({ event, options, state, route, prerender_default }
63
63
  }
64
64
  }
65
65
 
66
- const resolved = resolve(event.url.pathname, requested.split('?')[0]);
66
+ const resolved = resolve(event.url.pathname, requested.split('?')[0]).replace(/#.+$/, '');
67
67
 
68
68
  /** @type {Response} */
69
69
  let response;
@@ -95,6 +95,8 @@ declare module '$app/environment' {
95
95
  * ```
96
96
  */
97
97
  declare module '$app/navigation' {
98
+ import { Navigation } from '@sveltejs/kit';
99
+
98
100
  /**
99
101
  * If called when the page is being updated following a navigation (in `onMount` or `afterNavigate` or an action, for example), this disables SvelteKit's built-in scroll handling.
100
102
  * This is generally discouraged, since it breaks user expectations.
@@ -158,17 +160,23 @@ declare module '$app/navigation' {
158
160
  export function prefetchRoutes(routes?: string[]): Promise<void>;
159
161
 
160
162
  /**
161
- * A navigation interceptor that triggers before we navigate to a new URL (internal or external) whether by clicking a link, calling `goto`, or using the browser back/forward controls.
162
- * This is helpful if we want to conditionally prevent a navigation from completing or lookup the upcoming url.
163
+ * A navigation interceptor that triggers before we navigate to a new URL, whether by clicking a link, calling `goto(...)`, or using the browser back/forward controls.
164
+ * Calling `cancel()` will prevent the navigation from completing.
165
+ *
166
+ * When navigating to an external URL, `navigation.to` will be `null`.
167
+ *
168
+ * `beforeNavigate` must be called during a component initialization. It remains active as long as the component is mounted.
163
169
  */
164
170
  export function beforeNavigate(
165
- fn: (navigation: { from: URL; to: URL | null; cancel: () => void }) => void
171
+ callback: (navigation: Navigation & { cancel: () => void }) => void
166
172
  ): void;
167
173
 
168
174
  /**
169
- * A lifecycle function that runs when the page mounts, and also whenever SvelteKit navigates to a new URL but stays on this component.
175
+ * A lifecycle function that runs the supplied `callback` when the current component mounts, and also whenever we navigate to a new URL.
176
+ *
177
+ * `afterNavigate` must be called during a component initialization. It remains active as long as the component is mounted.
170
178
  */
171
- export function afterNavigate(fn: (navigation: { from: URL | null; to: URL }) => void): void;
179
+ export function afterNavigate(callback: (navigation: Navigation) => void): void;
172
180
  }
173
181
 
174
182
  /**
@@ -210,7 +218,7 @@ declare module '$app/stores' {
210
218
  export const page: Readable<Page>;
211
219
  /**
212
220
  * A readable store.
213
- * When navigating starts, its value is `{ from: URL, to: URL }`,
221
+ * When navigating starts, its value is a `Navigation` object with `from`, `to`, `type` and (if `type === 'popstate'`) `delta` properties.
214
222
  * When navigating finishes, its value reverts to `null`.
215
223
  */
216
224
  export const navigating: Readable<Navigation | null>;
package/types/index.d.ts CHANGED
@@ -219,9 +219,19 @@ export interface LoadEvent<
219
219
  depends: (...deps: string[]) => void;
220
220
  }
221
221
 
222
+ export interface NavigationTarget {
223
+ params: Record<string, string> | null;
224
+ routeId: string | null;
225
+ url: URL;
226
+ }
227
+
228
+ export type NavigationType = 'load' | 'unload' | 'link' | 'goto' | 'popstate';
229
+
222
230
  export interface Navigation {
223
- from: URL;
224
- to: URL;
231
+ from: NavigationTarget | null;
232
+ to: NavigationTarget | null;
233
+ type: NavigationType;
234
+ delta?: number;
225
235
  }
226
236
 
227
237
  export interface Page<Params extends Record<string, string> = Record<string, string>> {