Skip to content

Commit d2458f1

Browse files
authored
fix(router): fix URL creation in Cloudflare Pages (#9682)
* fix URL creation in cloudflare pages * Remove fallback url origin in favor of invariant * Fallback on window.location.href for firefox * Bump bundle * doh
1 parent ef6bce6 commit d2458f1

File tree

6 files changed

+62
-39
lines changed

6 files changed

+62
-39
lines changed

.changeset/new-kiwis-confess.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@remix-run/router": patch
3+
---
4+
5+
Fix URL creation in Cloudflare Pages or other non-browser-environment

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@
107107
},
108108
"filesize": {
109109
"packages/router/dist/router.umd.min.js": {
110-
"none": "35 kB"
110+
"none": "35.5 kB"
111111
},
112112
"packages/react-router/dist/react-router.production.min.js": {
113113
"none": "12.5 kB"

packages/router/history.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,20 @@ export function createHashHistory(
447447
//#region UTILS
448448
////////////////////////////////////////////////////////////////////////////////
449449

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+
450464
function warning(cond: any, message: string) {
451465
if (!cond) {
452466
// eslint-disable-next-line no-console
@@ -544,7 +558,7 @@ export function parsePath(path: string): Partial<Path> {
544558
return parsedPath;
545559
}
546560

547-
export function createURL(location: Location | string): URL {
561+
export function createClientSideURL(location: Location | string): URL {
548562
// window.location.origin is "null" (the literal string value) in Firefox
549563
// under certain conditions, notably when serving from a local HTML file
550564
// See https://bugzilla.mozilla.org/show_bug.cgi?id=878297
@@ -553,8 +567,12 @@ export function createURL(location: Location | string): URL {
553567
typeof window.location !== "undefined" &&
554568
window.location.origin !== "null"
555569
? window.location.origin
556-
: "unknown://unknown";
570+
: window.location.href;
557571
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+
);
558576
return new URL(href, base);
559577
}
560578

@@ -643,7 +661,9 @@ function getUrlBasedHistory(
643661
},
644662
encodeLocation(to) {
645663
// 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+
);
647667
return {
648668
pathname: url.pathname,
649669
search: url.search,

packages/router/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ export {
3232
defer,
3333
generatePath,
3434
getToPathname,
35-
invariant,
3635
isRouteErrorResponse,
3736
joinPaths,
3837
json,
@@ -59,13 +58,13 @@ export type {
5958
Path,
6059
To,
6160
} from "./history";
62-
6361
export {
6462
Action,
6563
createBrowserHistory,
6664
createPath,
6765
createHashHistory,
6866
createMemoryHistory,
67+
invariant,
6968
parsePath,
7069
} from "./history";
7170

packages/router/router.ts

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import {
33
Action as HistoryAction,
44
createLocation,
55
createPath,
6-
createURL,
6+
createClientSideURL,
7+
invariant,
78
parsePath,
89
} from "./history";
910
import type {
@@ -28,7 +29,6 @@ import {
2829
ResultType,
2930
convertRoutesToDataRoutes,
3031
getPathContributingMatches,
31-
invariant,
3232
isRouteErrorResponse,
3333
joinPaths,
3434
matchRoutes,
@@ -913,7 +913,7 @@ export function createRouter(init: RouterInit): Router {
913913

914914
// Create a controller/Request for this navigation
915915
pendingNavigationController = new AbortController();
916-
let request = createRequest(
916+
let request = createClientSideRequest(
917917
location,
918918
pendingNavigationController.signal,
919919
opts && opts.submission
@@ -954,7 +954,7 @@ export function createRouter(init: RouterInit): Router {
954954
loadingNavigation = navigation;
955955

956956
// Create a GET request for the loaders
957-
request = createRequest(request.url, request.signal);
957+
request = new Request(request.url, { signal: request.signal });
958958
}
959959

960960
// Call loaders
@@ -1299,7 +1299,11 @@ export function createRouter(init: RouterInit): Router {
12991299

13001300
// Call the action for the fetcher
13011301
let abortController = new AbortController();
1302-
let fetchRequest = createRequest(path, abortController.signal, submission);
1302+
let fetchRequest = createClientSideRequest(
1303+
path,
1304+
abortController.signal,
1305+
submission
1306+
);
13031307
fetchControllers.set(key, abortController);
13041308

13051309
let actionResult = await callLoaderOrAction(
@@ -1346,7 +1350,7 @@ export function createRouter(init: RouterInit): Router {
13461350
// Start the data load for current matches, or the next location if we're
13471351
// in the middle of a navigation
13481352
let nextLocation = state.navigation.location || state.location;
1349-
let revalidationRequest = createRequest(
1353+
let revalidationRequest = createClientSideRequest(
13501354
nextLocation,
13511355
abortController.signal
13521356
);
@@ -1501,7 +1505,7 @@ export function createRouter(init: RouterInit): Router {
15011505

15021506
// Call the loader for this fetcher route match
15031507
let abortController = new AbortController();
1504-
let fetchRequest = createRequest(path, abortController.signal);
1508+
let fetchRequest = createClientSideRequest(path, abortController.signal);
15051509
fetchControllers.set(key, abortController);
15061510
let result: DataResult = await callLoaderOrAction(
15071511
"loader",
@@ -1675,7 +1679,7 @@ export function createRouter(init: RouterInit): Router {
16751679
...fetchersToLoad.map(([, href, match, fetchMatches]) =>
16761680
callLoaderOrAction(
16771681
"loader",
1678-
createRequest(href, request.signal),
1682+
createClientSideRequest(href, request.signal),
16791683
match,
16801684
fetchMatches,
16811685
router.basename
@@ -2120,7 +2124,7 @@ export function unstable_createStaticHandler(
21202124
if (!actionMatch.route.action) {
21212125
let error = getInternalRouterError(405, {
21222126
method: request.method,
2123-
pathname: createURL(request.url).pathname,
2127+
pathname: new URL(request.url).pathname,
21242128
routeId: actionMatch.route.id,
21252129
});
21262130
if (isRouteRequest) {
@@ -2206,7 +2210,7 @@ export function unstable_createStaticHandler(
22062210
}
22072211

22082212
// Create a GET request for the loaders
2209-
let loaderRequest = createRequest(request.url, request.signal);
2213+
let loaderRequest = new Request(request.url, { signal: request.signal });
22102214
let context = await loadRouteData(loaderRequest, matches);
22112215

22122216
return {
@@ -2240,7 +2244,7 @@ export function unstable_createStaticHandler(
22402244
if (isRouteRequest && !routeMatch?.route.loader) {
22412245
throw getInternalRouterError(400, {
22422246
method: request.method,
2243-
pathname: createURL(request.url).pathname,
2247+
pathname: new URL(request.url).pathname,
22442248
routeId: routeMatch?.route.id,
22452249
});
22462250
}
@@ -2531,9 +2535,9 @@ function shouldRevalidateLoader(
25312535
isRevalidationRequired: boolean,
25322536
actionResult: DataResult | undefined
25332537
) {
2534-
let currentUrl = createURL(currentLocation);
2538+
let currentUrl = createClientSideURL(currentLocation);
25352539
let currentParams = currentMatch.params;
2536-
let nextUrl = createURL(location);
2540+
let nextUrl = createClientSideURL(location);
25372541
let nextParams = match.params;
25382542

25392543
// This is the default implementation as to when we revalidate. If the route
@@ -2624,16 +2628,22 @@ async function callLoaderOrAction(
26242628
);
26252629

26262630
// Check if this an external redirect that goes to a new origin
2627-
let external = createURL(location).origin !== createURL("/").origin;
2631+
let currentUrl = new URL(request.url);
2632+
let currentOrigin = currentUrl.origin;
2633+
let newOrigin = new URL(location, currentOrigin).origin;
2634+
let external = newOrigin !== currentOrigin;
26282635

26292636
// Support relative routing in internal redirects
26302637
if (!external) {
26312638
let activeMatches = matches.slice(0, matches.indexOf(match) + 1);
26322639
let routePathnames = getPathContributingMatches(activeMatches).map(
26332640
(match) => match.pathnameBase
26342641
);
2635-
let requestPath = createURL(request.url).pathname;
2636-
let resolvedLocation = resolveTo(location, routePathnames, requestPath);
2642+
let resolvedLocation = resolveTo(
2643+
location,
2644+
routePathnames,
2645+
currentUrl.pathname
2646+
);
26372647
invariant(
26382648
createPath(resolvedLocation),
26392649
`Unable to resolve redirect location: ${location}`
@@ -2713,12 +2723,15 @@ async function callLoaderOrAction(
27132723
return { type: ResultType.data, data: result };
27142724
}
27152725

2716-
function createRequest(
2726+
// Utility method for creating the Request instances for loaders/actions during
2727+
// client-side navigations and fetches. During SSR we will always have a
2728+
// Request instance from the static handler (query/queryRoute)
2729+
function createClientSideRequest(
27172730
location: string | Location,
27182731
signal: AbortSignal,
27192732
submission?: Submission
27202733
): Request {
2721-
let url = createURL(stripHashFromPath(location)).toString();
2734+
let url = createClientSideURL(stripHashFromPath(location)).toString();
27222735
let init: RequestInit = { signal };
27232736

27242737
if (submission) {

packages/router/utils.ts

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Location, Path, To } from "./history";
2-
import { parsePath } from "./history";
2+
import { invariant, parsePath } from "./history";
33

44
/**
55
* Map of routeId -> data returned from a loader/action/error
@@ -771,20 +771,6 @@ export function stripBasename(
771771
return pathname.slice(startIndex) || "/";
772772
}
773773

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-
788774
/**
789775
* @private
790776
*/

0 commit comments

Comments
 (0)