@remix-run/router 1.11.0 → 1.12.0

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": "@remix-run/router",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "description": "Nested/Data-driven/Framework-agnostic Routing",
5
5
  "keywords": [
6
6
  "remix",
package/router.ts CHANGED
@@ -411,6 +411,7 @@ export interface RouterSubscriber {
411
411
  opts: {
412
412
  deletedFetchers: string[];
413
413
  unstable_viewTransitionOpts?: ViewTransitionOpts;
414
+ unstable_flushSync: boolean;
414
415
  }
415
416
  ): void;
416
417
  }
@@ -436,6 +437,7 @@ export type RelativeRoutingType = "route" | "path";
436
437
  type BaseNavigateOrFetchOptions = {
437
438
  preventScrollReset?: boolean;
438
439
  relative?: RelativeRoutingType;
440
+ unstable_flushSync?: boolean;
439
441
  };
440
442
 
441
443
  // Only allowed for navigations
@@ -1018,7 +1020,10 @@ export function createRouter(init: RouterInit): Router {
1018
1020
  // Update our state and notify the calling context of the change
1019
1021
  function updateState(
1020
1022
  newState: Partial<RouterState>,
1021
- viewTransitionOpts?: ViewTransitionOpts
1023
+ opts: {
1024
+ flushSync?: boolean;
1025
+ viewTransitionOpts?: ViewTransitionOpts;
1026
+ } = {}
1022
1027
  ): void {
1023
1028
  state = {
1024
1029
  ...state,
@@ -1045,10 +1050,14 @@ export function createRouter(init: RouterInit): Router {
1045
1050
  });
1046
1051
  }
1047
1052
 
1048
- subscribers.forEach((subscriber) =>
1053
+ // Iterate over a local copy so that if flushSync is used and we end up
1054
+ // removing and adding a new subscriber due to the useCallback dependencies,
1055
+ // we don't get ourselves into a loop calling the new subscriber immediately
1056
+ [...subscribers].forEach((subscriber) =>
1049
1057
  subscriber(state, {
1050
1058
  deletedFetchers: deletedFetchersKeys,
1051
- unstable_viewTransitionOpts: viewTransitionOpts,
1059
+ unstable_viewTransitionOpts: opts.viewTransitionOpts,
1060
+ unstable_flushSync: opts.flushSync === true,
1052
1061
  })
1053
1062
  );
1054
1063
 
@@ -1066,7 +1075,8 @@ export function createRouter(init: RouterInit): Router {
1066
1075
  // - Can pass any other state in newState
1067
1076
  function completeNavigation(
1068
1077
  location: Location,
1069
- newState: Partial<Omit<RouterState, "action" | "location" | "navigation">>
1078
+ newState: Partial<Omit<RouterState, "action" | "location" | "navigation">>,
1079
+ { flushSync }: { flushSync?: boolean } = {}
1070
1080
  ): void {
1071
1081
  // Deduce if we're in a loading/actionReload state:
1072
1082
  // - We have committed actionData in the store
@@ -1188,7 +1198,10 @@ export function createRouter(init: RouterInit): Router {
1188
1198
  preventScrollReset,
1189
1199
  blockers,
1190
1200
  },
1191
- viewTransitionOpts
1201
+ {
1202
+ viewTransitionOpts,
1203
+ flushSync: flushSync === true,
1204
+ }
1192
1205
  );
1193
1206
 
1194
1207
  // Reset stateful navigation vars
@@ -1266,6 +1279,8 @@ export function createRouter(init: RouterInit): Router {
1266
1279
  ? opts.preventScrollReset === true
1267
1280
  : undefined;
1268
1281
 
1282
+ let flushSync = (opts && opts.unstable_flushSync) === true;
1283
+
1269
1284
  let blockerKey = shouldBlockNavigation({
1270
1285
  currentLocation,
1271
1286
  nextLocation,
@@ -1304,6 +1319,7 @@ export function createRouter(init: RouterInit): Router {
1304
1319
  preventScrollReset,
1305
1320
  replace: opts && opts.replace,
1306
1321
  enableViewTransition: opts && opts.unstable_viewTransition,
1322
+ flushSync,
1307
1323
  });
1308
1324
  }
1309
1325
 
@@ -1355,6 +1371,7 @@ export function createRouter(init: RouterInit): Router {
1355
1371
  preventScrollReset?: boolean;
1356
1372
  replace?: boolean;
1357
1373
  enableViewTransition?: boolean;
1374
+ flushSync?: boolean;
1358
1375
  }
1359
1376
  ): Promise<void> {
1360
1377
  // Abort any in-progress navigations and start a new one. Unset any ongoing
@@ -1376,6 +1393,7 @@ export function createRouter(init: RouterInit): Router {
1376
1393
  let routesToUse = inFlightDataRoutes || dataRoutes;
1377
1394
  let loadingNavigation = opts && opts.overrideNavigation;
1378
1395
  let matches = matchRoutes(routesToUse, location, basename);
1396
+ let flushSync = (opts && opts.flushSync) === true;
1379
1397
 
1380
1398
  // Short circuit with a 404 on the root error boundary if we match nothing
1381
1399
  if (!matches) {
@@ -1384,13 +1402,17 @@ export function createRouter(init: RouterInit): Router {
1384
1402
  getShortCircuitMatches(routesToUse);
1385
1403
  // Cancel all pending deferred on 404s since we don't keep any routes
1386
1404
  cancelActiveDeferreds();
1387
- completeNavigation(location, {
1388
- matches: notFoundMatches,
1389
- loaderData: {},
1390
- errors: {
1391
- [route.id]: error,
1405
+ completeNavigation(
1406
+ location,
1407
+ {
1408
+ matches: notFoundMatches,
1409
+ loaderData: {},
1410
+ errors: {
1411
+ [route.id]: error,
1412
+ },
1392
1413
  },
1393
- });
1414
+ { flushSync }
1415
+ );
1394
1416
  return;
1395
1417
  }
1396
1418
 
@@ -1406,7 +1428,7 @@ export function createRouter(init: RouterInit): Router {
1406
1428
  isHashChangeOnly(state.location, location) &&
1407
1429
  !(opts && opts.submission && isMutationMethod(opts.submission.formMethod))
1408
1430
  ) {
1409
- completeNavigation(location, { matches });
1431
+ completeNavigation(location, { matches }, { flushSync });
1410
1432
  return;
1411
1433
  }
1412
1434
 
@@ -1440,7 +1462,7 @@ export function createRouter(init: RouterInit): Router {
1440
1462
  location,
1441
1463
  opts.submission,
1442
1464
  matches,
1443
- { replace: opts.replace }
1465
+ { replace: opts.replace, flushSync }
1444
1466
  );
1445
1467
 
1446
1468
  if (actionOutput.shortCircuited) {
@@ -1450,6 +1472,7 @@ export function createRouter(init: RouterInit): Router {
1450
1472
  pendingActionData = actionOutput.pendingActionData;
1451
1473
  pendingError = actionOutput.pendingActionError;
1452
1474
  loadingNavigation = getLoadingNavigation(location, opts.submission);
1475
+ flushSync = false;
1453
1476
 
1454
1477
  // Create a GET request for the loaders
1455
1478
  request = new Request(request.url, { signal: request.signal });
@@ -1464,6 +1487,7 @@ export function createRouter(init: RouterInit): Router {
1464
1487
  opts && opts.submission,
1465
1488
  opts && opts.fetcherSubmission,
1466
1489
  opts && opts.replace,
1490
+ flushSync,
1467
1491
  pendingActionData,
1468
1492
  pendingError
1469
1493
  );
@@ -1492,13 +1516,13 @@ export function createRouter(init: RouterInit): Router {
1492
1516
  location: Location,
1493
1517
  submission: Submission,
1494
1518
  matches: AgnosticDataRouteMatch[],
1495
- opts: { replace?: boolean } = {}
1519
+ opts: { replace?: boolean; flushSync?: boolean } = {}
1496
1520
  ): Promise<HandleActionResult> {
1497
1521
  interruptActiveLoads();
1498
1522
 
1499
1523
  // Put us in a submitting state
1500
1524
  let navigation = getSubmittingNavigation(location, submission);
1501
- updateState({ navigation });
1525
+ updateState({ navigation }, { flushSync: opts.flushSync === true });
1502
1526
 
1503
1527
  // Call our action and get the result
1504
1528
  let result: DataResult;
@@ -1583,6 +1607,7 @@ export function createRouter(init: RouterInit): Router {
1583
1607
  submission?: Submission,
1584
1608
  fetcherSubmission?: Submission,
1585
1609
  replace?: boolean,
1610
+ flushSync?: boolean,
1586
1611
  pendingActionData?: RouteData,
1587
1612
  pendingError?: RouteData
1588
1613
  ): Promise<HandleLoadersResult> {
@@ -1629,14 +1654,18 @@ export function createRouter(init: RouterInit): Router {
1629
1654
  // Short circuit if we have no loaders to run
1630
1655
  if (matchesToLoad.length === 0 && revalidatingFetchers.length === 0) {
1631
1656
  let updatedFetchers = markFetchRedirectsDone();
1632
- completeNavigation(location, {
1633
- matches,
1634
- loaderData: {},
1635
- // Commit pending error if we're short circuiting
1636
- errors: pendingError || null,
1637
- ...(pendingActionData ? { actionData: pendingActionData } : {}),
1638
- ...(updatedFetchers ? { fetchers: new Map(state.fetchers) } : {}),
1639
- });
1657
+ completeNavigation(
1658
+ location,
1659
+ {
1660
+ matches,
1661
+ loaderData: {},
1662
+ // Commit pending error if we're short circuiting
1663
+ errors: pendingError || null,
1664
+ ...(pendingActionData ? { actionData: pendingActionData } : {}),
1665
+ ...(updatedFetchers ? { fetchers: new Map(state.fetchers) } : {}),
1666
+ },
1667
+ { flushSync }
1668
+ );
1640
1669
  return { shortCircuited: true };
1641
1670
  }
1642
1671
 
@@ -1654,17 +1683,22 @@ export function createRouter(init: RouterInit): Router {
1654
1683
  state.fetchers.set(rf.key, revalidatingFetcher);
1655
1684
  });
1656
1685
  let actionData = pendingActionData || state.actionData;
1657
- updateState({
1658
- navigation: loadingNavigation,
1659
- ...(actionData
1660
- ? Object.keys(actionData).length === 0
1661
- ? { actionData: null }
1662
- : { actionData }
1663
- : {}),
1664
- ...(revalidatingFetchers.length > 0
1665
- ? { fetchers: new Map(state.fetchers) }
1666
- : {}),
1667
- });
1686
+ updateState(
1687
+ {
1688
+ navigation: loadingNavigation,
1689
+ ...(actionData
1690
+ ? Object.keys(actionData).length === 0
1691
+ ? { actionData: null }
1692
+ : { actionData }
1693
+ : {}),
1694
+ ...(revalidatingFetchers.length > 0
1695
+ ? { fetchers: new Map(state.fetchers) }
1696
+ : {}),
1697
+ },
1698
+ {
1699
+ flushSync,
1700
+ }
1701
+ );
1668
1702
  }
1669
1703
 
1670
1704
  revalidatingFetchers.forEach((rf) => {
@@ -1764,18 +1798,6 @@ export function createRouter(init: RouterInit): Router {
1764
1798
  };
1765
1799
  }
1766
1800
 
1767
- function getFetcher<TData = any>(key: string): Fetcher<TData> {
1768
- if (future.v7_fetcherPersist) {
1769
- activeFetchers.set(key, (activeFetchers.get(key) || 0) + 1);
1770
- // If this fetcher was previously marked for deletion, unmark it since we
1771
- // have a new instance
1772
- if (deletedFetchers.has(key)) {
1773
- deletedFetchers.delete(key);
1774
- }
1775
- }
1776
- return state.fetchers.get(key) || IDLE_FETCHER;
1777
- }
1778
-
1779
1801
  // Trigger a fetcher load/submit for the given fetcher key
1780
1802
  function fetch(
1781
1803
  key: string,
@@ -1792,6 +1814,7 @@ export function createRouter(init: RouterInit): Router {
1792
1814
  }
1793
1815
 
1794
1816
  if (fetchControllers.has(key)) abortFetcher(key);
1817
+ let flushSync = (opts && opts.unstable_flushSync) === true;
1795
1818
 
1796
1819
  let routesToUse = inFlightDataRoutes || dataRoutes;
1797
1820
  let normalizedPath = normalizeTo(
@@ -1809,7 +1832,8 @@ export function createRouter(init: RouterInit): Router {
1809
1832
  setFetcherError(
1810
1833
  key,
1811
1834
  routeId,
1812
- getInternalRouterError(404, { pathname: normalizedPath })
1835
+ getInternalRouterError(404, { pathname: normalizedPath }),
1836
+ { flushSync }
1813
1837
  );
1814
1838
  return;
1815
1839
  }
@@ -1822,7 +1846,7 @@ export function createRouter(init: RouterInit): Router {
1822
1846
  );
1823
1847
 
1824
1848
  if (error) {
1825
- setFetcherError(key, routeId, error);
1849
+ setFetcherError(key, routeId, error, { flushSync });
1826
1850
  return;
1827
1851
  }
1828
1852
 
@@ -1831,14 +1855,30 @@ export function createRouter(init: RouterInit): Router {
1831
1855
  pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
1832
1856
 
1833
1857
  if (submission && isMutationMethod(submission.formMethod)) {
1834
- handleFetcherAction(key, routeId, path, match, matches, submission);
1858
+ handleFetcherAction(
1859
+ key,
1860
+ routeId,
1861
+ path,
1862
+ match,
1863
+ matches,
1864
+ flushSync,
1865
+ submission
1866
+ );
1835
1867
  return;
1836
1868
  }
1837
1869
 
1838
1870
  // Store off the match so we can call it's shouldRevalidate on subsequent
1839
1871
  // revalidations
1840
1872
  fetchLoadMatches.set(key, { routeId, path });
1841
- handleFetcherLoader(key, routeId, path, match, matches, submission);
1873
+ handleFetcherLoader(
1874
+ key,
1875
+ routeId,
1876
+ path,
1877
+ match,
1878
+ matches,
1879
+ flushSync,
1880
+ submission
1881
+ );
1842
1882
  }
1843
1883
 
1844
1884
  // Call the action for the matched fetcher.submit(), and then handle redirects,
@@ -1849,6 +1889,7 @@ export function createRouter(init: RouterInit): Router {
1849
1889
  path: string,
1850
1890
  match: AgnosticDataRouteMatch,
1851
1891
  requestMatches: AgnosticDataRouteMatch[],
1892
+ flushSync: boolean,
1852
1893
  submission: Submission
1853
1894
  ) {
1854
1895
  interruptActiveLoads();
@@ -1860,15 +1901,15 @@ export function createRouter(init: RouterInit): Router {
1860
1901
  pathname: path,
1861
1902
  routeId: routeId,
1862
1903
  });
1863
- setFetcherError(key, routeId, error);
1904
+ setFetcherError(key, routeId, error, { flushSync });
1864
1905
  return;
1865
1906
  }
1866
1907
 
1867
1908
  // Put this fetcher into it's submitting state
1868
1909
  let existingFetcher = state.fetchers.get(key);
1869
- let fetcher = getSubmittingFetcher(submission, existingFetcher);
1870
- state.fetchers.set(key, fetcher);
1871
- updateState({ fetchers: new Map(state.fetchers) });
1910
+ updateFetcherState(key, getSubmittingFetcher(submission, existingFetcher), {
1911
+ flushSync,
1912
+ });
1872
1913
 
1873
1914
  // Call the action for the fetcher
1874
1915
  let abortController = new AbortController();
@@ -1901,8 +1942,7 @@ export function createRouter(init: RouterInit): Router {
1901
1942
  }
1902
1943
 
1903
1944
  if (deletedFetchers.has(key)) {
1904
- state.fetchers.set(key, getDoneFetcher(undefined));
1905
- updateState({ fetchers: new Map(state.fetchers) });
1945
+ updateFetcherState(key, getDoneFetcher(undefined));
1906
1946
  return;
1907
1947
  }
1908
1948
 
@@ -1913,16 +1953,11 @@ export function createRouter(init: RouterInit): Router {
1913
1953
  // should take precedence over this redirect navigation. We already
1914
1954
  // set isRevalidationRequired so all loaders for the new route should
1915
1955
  // fire unless opted out via shouldRevalidate
1916
- let doneFetcher = getDoneFetcher(undefined);
1917
- state.fetchers.set(key, doneFetcher);
1918
- updateState({ fetchers: new Map(state.fetchers) });
1956
+ updateFetcherState(key, getDoneFetcher(undefined));
1919
1957
  return;
1920
1958
  } else {
1921
1959
  fetchRedirectIds.add(key);
1922
- let loadingFetcher = getLoadingFetcher(submission);
1923
- state.fetchers.set(key, loadingFetcher);
1924
- updateState({ fetchers: new Map(state.fetchers) });
1925
-
1960
+ updateFetcherState(key, getLoadingFetcher(submission));
1926
1961
  return startRedirectNavigation(state, actionResult, {
1927
1962
  fetcherSubmission: submission,
1928
1963
  });
@@ -2106,16 +2141,18 @@ export function createRouter(init: RouterInit): Router {
2106
2141
  path: string,
2107
2142
  match: AgnosticDataRouteMatch,
2108
2143
  matches: AgnosticDataRouteMatch[],
2144
+ flushSync: boolean,
2109
2145
  submission?: Submission
2110
2146
  ) {
2111
2147
  let existingFetcher = state.fetchers.get(key);
2112
- // Put this fetcher into it's loading state
2113
- let loadingFetcher = getLoadingFetcher(
2114
- submission,
2115
- existingFetcher ? existingFetcher.data : undefined
2148
+ updateFetcherState(
2149
+ key,
2150
+ getLoadingFetcher(
2151
+ submission,
2152
+ existingFetcher ? existingFetcher.data : undefined
2153
+ ),
2154
+ { flushSync }
2116
2155
  );
2117
- state.fetchers.set(key, loadingFetcher);
2118
- updateState({ fetchers: new Map(state.fetchers) });
2119
2156
 
2120
2157
  // Call the loader for this fetcher route match
2121
2158
  let abortController = new AbortController();
@@ -2158,8 +2195,7 @@ export function createRouter(init: RouterInit): Router {
2158
2195
  }
2159
2196
 
2160
2197
  if (deletedFetchers.has(key)) {
2161
- state.fetchers.set(key, getDoneFetcher(undefined));
2162
- updateState({ fetchers: new Map(state.fetchers) });
2198
+ updateFetcherState(key, getDoneFetcher(undefined));
2163
2199
  return;
2164
2200
  }
2165
2201
 
@@ -2168,9 +2204,7 @@ export function createRouter(init: RouterInit): Router {
2168
2204
  if (pendingNavigationLoadId > originatingLoadId) {
2169
2205
  // A new navigation was kicked off after our loader started, so that
2170
2206
  // should take precedence over this redirect navigation
2171
- let doneFetcher = getDoneFetcher(undefined);
2172
- state.fetchers.set(key, doneFetcher);
2173
- updateState({ fetchers: new Map(state.fetchers) });
2207
+ updateFetcherState(key, getDoneFetcher(undefined));
2174
2208
  return;
2175
2209
  } else {
2176
2210
  fetchRedirectIds.add(key);
@@ -2188,9 +2222,7 @@ export function createRouter(init: RouterInit): Router {
2188
2222
  invariant(!isDeferredResult(result), "Unhandled fetcher deferred data");
2189
2223
 
2190
2224
  // Put the fetcher back into an idle state
2191
- let doneFetcher = getDoneFetcher(result.data);
2192
- state.fetchers.set(key, doneFetcher);
2193
- updateState({ fetchers: new Map(state.fetchers) });
2225
+ updateFetcherState(key, getDoneFetcher(result.data));
2194
2226
  }
2195
2227
 
2196
2228
  /**
@@ -2399,15 +2431,47 @@ export function createRouter(init: RouterInit): Router {
2399
2431
  });
2400
2432
  }
2401
2433
 
2402
- function setFetcherError(key: string, routeId: string, error: any) {
2434
+ function updateFetcherState(
2435
+ key: string,
2436
+ fetcher: Fetcher,
2437
+ opts: { flushSync?: boolean } = {}
2438
+ ) {
2439
+ state.fetchers.set(key, fetcher);
2440
+ updateState(
2441
+ { fetchers: new Map(state.fetchers) },
2442
+ { flushSync: (opts && opts.flushSync) === true }
2443
+ );
2444
+ }
2445
+
2446
+ function setFetcherError(
2447
+ key: string,
2448
+ routeId: string,
2449
+ error: any,
2450
+ opts: { flushSync?: boolean } = {}
2451
+ ) {
2403
2452
  let boundaryMatch = findNearestBoundary(state.matches, routeId);
2404
2453
  deleteFetcher(key);
2405
- updateState({
2406
- errors: {
2407
- [boundaryMatch.route.id]: error,
2454
+ updateState(
2455
+ {
2456
+ errors: {
2457
+ [boundaryMatch.route.id]: error,
2458
+ },
2459
+ fetchers: new Map(state.fetchers),
2408
2460
  },
2409
- fetchers: new Map(state.fetchers),
2410
- });
2461
+ { flushSync: (opts && opts.flushSync) === true }
2462
+ );
2463
+ }
2464
+
2465
+ function getFetcher<TData = any>(key: string): Fetcher<TData> {
2466
+ if (future.v7_fetcherPersist) {
2467
+ activeFetchers.set(key, (activeFetchers.get(key) || 0) + 1);
2468
+ // If this fetcher was previously marked for deletion, unmark it since we
2469
+ // have a new instance
2470
+ if (deletedFetchers.has(key)) {
2471
+ deletedFetchers.delete(key);
2472
+ }
2473
+ }
2474
+ return state.fetchers.get(key) || IDLE_FETCHER;
2411
2475
  }
2412
2476
 
2413
2477
  function deleteFetcher(key: string): void {
@@ -3255,11 +3319,9 @@ function normalizeTo(
3255
3319
  ) {
3256
3320
  let contextualMatches: AgnosticDataRouteMatch[];
3257
3321
  let activeRouteMatch: AgnosticDataRouteMatch | undefined;
3258
- if (fromRouteId != null && relative !== "path") {
3322
+ if (fromRouteId) {
3259
3323
  // Grab matches up to the calling route so our route-relative logic is
3260
- // relative to the correct source route. When using relative:path,
3261
- // fromRouteId is ignored since that is always relative to the current
3262
- // location path
3324
+ // relative to the correct source route
3263
3325
  contextualMatches = [];
3264
3326
  for (let match of matches) {
3265
3327
  contextualMatches.push(match);
package/utils.ts CHANGED
@@ -1188,17 +1188,36 @@ export function resolveTo(
1188
1188
  // `to` values that do not provide a pathname. `to` can simply be a search or
1189
1189
  // hash string, in which case we should assume that the navigation is relative
1190
1190
  // to the current location's pathname and *not* the route pathname.
1191
- if (isPathRelative || toPathname == null) {
1191
+ if (toPathname == null) {
1192
1192
  from = locationPathname;
1193
+ } else if (isPathRelative) {
1194
+ let fromSegments = routePathnames[routePathnames.length - 1]
1195
+ .replace(/^\//, "")
1196
+ .split("/");
1197
+
1198
+ if (toPathname.startsWith("..")) {
1199
+ let toSegments = toPathname.split("/");
1200
+
1201
+ // With relative="path", each leading .. segment means "go up one URL segment"
1202
+ while (toSegments[0] === "..") {
1203
+ toSegments.shift();
1204
+ fromSegments.pop();
1205
+ }
1206
+
1207
+ to.pathname = toSegments.join("/");
1208
+ }
1209
+
1210
+ from = "/" + fromSegments.join("/");
1193
1211
  } else {
1194
1212
  let routePathnameIndex = routePathnames.length - 1;
1195
1213
 
1196
1214
  if (toPathname.startsWith("..")) {
1197
1215
  let toSegments = toPathname.split("/");
1198
1216
 
1199
- // Each leading .. segment means "go up one route" instead of "go up one
1200
- // URL segment". This is a key difference from how <a href> works and a
1201
- // major reason we call this a "to" value instead of a "href".
1217
+ // With relative="route" (the default), each leading .. segment means
1218
+ // "go up one route" instead of "go up one URL segment". This is a key
1219
+ // difference from how <a href> works and a major reason we call this a
1220
+ // "to" value instead of a "href".
1202
1221
  while (toSegments[0] === "..") {
1203
1222
  toSegments.shift();
1204
1223
  routePathnameIndex -= 1;