@remix-run/router 1.0.4 → 1.0.5-pre.1

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/utils.d.ts CHANGED
@@ -35,7 +35,6 @@ export interface RedirectResult {
35
35
  status: number;
36
36
  location: string;
37
37
  revalidate: boolean;
38
- external: boolean;
39
38
  }
40
39
  /**
41
40
  * Unsuccessful result from a loader or action
@@ -205,13 +204,13 @@ export declare function convertRoutesToDataRoutes(routes: AgnosticRouteObject[],
205
204
  /**
206
205
  * Matches the given routes to a location and returns the match data.
207
206
  *
208
- * @see https://reactrouter.com/docs/en/v6/utils/match-routes
207
+ * @see https://reactrouter.com/utils/match-routes
209
208
  */
210
209
  export declare function matchRoutes<RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject>(routes: RouteObjectType[], locationArg: Partial<Location> | string, basename?: string): AgnosticRouteMatch<string, RouteObjectType>[] | null;
211
210
  /**
212
211
  * Returns a path with params interpolated.
213
212
  *
214
- * @see https://reactrouter.com/docs/en/v6/utils/generate-path
213
+ * @see https://reactrouter.com/utils/generate-path
215
214
  */
216
215
  export declare function generatePath<Path extends string>(path: Path, params?: {
217
216
  [key in PathParam<Path>]: string;
@@ -261,18 +260,13 @@ export interface PathMatch<ParamKey extends string = string> {
261
260
  * Performs pattern matching on a URL pathname and returns information about
262
261
  * the match.
263
262
  *
264
- * @see https://reactrouter.com/docs/en/v6/utils/match-path
263
+ * @see https://reactrouter.com/utils/match-path
265
264
  */
266
265
  export declare function matchPath<ParamKey extends ParamParseKey<Path>, Path extends string>(pattern: PathPattern<Path> | Path, pathname: string): PathMatch<ParamKey> | null;
267
266
  /**
268
267
  * @private
269
268
  */
270
269
  export declare function stripBasename(pathname: string, basename: string): string | null;
271
- /**
272
- * @private
273
- */
274
- export declare function invariant(value: boolean, message?: string): asserts value;
275
- export declare function invariant<T>(value: T | null | undefined, message?: string): asserts value is T;
276
270
  /**
277
271
  * @private
278
272
  */
@@ -280,7 +274,7 @@ export declare function warning(cond: any, message: string): void;
280
274
  /**
281
275
  * Returns a resolved path object relative to the given pathname.
282
276
  *
283
- * @see https://reactrouter.com/docs/en/v6/utils/resolve-path
277
+ * @see https://reactrouter.com/utils/resolve-path
284
278
  */
285
279
  export declare function resolvePath(to: To, fromPathname?: string): Path;
286
280
  /**
package/history.ts CHANGED
@@ -447,6 +447,20 @@ export function createHashHistory(
447
447
  //#region UTILS
448
448
  ////////////////////////////////////////////////////////////////////////////////
449
449
 
450
+ /**
451
+ * @private
452
+ */
453
+ export function invariant(value: boolean, message?: string): asserts value;
454
+ export function invariant<T>(
455
+ value: T | null | undefined,
456
+ message?: string
457
+ ): asserts value is T;
458
+ export function invariant(value: any, message?: string) {
459
+ if (value === false || value === null || typeof value === "undefined") {
460
+ throw new Error(message);
461
+ }
462
+ }
463
+
450
464
  function warning(cond: any, message: string) {
451
465
  if (!cond) {
452
466
  // eslint-disable-next-line no-console
@@ -544,7 +558,7 @@ export function parsePath(path: string): Partial<Path> {
544
558
  return parsedPath;
545
559
  }
546
560
 
547
- export function createURL(location: Location | string): URL {
561
+ export function createClientSideURL(location: Location | string): URL {
548
562
  // window.location.origin is "null" (the literal string value) in Firefox
549
563
  // under certain conditions, notably when serving from a local HTML file
550
564
  // See https://bugzilla.mozilla.org/show_bug.cgi?id=878297
@@ -553,8 +567,12 @@ export function createURL(location: Location | string): URL {
553
567
  typeof window.location !== "undefined" &&
554
568
  window.location.origin !== "null"
555
569
  ? window.location.origin
556
- : "unknown://unknown";
570
+ : window.location.href;
557
571
  let href = typeof location === "string" ? location : createPath(location);
572
+ invariant(
573
+ base,
574
+ `No window.location.(origin|href) available to create URL for href: ${href}`
575
+ );
558
576
  return new URL(href, base);
559
577
  }
560
578
 
@@ -643,7 +661,9 @@ function getUrlBasedHistory(
643
661
  },
644
662
  encodeLocation(to) {
645
663
  // Encode a Location the same way window.location would
646
- let url = createURL(typeof to === "string" ? to : createPath(to));
664
+ let url = createClientSideURL(
665
+ typeof to === "string" ? to : createPath(to)
666
+ );
647
667
  return {
648
668
  pathname: url.pathname,
649
669
  search: url.search,
package/index.ts CHANGED
@@ -32,7 +32,6 @@ export {
32
32
  defer,
33
33
  generatePath,
34
34
  getToPathname,
35
- invariant,
36
35
  isRouteErrorResponse,
37
36
  joinPaths,
38
37
  json,
@@ -59,13 +58,13 @@ export type {
59
58
  Path,
60
59
  To,
61
60
  } from "./history";
62
-
63
61
  export {
64
62
  Action,
65
63
  createBrowserHistory,
66
64
  createPath,
67
65
  createHashHistory,
68
66
  createMemoryHistory,
67
+ invariant,
69
68
  parsePath,
70
69
  } from "./history";
71
70
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remix-run/router",
3
- "version": "1.0.4",
3
+ "version": "1.0.5-pre.1",
4
4
  "description": "Nested/Data-driven/Framework-agnostic Routing",
5
5
  "keywords": [
6
6
  "remix",
package/router.ts CHANGED
@@ -3,7 +3,8 @@ import {
3
3
  Action as HistoryAction,
4
4
  createLocation,
5
5
  createPath,
6
- createURL,
6
+ createClientSideURL,
7
+ invariant,
7
8
  parsePath,
8
9
  } from "./history";
9
10
  import type {
@@ -28,7 +29,6 @@ import {
28
29
  ResultType,
29
30
  convertRoutesToDataRoutes,
30
31
  getPathContributingMatches,
31
- invariant,
32
32
  isRouteErrorResponse,
33
33
  joinPaths,
34
34
  matchRoutes,
@@ -913,7 +913,7 @@ export function createRouter(init: RouterInit): Router {
913
913
 
914
914
  // Create a controller/Request for this navigation
915
915
  pendingNavigationController = new AbortController();
916
- let request = createRequest(
916
+ let request = createClientSideRequest(
917
917
  location,
918
918
  pendingNavigationController.signal,
919
919
  opts && opts.submission
@@ -952,6 +952,9 @@ export function createRouter(init: RouterInit): Router {
952
952
  ...opts.submission,
953
953
  };
954
954
  loadingNavigation = navigation;
955
+
956
+ // Create a GET request for the loaders
957
+ request = new Request(request.url, { signal: request.signal });
955
958
  }
956
959
 
957
960
  // Call loaders
@@ -1296,7 +1299,11 @@ export function createRouter(init: RouterInit): Router {
1296
1299
 
1297
1300
  // Call the action for the fetcher
1298
1301
  let abortController = new AbortController();
1299
- let fetchRequest = createRequest(path, abortController.signal, submission);
1302
+ let fetchRequest = createClientSideRequest(
1303
+ path,
1304
+ abortController.signal,
1305
+ submission
1306
+ );
1300
1307
  fetchControllers.set(key, abortController);
1301
1308
 
1302
1309
  let actionResult = await callLoaderOrAction(
@@ -1343,7 +1350,7 @@ export function createRouter(init: RouterInit): Router {
1343
1350
  // Start the data load for current matches, or the next location if we're
1344
1351
  // in the middle of a navigation
1345
1352
  let nextLocation = state.navigation.location || state.location;
1346
- let revalidationRequest = createRequest(
1353
+ let revalidationRequest = createClientSideRequest(
1347
1354
  nextLocation,
1348
1355
  abortController.signal
1349
1356
  );
@@ -1498,7 +1505,7 @@ export function createRouter(init: RouterInit): Router {
1498
1505
 
1499
1506
  // Call the loader for this fetcher route match
1500
1507
  let abortController = new AbortController();
1501
- let fetchRequest = createRequest(path, abortController.signal);
1508
+ let fetchRequest = createClientSideRequest(path, abortController.signal);
1502
1509
  fetchControllers.set(key, abortController);
1503
1510
  let result: DataResult = await callLoaderOrAction(
1504
1511
  "loader",
@@ -1599,17 +1606,17 @@ export function createRouter(init: RouterInit): Router {
1599
1606
  "Expected a location on the redirect navigation"
1600
1607
  );
1601
1608
 
1602
- if (
1603
- redirect.external &&
1604
- typeof window !== "undefined" &&
1605
- typeof window.location !== "undefined"
1606
- ) {
1607
- if (replace) {
1608
- window.location.replace(redirect.location);
1609
- } else {
1610
- window.location.assign(redirect.location);
1609
+ // Check if this an external redirect that goes to a new origin
1610
+ if (typeof window?.location !== "undefined") {
1611
+ let newOrigin = createClientSideURL(redirect.location).origin;
1612
+ if (window.location.origin !== newOrigin) {
1613
+ if (replace) {
1614
+ window.location.replace(redirect.location);
1615
+ } else {
1616
+ window.location.assign(redirect.location);
1617
+ }
1618
+ return;
1611
1619
  }
1612
- return;
1613
1620
  }
1614
1621
 
1615
1622
  // There's no need to abort on redirects, since we don't detect the
@@ -1672,7 +1679,7 @@ export function createRouter(init: RouterInit): Router {
1672
1679
  ...fetchersToLoad.map(([, href, match, fetchMatches]) =>
1673
1680
  callLoaderOrAction(
1674
1681
  "loader",
1675
- createRequest(href, request.signal),
1682
+ createClientSideRequest(href, request.signal),
1676
1683
  match,
1677
1684
  fetchMatches,
1678
1685
  router.basename
@@ -1981,7 +1988,7 @@ export function unstable_createStaticHandler(
1981
1988
  }
1982
1989
 
1983
1990
  let result = await queryImpl(request, location, matches);
1984
- if (result instanceof Response) {
1991
+ if (isResponse(result)) {
1985
1992
  return result;
1986
1993
  }
1987
1994
 
@@ -2039,7 +2046,7 @@ export function unstable_createStaticHandler(
2039
2046
  }
2040
2047
 
2041
2048
  let result = await queryImpl(request, location, matches, match);
2042
- if (result instanceof Response) {
2049
+ if (isResponse(result)) {
2043
2050
  return result;
2044
2051
  }
2045
2052
 
@@ -2080,7 +2087,7 @@ export function unstable_createStaticHandler(
2080
2087
  }
2081
2088
 
2082
2089
  let result = await loadRouteData(request, matches, routeMatch);
2083
- return result instanceof Response
2090
+ return isResponse(result)
2084
2091
  ? result
2085
2092
  : {
2086
2093
  ...result,
@@ -2117,7 +2124,7 @@ export function unstable_createStaticHandler(
2117
2124
  if (!actionMatch.route.action) {
2118
2125
  let error = getInternalRouterError(405, {
2119
2126
  method: request.method,
2120
- pathname: createURL(request.url).pathname,
2127
+ pathname: new URL(request.url).pathname,
2121
2128
  routeId: actionMatch.route.id,
2122
2129
  });
2123
2130
  if (isRouteRequest) {
@@ -2202,7 +2209,9 @@ export function unstable_createStaticHandler(
2202
2209
  };
2203
2210
  }
2204
2211
 
2205
- let context = await loadRouteData(request, matches);
2212
+ // Create a GET request for the loaders
2213
+ let loaderRequest = new Request(request.url, { signal: request.signal });
2214
+ let context = await loadRouteData(loaderRequest, matches);
2206
2215
 
2207
2216
  return {
2208
2217
  ...context,
@@ -2235,7 +2244,7 @@ export function unstable_createStaticHandler(
2235
2244
  if (isRouteRequest && !routeMatch?.route.loader) {
2236
2245
  throw getInternalRouterError(400, {
2237
2246
  method: request.method,
2238
- pathname: createURL(request.url).pathname,
2247
+ pathname: new URL(request.url).pathname,
2239
2248
  routeId: routeMatch?.route.id,
2240
2249
  });
2241
2250
  }
@@ -2526,9 +2535,9 @@ function shouldRevalidateLoader(
2526
2535
  isRevalidationRequired: boolean,
2527
2536
  actionResult: DataResult | undefined
2528
2537
  ) {
2529
- let currentUrl = createURL(currentLocation);
2538
+ let currentUrl = createClientSideURL(currentLocation);
2530
2539
  let currentParams = currentMatch.params;
2531
- let nextUrl = createURL(location);
2540
+ let nextUrl = createClientSideURL(location);
2532
2541
  let nextParams = match.params;
2533
2542
 
2534
2543
  // This is the default implementation as to when we revalidate. If the route
@@ -2607,7 +2616,7 @@ async function callLoaderOrAction(
2607
2616
  request.signal.removeEventListener("abort", onReject);
2608
2617
  }
2609
2618
 
2610
- if (result instanceof Response) {
2619
+ if (isResponse(result)) {
2611
2620
  let status = result.status;
2612
2621
 
2613
2622
  // Process redirects
@@ -2618,17 +2627,20 @@ async function callLoaderOrAction(
2618
2627
  "Redirects returned/thrown from loaders/actions must have a Location header"
2619
2628
  );
2620
2629
 
2621
- // Check if this an external redirect that goes to a new origin
2622
- let external = createURL(location).origin !== createURL("/").origin;
2630
+ let isAbsolute =
2631
+ /^[a-z+]+:\/\//i.test(location) || location.startsWith("//");
2623
2632
 
2624
2633
  // Support relative routing in internal redirects
2625
- if (!external) {
2634
+ if (!isAbsolute) {
2626
2635
  let activeMatches = matches.slice(0, matches.indexOf(match) + 1);
2627
2636
  let routePathnames = getPathContributingMatches(activeMatches).map(
2628
2637
  (match) => match.pathnameBase
2629
2638
  );
2630
- let requestPath = createURL(request.url).pathname;
2631
- let resolvedLocation = resolveTo(location, routePathnames, requestPath);
2639
+ let resolvedLocation = resolveTo(
2640
+ location,
2641
+ routePathnames,
2642
+ new URL(request.url).pathname
2643
+ );
2632
2644
  invariant(
2633
2645
  createPath(resolvedLocation),
2634
2646
  `Unable to resolve redirect location: ${location}`
@@ -2658,7 +2670,6 @@ async function callLoaderOrAction(
2658
2670
  status,
2659
2671
  location,
2660
2672
  revalidate: result.headers.get("X-Remix-Revalidate") !== null,
2661
- external,
2662
2673
  };
2663
2674
  }
2664
2675
 
@@ -2708,12 +2719,15 @@ async function callLoaderOrAction(
2708
2719
  return { type: ResultType.data, data: result };
2709
2720
  }
2710
2721
 
2711
- function createRequest(
2722
+ // Utility method for creating the Request instances for loaders/actions during
2723
+ // client-side navigations and fetches. During SSR we will always have a
2724
+ // Request instance from the static handler (query/queryRoute)
2725
+ function createClientSideRequest(
2712
2726
  location: string | Location,
2713
2727
  signal: AbortSignal,
2714
2728
  submission?: Submission
2715
2729
  ): Request {
2716
- let url = createURL(stripHashFromPath(location)).toString();
2730
+ let url = createClientSideURL(stripHashFromPath(location)).toString();
2717
2731
  let init: RequestInit = { signal };
2718
2732
 
2719
2733
  if (submission) {
@@ -3034,8 +3048,18 @@ function isRedirectResult(result?: DataResult): result is RedirectResult {
3034
3048
  return (result && result.type) === ResultType.redirect;
3035
3049
  }
3036
3050
 
3051
+ function isResponse(value: any): value is Response {
3052
+ return (
3053
+ value != null &&
3054
+ typeof value.status === "number" &&
3055
+ typeof value.statusText === "string" &&
3056
+ typeof value.headers === "object" &&
3057
+ typeof value.body !== "undefined"
3058
+ );
3059
+ }
3060
+
3037
3061
  function isRedirectResponse(result: any): result is Response {
3038
- if (!(result instanceof Response)) {
3062
+ if (!isResponse(result)) {
3039
3063
  return false;
3040
3064
  }
3041
3065
 
@@ -3047,7 +3071,7 @@ function isRedirectResponse(result: any): result is Response {
3047
3071
  function isQueryRouteResponse(obj: any): obj is QueryRouteResponse {
3048
3072
  return (
3049
3073
  obj &&
3050
- obj.response instanceof Response &&
3074
+ isResponse(obj.response) &&
3051
3075
  (obj.type === ResultType.data || ResultType.error)
3052
3076
  );
3053
3077
  }
package/utils.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Location, Path, To } from "./history";
2
- import { parsePath } from "./history";
2
+ import { invariant, parsePath } from "./history";
3
3
 
4
4
  /**
5
5
  * Map of routeId -> data returned from a loader/action/error
@@ -41,7 +41,6 @@ export interface RedirectResult {
41
41
  status: number;
42
42
  location: string;
43
43
  revalidate: boolean;
44
- external: boolean;
45
44
  }
46
45
 
47
46
  /**
@@ -309,7 +308,7 @@ export function convertRoutesToDataRoutes(
309
308
  /**
310
309
  * Matches the given routes to a location and returns the match data.
311
310
  *
312
- * @see https://reactrouter.com/docs/en/v6/utils/match-routes
311
+ * @see https://reactrouter.com/utils/match-routes
313
312
  */
314
313
  export function matchRoutes<
315
314
  RouteObjectType extends AgnosticRouteObject = AgnosticRouteObject
@@ -531,7 +530,7 @@ function matchRouteBranch<
531
530
  /**
532
531
  * Returns a path with params interpolated.
533
532
  *
534
- * @see https://reactrouter.com/docs/en/v6/utils/generate-path
533
+ * @see https://reactrouter.com/utils/generate-path
535
534
  */
536
535
  export function generatePath<Path extends string>(
537
536
  path: Path,
@@ -609,7 +608,7 @@ type Mutable<T> = {
609
608
  * Performs pattern matching on a URL pathname and returns information about
610
609
  * the match.
611
610
  *
612
- * @see https://reactrouter.com/docs/en/v6/utils/match-path
611
+ * @see https://reactrouter.com/utils/match-path
613
612
  */
614
613
  export function matchPath<
615
614
  ParamKey extends ParamParseKey<Path>,
@@ -771,20 +770,6 @@ export function stripBasename(
771
770
  return pathname.slice(startIndex) || "/";
772
771
  }
773
772
 
774
- /**
775
- * @private
776
- */
777
- export function invariant(value: boolean, message?: string): asserts value;
778
- export function invariant<T>(
779
- value: T | null | undefined,
780
- message?: string
781
- ): asserts value is T;
782
- export function invariant(value: any, message?: string) {
783
- if (value === false || value === null || typeof value === "undefined") {
784
- throw new Error(message);
785
- }
786
- }
787
-
788
773
  /**
789
774
  * @private
790
775
  */
@@ -808,7 +793,7 @@ export function warning(cond: any, message: string): void {
808
793
  /**
809
794
  * Returns a resolved path object relative to the given pathname.
810
795
  *
811
- * @see https://reactrouter.com/docs/en/v6/utils/resolve-path
796
+ * @see https://reactrouter.com/utils/resolve-path
812
797
  */
813
798
  export function resolvePath(to: To, fromPathname = "/"): Path {
814
799
  let {