@remix-run/router 1.7.2 → 1.8.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/dist/utils.d.ts CHANGED
@@ -37,6 +37,7 @@ export interface RedirectResult {
37
37
  status: number;
38
38
  location: string;
39
39
  revalidate: boolean;
40
+ reloadDocument?: boolean;
40
41
  }
41
42
  /**
42
43
  * Unsuccessful result from a loader or action
@@ -451,6 +452,12 @@ export type RedirectFunction = (url: string, init?: number | ResponseInit) => Re
451
452
  * Defaults to "302 Found".
452
453
  */
453
454
  export declare const redirect: RedirectFunction;
455
+ /**
456
+ * A redirect response that will force a document reload to the new location.
457
+ * Sets the status code and the `Location` header.
458
+ * Defaults to "302 Found".
459
+ */
460
+ export declare const redirectDocument: RedirectFunction;
454
461
  /**
455
462
  * @private
456
463
  * Utility class we use to hold auto-unwrapped 4xx/5xx Response bodies
package/history.ts CHANGED
@@ -423,6 +423,17 @@ export function createHashHistory(
423
423
  search = "",
424
424
  hash = "",
425
425
  } = parsePath(window.location.hash.substr(1));
426
+
427
+ // Hash URL should always have a leading / just like window.location.pathname
428
+ // does, so if an app ends up at a route like /#something then we add a
429
+ // leading slash so all of our path-matching behaves the same as if it would
430
+ // in a browser router. This is particularly important when there exists a
431
+ // root splat route (<Route path="*">) since that matches internally against
432
+ // "/*" and we'd expect /#something to 404 in a hash router app.
433
+ if (!pathname.startsWith("/") && !pathname.startsWith(".")) {
434
+ pathname = "/" + pathname;
435
+ }
436
+
426
437
  return createLocation(
427
438
  "",
428
439
  { pathname, search, hash },
package/index.ts CHANGED
@@ -39,6 +39,7 @@ export {
39
39
  matchRoutes,
40
40
  normalizePathname,
41
41
  redirect,
42
+ redirectDocument,
42
43
  resolvePath,
43
44
  resolveTo,
44
45
  stripBasename,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remix-run/router",
3
- "version": "1.7.2",
3
+ "version": "1.8.0",
4
4
  "description": "Nested/Data-driven/Framework-agnostic Routing",
5
5
  "keywords": [
6
6
  "remix",
@@ -25,7 +25,7 @@
25
25
  "CHANGELOG.md"
26
26
  ],
27
27
  "engines": {
28
- "node": ">=14"
28
+ "node": ">=14.0.0"
29
29
  },
30
30
  "publishConfig": {
31
31
  "access": "public"
package/router.ts CHANGED
@@ -2111,12 +2111,23 @@ export function createRouter(init: RouterInit): Router {
2111
2111
  redirectLocation,
2112
2112
  "Expected a location on the redirect navigation"
2113
2113
  );
2114
- // Check if this an absolute external redirect that goes to a new origin
2115
- if (ABSOLUTE_URL_REGEX.test(redirect.location) && isBrowser) {
2116
- let url = init.history.createURL(redirect.location);
2117
- let isDifferentBasename = stripBasename(url.pathname, basename) == null;
2118
2114
 
2119
- if (routerWindow.location.origin !== url.origin || isDifferentBasename) {
2115
+ if (isBrowser) {
2116
+ let isDocumentReload = false;
2117
+
2118
+ if (redirect.reloadDocument) {
2119
+ // Hard reload if the response contained X-Remix-Reload-Document
2120
+ isDocumentReload = true;
2121
+ } else if (ABSOLUTE_URL_REGEX.test(redirect.location)) {
2122
+ const url = init.history.createURL(redirect.location);
2123
+ isDocumentReload =
2124
+ // Hard reload if it's an absolute URL to a new origin
2125
+ url.origin !== routerWindow.location.origin ||
2126
+ // Hard reload if it's an absolute URL that does not match our basename
2127
+ stripBasename(url.pathname, basename) == null;
2128
+ }
2129
+
2130
+ if (isDocumentReload) {
2120
2131
  if (replace) {
2121
2132
  routerWindow.location.replace(redirect.location);
2122
2133
  } else {
@@ -2789,7 +2800,7 @@ export function createStaticHandler(
2789
2800
  // it to bail out and then return or throw here based on whether the user
2790
2801
  // returned or threw
2791
2802
  if (isQueryRouteResponse(e)) {
2792
- if (e.type === ResultType.error && !isRedirectResponse(e.response)) {
2803
+ if (e.type === ResultType.error) {
2793
2804
  throw e.response;
2794
2805
  }
2795
2806
  return e.response;
@@ -3734,6 +3745,7 @@ async function callLoaderOrAction(
3734
3745
  status,
3735
3746
  location,
3736
3747
  revalidate: result.headers.get("X-Remix-Revalidate") !== null,
3748
+ reloadDocument: result.headers.get("X-Remix-Reload-Document") !== null,
3737
3749
  };
3738
3750
  }
3739
3751
 
@@ -3741,11 +3753,12 @@ async function callLoaderOrAction(
3741
3753
  // without unwrapping. We do this with the QueryRouteResponse wrapper
3742
3754
  // interface so we can know whether it was returned or thrown
3743
3755
  if (opts.isRouteRequest) {
3744
- // eslint-disable-next-line no-throw-literal
3745
- throw {
3746
- type: resultType || ResultType.data,
3756
+ let queryRouteResponse: QueryRouteResponse = {
3757
+ type:
3758
+ resultType === ResultType.error ? ResultType.error : ResultType.data,
3747
3759
  response: result,
3748
3760
  };
3761
+ throw queryRouteResponse;
3749
3762
  }
3750
3763
 
3751
3764
  let data: any;
@@ -4220,7 +4233,7 @@ function isQueryRouteResponse(obj: any): obj is QueryRouteResponse {
4220
4233
  return (
4221
4234
  obj &&
4222
4235
  isResponse(obj.response) &&
4223
- (obj.type === ResultType.data || ResultType.error)
4236
+ (obj.type === ResultType.data || obj.type === ResultType.error)
4224
4237
  );
4225
4238
  }
4226
4239
 
package/utils.ts CHANGED
@@ -43,6 +43,7 @@ export interface RedirectResult {
43
43
  status: number;
44
44
  location: string;
45
45
  revalidate: boolean;
46
+ reloadDocument?: boolean;
46
47
  }
47
48
 
48
49
  /**
@@ -1484,6 +1485,17 @@ export const redirect: RedirectFunction = (url, init = 302) => {
1484
1485
  });
1485
1486
  };
1486
1487
 
1488
+ /**
1489
+ * A redirect response that will force a document reload to the new location.
1490
+ * Sets the status code and the `Location` header.
1491
+ * Defaults to "302 Found".
1492
+ */
1493
+ export const redirectDocument: RedirectFunction = (url, init) => {
1494
+ let response = redirect(url, init);
1495
+ response.headers.set("X-Remix-Reload-Document", "true");
1496
+ return response;
1497
+ };
1498
+
1487
1499
  /**
1488
1500
  * @private
1489
1501
  * Utility class we use to hold auto-unwrapped 4xx/5xx Response bodies