@remix-run/router 1.2.1 → 1.3.0-pre.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/CHANGELOG.md +12 -0
- package/dist/history.d.ts +6 -1
- package/dist/index.d.ts +1 -2
- package/dist/router.cjs.js +164 -83
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +2 -0
- package/dist/router.js +163 -84
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +164 -83
- package/dist/router.umd.js.map +1 -1
- package/dist/router.umd.min.js +2 -2
- package/dist/router.umd.min.js.map +1 -1
- package/dist/utils.d.ts +14 -7
- package/history.ts +33 -23
- package/index.ts +3 -3
- package/package.json +1 -1
- package/router.ts +77 -34
- package/utils.ts +88 -42
package/dist/utils.d.ts
CHANGED
|
@@ -26,6 +26,8 @@ export interface SuccessResult {
|
|
|
26
26
|
export interface DeferredResult {
|
|
27
27
|
type: ResultType.deferred;
|
|
28
28
|
deferredData: DeferredData;
|
|
29
|
+
statusCode?: number;
|
|
30
|
+
headers?: Headers;
|
|
29
31
|
}
|
|
30
32
|
/**
|
|
31
33
|
* Redirect result from a loader or action
|
|
@@ -158,7 +160,7 @@ export declare type AgnosticDataNonIndexRouteObject = AgnosticNonIndexRouteObjec
|
|
|
158
160
|
* A data route object, which is just a RouteObject with a required unique ID
|
|
159
161
|
*/
|
|
160
162
|
export declare type AgnosticDataRouteObject = AgnosticDataIndexRouteObject | AgnosticDataNonIndexRouteObject;
|
|
161
|
-
declare type _PathParam<Path extends string> = Path extends `${infer L}/${infer R}` ? _PathParam<L> | _PathParam<R> : Path extends `:${infer Param}` ? Param : never;
|
|
163
|
+
declare type _PathParam<Path extends string> = Path extends `${infer L}/${infer R}` ? _PathParam<L> | _PathParam<R> : Path extends `:${infer Param}` ? Param extends `${infer Optional}?` ? Optional : Param : never;
|
|
162
164
|
/**
|
|
163
165
|
* Examples:
|
|
164
166
|
* "/a/b/*" -> "*"
|
|
@@ -214,7 +216,7 @@ export declare function matchRoutes<RouteObjectType extends AgnosticRouteObject
|
|
|
214
216
|
* @see https://reactrouter.com/utils/generate-path
|
|
215
217
|
*/
|
|
216
218
|
export declare function generatePath<Path extends string>(originalPath: Path, params?: {
|
|
217
|
-
[key in PathParam<Path>]: string;
|
|
219
|
+
[key in PathParam<Path>]: string | null;
|
|
218
220
|
}): string;
|
|
219
221
|
/**
|
|
220
222
|
* A PathPattern is used to match on some portion of a URL pathname.
|
|
@@ -340,22 +342,27 @@ export interface TrackedPromise extends Promise<any> {
|
|
|
340
342
|
export declare class AbortedDeferredError extends Error {
|
|
341
343
|
}
|
|
342
344
|
export declare class DeferredData {
|
|
343
|
-
private
|
|
345
|
+
private pendingKeysSet;
|
|
344
346
|
private controller;
|
|
345
347
|
private abortPromise;
|
|
346
348
|
private unlistenAbortSignal;
|
|
347
|
-
private
|
|
349
|
+
private subscribers;
|
|
348
350
|
data: Record<string, unknown>;
|
|
349
|
-
|
|
351
|
+
init?: ResponseInit;
|
|
352
|
+
deferredKeys: string[];
|
|
353
|
+
constructor(data: Record<string, unknown>, responseInit?: ResponseInit);
|
|
350
354
|
private trackPromise;
|
|
351
355
|
private onSettle;
|
|
352
|
-
|
|
356
|
+
private emit;
|
|
357
|
+
subscribe(fn: (aborted: boolean, settledKey?: string) => void): () => boolean;
|
|
353
358
|
cancel(): void;
|
|
354
359
|
resolveData(signal: AbortSignal): Promise<boolean>;
|
|
355
360
|
get done(): boolean;
|
|
356
361
|
get unwrappedData(): {};
|
|
362
|
+
get pendingKeys(): string[];
|
|
357
363
|
}
|
|
358
|
-
export declare
|
|
364
|
+
export declare type DeferFunction = (data: Record<string, unknown>, init?: number | ResponseInit) => DeferredData;
|
|
365
|
+
export declare const defer: DeferFunction;
|
|
359
366
|
export declare type RedirectFunction = (url: string, init?: number | ResponseInit) => Response;
|
|
360
367
|
/**
|
|
361
368
|
* A redirect response. Sets the status code and the `Location` header.
|
package/history.ts
CHANGED
|
@@ -125,6 +125,13 @@ export interface History {
|
|
|
125
125
|
*/
|
|
126
126
|
createHref(to: To): string;
|
|
127
127
|
|
|
128
|
+
/**
|
|
129
|
+
* Returns a URL for the given `to` value
|
|
130
|
+
*
|
|
131
|
+
* @param to - The destination URL
|
|
132
|
+
*/
|
|
133
|
+
createURL(to: To): URL;
|
|
134
|
+
|
|
128
135
|
/**
|
|
129
136
|
* Encode a location the same way window.history would do (no-op for memory
|
|
130
137
|
* history) so we ensure our PUSH/REPLACE navigations for data routers
|
|
@@ -255,6 +262,10 @@ export function createMemoryHistory(
|
|
|
255
262
|
return location;
|
|
256
263
|
}
|
|
257
264
|
|
|
265
|
+
function createHref(to: To) {
|
|
266
|
+
return typeof to === "string" ? to : createPath(to);
|
|
267
|
+
}
|
|
268
|
+
|
|
258
269
|
let history: MemoryHistory = {
|
|
259
270
|
get index() {
|
|
260
271
|
return index;
|
|
@@ -265,8 +276,9 @@ export function createMemoryHistory(
|
|
|
265
276
|
get location() {
|
|
266
277
|
return getCurrentLocation();
|
|
267
278
|
},
|
|
268
|
-
createHref
|
|
269
|
-
|
|
279
|
+
createHref,
|
|
280
|
+
createURL(to) {
|
|
281
|
+
return new URL(createHref(to), "http://localhost");
|
|
270
282
|
},
|
|
271
283
|
encodeLocation(to: To) {
|
|
272
284
|
let path = typeof to === "string" ? parsePath(to) : to;
|
|
@@ -558,24 +570,6 @@ export function parsePath(path: string): Partial<Path> {
|
|
|
558
570
|
return parsedPath;
|
|
559
571
|
}
|
|
560
572
|
|
|
561
|
-
export function createClientSideURL(location: Location | string): URL {
|
|
562
|
-
// window.location.origin is "null" (the literal string value) in Firefox
|
|
563
|
-
// under certain conditions, notably when serving from a local HTML file
|
|
564
|
-
// See https://bugzilla.mozilla.org/show_bug.cgi?id=878297
|
|
565
|
-
let base =
|
|
566
|
-
typeof window !== "undefined" &&
|
|
567
|
-
typeof window.location !== "undefined" &&
|
|
568
|
-
window.location.origin !== "null"
|
|
569
|
-
? window.location.origin
|
|
570
|
-
: window.location.href;
|
|
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
|
-
);
|
|
576
|
-
return new URL(href, base);
|
|
577
|
-
}
|
|
578
|
-
|
|
579
573
|
export interface UrlHistory extends History {}
|
|
580
574
|
|
|
581
575
|
export type UrlHistoryOptions = {
|
|
@@ -637,6 +631,23 @@ function getUrlBasedHistory(
|
|
|
637
631
|
}
|
|
638
632
|
}
|
|
639
633
|
|
|
634
|
+
function createURL(to: To): URL {
|
|
635
|
+
// window.location.origin is "null" (the literal string value) in Firefox
|
|
636
|
+
// under certain conditions, notably when serving from a local HTML file
|
|
637
|
+
// See https://bugzilla.mozilla.org/show_bug.cgi?id=878297
|
|
638
|
+
let base =
|
|
639
|
+
window.location.origin !== "null"
|
|
640
|
+
? window.location.origin
|
|
641
|
+
: window.location.href;
|
|
642
|
+
|
|
643
|
+
let href = typeof to === "string" ? to : createPath(to);
|
|
644
|
+
invariant(
|
|
645
|
+
base,
|
|
646
|
+
`No window.location.(origin|href) available to create URL for href: ${href}`
|
|
647
|
+
);
|
|
648
|
+
return new URL(href, base);
|
|
649
|
+
}
|
|
650
|
+
|
|
640
651
|
let history: History = {
|
|
641
652
|
get action() {
|
|
642
653
|
return action;
|
|
@@ -659,11 +670,10 @@ function getUrlBasedHistory(
|
|
|
659
670
|
createHref(to) {
|
|
660
671
|
return createHref(window, to);
|
|
661
672
|
},
|
|
673
|
+
createURL,
|
|
662
674
|
encodeLocation(to) {
|
|
663
675
|
// Encode a Location the same way window.location would
|
|
664
|
-
let url =
|
|
665
|
-
typeof to === "string" ? to : createPath(to)
|
|
666
|
-
);
|
|
676
|
+
let url = createURL(to);
|
|
667
677
|
return {
|
|
668
678
|
pathname: url.pathname,
|
|
669
679
|
search: url.search,
|
package/index.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { convertRoutesToDataRoutes, getPathContributingMatches } from "./utils";
|
|
2
|
-
|
|
3
1
|
export type {
|
|
4
2
|
ActionFunction,
|
|
5
3
|
ActionFunctionArgs,
|
|
@@ -58,6 +56,7 @@ export type {
|
|
|
58
56
|
Path,
|
|
59
57
|
To,
|
|
60
58
|
} from "./history";
|
|
59
|
+
|
|
61
60
|
export {
|
|
62
61
|
Action,
|
|
63
62
|
createBrowserHistory,
|
|
@@ -79,6 +78,7 @@ export * from "./router";
|
|
|
79
78
|
|
|
80
79
|
/** @internal */
|
|
81
80
|
export {
|
|
81
|
+
DeferredData as UNSAFE_DeferredData,
|
|
82
82
|
convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes,
|
|
83
83
|
getPathContributingMatches as UNSAFE_getPathContributingMatches,
|
|
84
|
-
};
|
|
84
|
+
} from "./utils";
|
package/package.json
CHANGED
package/router.ts
CHANGED
|
@@ -3,7 +3,6 @@ import {
|
|
|
3
3
|
Action as HistoryAction,
|
|
4
4
|
createLocation,
|
|
5
5
|
createPath,
|
|
6
|
-
createClientSideURL,
|
|
7
6
|
invariant,
|
|
8
7
|
parsePath,
|
|
9
8
|
} from "./history";
|
|
@@ -308,6 +307,7 @@ export interface StaticHandlerContext {
|
|
|
308
307
|
statusCode: number;
|
|
309
308
|
loaderHeaders: Record<string, Headers>;
|
|
310
309
|
actionHeaders: Record<string, Headers>;
|
|
310
|
+
activeDeferreds: Record<string, DeferredData> | null;
|
|
311
311
|
_deepestRenderedBoundaryId?: string | null;
|
|
312
312
|
}
|
|
313
313
|
|
|
@@ -957,6 +957,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
957
957
|
// Create a controller/Request for this navigation
|
|
958
958
|
pendingNavigationController = new AbortController();
|
|
959
959
|
let request = createClientSideRequest(
|
|
960
|
+
init.history,
|
|
960
961
|
location,
|
|
961
962
|
pendingNavigationController.signal,
|
|
962
963
|
opts && opts.submission
|
|
@@ -1115,7 +1116,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1115
1116
|
}
|
|
1116
1117
|
|
|
1117
1118
|
if (isDeferredResult(result)) {
|
|
1118
|
-
throw
|
|
1119
|
+
throw getInternalRouterError(400, { type: "defer-action" });
|
|
1119
1120
|
}
|
|
1120
1121
|
|
|
1121
1122
|
return {
|
|
@@ -1167,6 +1168,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1167
1168
|
: undefined;
|
|
1168
1169
|
|
|
1169
1170
|
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(
|
|
1171
|
+
init.history,
|
|
1170
1172
|
state,
|
|
1171
1173
|
matches,
|
|
1172
1174
|
activeSubmission,
|
|
@@ -1380,6 +1382,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1380
1382
|
// Call the action for the fetcher
|
|
1381
1383
|
let abortController = new AbortController();
|
|
1382
1384
|
let fetchRequest = createClientSideRequest(
|
|
1385
|
+
init.history,
|
|
1383
1386
|
path,
|
|
1384
1387
|
abortController.signal,
|
|
1385
1388
|
submission
|
|
@@ -1427,13 +1430,15 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1427
1430
|
}
|
|
1428
1431
|
|
|
1429
1432
|
if (isDeferredResult(actionResult)) {
|
|
1430
|
-
|
|
1433
|
+
throw getInternalRouterError(400, { type: "defer-action" });
|
|
1431
1434
|
}
|
|
1432
1435
|
|
|
1433
1436
|
// Start the data load for current matches, or the next location if we're
|
|
1434
1437
|
// in the middle of a navigation
|
|
1435
1438
|
let nextLocation = state.navigation.location || state.location;
|
|
1436
1439
|
let revalidationRequest = createClientSideRequest(
|
|
1440
|
+
init.history,
|
|
1441
|
+
|
|
1437
1442
|
nextLocation,
|
|
1438
1443
|
abortController.signal
|
|
1439
1444
|
);
|
|
@@ -1456,6 +1461,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1456
1461
|
state.fetchers.set(key, loadFetcher);
|
|
1457
1462
|
|
|
1458
1463
|
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(
|
|
1464
|
+
init.history,
|
|
1459
1465
|
state,
|
|
1460
1466
|
matches,
|
|
1461
1467
|
submission,
|
|
@@ -1599,7 +1605,11 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1599
1605
|
|
|
1600
1606
|
// Call the loader for this fetcher route match
|
|
1601
1607
|
let abortController = new AbortController();
|
|
1602
|
-
let fetchRequest = createClientSideRequest(
|
|
1608
|
+
let fetchRequest = createClientSideRequest(
|
|
1609
|
+
init.history,
|
|
1610
|
+
path,
|
|
1611
|
+
abortController.signal
|
|
1612
|
+
);
|
|
1603
1613
|
fetchControllers.set(key, abortController);
|
|
1604
1614
|
let result: DataResult = await callLoaderOrAction(
|
|
1605
1615
|
"loader",
|
|
@@ -1609,7 +1619,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1609
1619
|
router.basename
|
|
1610
1620
|
);
|
|
1611
1621
|
|
|
1612
|
-
// Deferred isn't supported
|
|
1622
|
+
// Deferred isn't supported for fetcher loads, await everything and treat it
|
|
1613
1623
|
// as a normal load. resolveDeferredData will return undefined if this
|
|
1614
1624
|
// fetcher gets aborted, so we just leave result untouched and short circuit
|
|
1615
1625
|
// below if that happens
|
|
@@ -1719,7 +1729,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1719
1729
|
|
|
1720
1730
|
// Check if this an external redirect that goes to a new origin
|
|
1721
1731
|
if (typeof window?.location !== "undefined") {
|
|
1722
|
-
let newOrigin =
|
|
1732
|
+
let newOrigin = init.history.createURL(redirect.location).origin;
|
|
1723
1733
|
if (window.location.origin !== newOrigin) {
|
|
1724
1734
|
if (replace) {
|
|
1725
1735
|
window.location.replace(redirect.location);
|
|
@@ -1796,7 +1806,7 @@ export function createRouter(init: RouterInit): Router {
|
|
|
1796
1806
|
...fetchersToLoad.map(([, href, match, fetchMatches]) =>
|
|
1797
1807
|
callLoaderOrAction(
|
|
1798
1808
|
"loader",
|
|
1799
|
-
createClientSideRequest(href, request.signal),
|
|
1809
|
+
createClientSideRequest(init.history, href, request.signal),
|
|
1800
1810
|
match,
|
|
1801
1811
|
fetchMatches,
|
|
1802
1812
|
router.basename
|
|
@@ -2027,6 +2037,8 @@ export function createRouter(init: RouterInit): Router {
|
|
|
2027
2037
|
//#region createStaticHandler
|
|
2028
2038
|
////////////////////////////////////////////////////////////////////////////////
|
|
2029
2039
|
|
|
2040
|
+
export const UNSAFE_DEFERRED_SYMBOL = Symbol("deferred");
|
|
2041
|
+
|
|
2030
2042
|
export function createStaticHandler(
|
|
2031
2043
|
routes: AgnosticRouteObject[],
|
|
2032
2044
|
opts?: {
|
|
@@ -2086,6 +2098,7 @@ export function createStaticHandler(
|
|
|
2086
2098
|
statusCode: error.status,
|
|
2087
2099
|
loaderHeaders: {},
|
|
2088
2100
|
actionHeaders: {},
|
|
2101
|
+
activeDeferreds: null,
|
|
2089
2102
|
};
|
|
2090
2103
|
} else if (!matches) {
|
|
2091
2104
|
let error = getInternalRouterError(404, { pathname: location.pathname });
|
|
@@ -2103,6 +2116,7 @@ export function createStaticHandler(
|
|
|
2103
2116
|
statusCode: error.status,
|
|
2104
2117
|
loaderHeaders: {},
|
|
2105
2118
|
actionHeaders: {},
|
|
2119
|
+
activeDeferreds: null,
|
|
2106
2120
|
};
|
|
2107
2121
|
}
|
|
2108
2122
|
|
|
@@ -2191,8 +2205,19 @@ export function createStaticHandler(
|
|
|
2191
2205
|
}
|
|
2192
2206
|
|
|
2193
2207
|
// Pick off the right state value to return
|
|
2194
|
-
|
|
2195
|
-
|
|
2208
|
+
if (result.actionData) {
|
|
2209
|
+
return Object.values(result.actionData)[0];
|
|
2210
|
+
}
|
|
2211
|
+
|
|
2212
|
+
if (result.loaderData) {
|
|
2213
|
+
let data = Object.values(result.loaderData)[0];
|
|
2214
|
+
if (result.activeDeferreds?.[match.route.id]) {
|
|
2215
|
+
data[UNSAFE_DEFERRED_SYMBOL] = result.activeDeferreds[match.route.id];
|
|
2216
|
+
}
|
|
2217
|
+
return data;
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
return undefined;
|
|
2196
2221
|
}
|
|
2197
2222
|
|
|
2198
2223
|
async function queryImpl(
|
|
@@ -2305,7 +2330,14 @@ export function createStaticHandler(
|
|
|
2305
2330
|
}
|
|
2306
2331
|
|
|
2307
2332
|
if (isDeferredResult(result)) {
|
|
2308
|
-
|
|
2333
|
+
let error = getInternalRouterError(400, { type: "defer-action" });
|
|
2334
|
+
if (isRouteRequest) {
|
|
2335
|
+
throw error;
|
|
2336
|
+
}
|
|
2337
|
+
result = {
|
|
2338
|
+
type: ResultType.error,
|
|
2339
|
+
error,
|
|
2340
|
+
};
|
|
2309
2341
|
}
|
|
2310
2342
|
|
|
2311
2343
|
if (isRouteRequest) {
|
|
@@ -2325,6 +2357,7 @@ export function createStaticHandler(
|
|
|
2325
2357
|
statusCode: 200,
|
|
2326
2358
|
loaderHeaders: {},
|
|
2327
2359
|
actionHeaders: {},
|
|
2360
|
+
activeDeferreds: null,
|
|
2328
2361
|
};
|
|
2329
2362
|
}
|
|
2330
2363
|
|
|
@@ -2420,6 +2453,7 @@ export function createStaticHandler(
|
|
|
2420
2453
|
errors: pendingActionError || null,
|
|
2421
2454
|
statusCode: 200,
|
|
2422
2455
|
loaderHeaders: {},
|
|
2456
|
+
activeDeferreds: null,
|
|
2423
2457
|
};
|
|
2424
2458
|
}
|
|
2425
2459
|
|
|
@@ -2443,25 +2477,20 @@ export function createStaticHandler(
|
|
|
2443
2477
|
throw new Error(`${method}() call aborted`);
|
|
2444
2478
|
}
|
|
2445
2479
|
|
|
2446
|
-
let executedLoaders = new Set<string>();
|
|
2447
|
-
results.forEach((result, i) => {
|
|
2448
|
-
executedLoaders.add(matchesToLoad[i].route.id);
|
|
2449
|
-
// Can't do anything with these without the Remix side of things, so just
|
|
2450
|
-
// cancel them for now
|
|
2451
|
-
if (isDeferredResult(result)) {
|
|
2452
|
-
result.deferredData.cancel();
|
|
2453
|
-
}
|
|
2454
|
-
});
|
|
2455
|
-
|
|
2456
2480
|
// Process and commit output from loaders
|
|
2481
|
+
let activeDeferreds = new Map<string, DeferredData>();
|
|
2457
2482
|
let context = processRouteLoaderData(
|
|
2458
2483
|
matches,
|
|
2459
2484
|
matchesToLoad,
|
|
2460
2485
|
results,
|
|
2461
|
-
pendingActionError
|
|
2486
|
+
pendingActionError,
|
|
2487
|
+
activeDeferreds
|
|
2462
2488
|
);
|
|
2463
2489
|
|
|
2464
2490
|
// Add a null for any non-loader matches for proper revalidation on the client
|
|
2491
|
+
let executedLoaders = new Set<string>(
|
|
2492
|
+
matchesToLoad.map((match) => match.route.id)
|
|
2493
|
+
);
|
|
2465
2494
|
matches.forEach((match) => {
|
|
2466
2495
|
if (!executedLoaders.has(match.route.id)) {
|
|
2467
2496
|
context.loaderData[match.route.id] = null;
|
|
@@ -2471,6 +2500,10 @@ export function createStaticHandler(
|
|
|
2471
2500
|
return {
|
|
2472
2501
|
...context,
|
|
2473
2502
|
matches,
|
|
2503
|
+
activeDeferreds:
|
|
2504
|
+
activeDeferreds.size > 0
|
|
2505
|
+
? Object.fromEntries(activeDeferreds.entries())
|
|
2506
|
+
: null,
|
|
2474
2507
|
};
|
|
2475
2508
|
}
|
|
2476
2509
|
|
|
@@ -2595,6 +2628,7 @@ function getLoaderMatchesUntilBoundary(
|
|
|
2595
2628
|
}
|
|
2596
2629
|
|
|
2597
2630
|
function getMatchesToLoad(
|
|
2631
|
+
history: History,
|
|
2598
2632
|
state: RouterState,
|
|
2599
2633
|
matches: AgnosticDataRouteMatch[],
|
|
2600
2634
|
submission: Submission | undefined,
|
|
@@ -2622,6 +2656,7 @@ function getMatchesToLoad(
|
|
|
2622
2656
|
// If this route had a pending deferred cancelled it must be revalidated
|
|
2623
2657
|
cancelledDeferredRoutes.some((id) => id === match.route.id) ||
|
|
2624
2658
|
shouldRevalidateLoader(
|
|
2659
|
+
history,
|
|
2625
2660
|
state.location,
|
|
2626
2661
|
state.matches[index],
|
|
2627
2662
|
submission,
|
|
@@ -2641,6 +2676,7 @@ function getMatchesToLoad(
|
|
|
2641
2676
|
revalidatingFetchers.push([key, href, match, fetchMatches]);
|
|
2642
2677
|
} else if (isRevalidationRequired) {
|
|
2643
2678
|
let shouldRevalidate = shouldRevalidateLoader(
|
|
2679
|
+
history,
|
|
2644
2680
|
href,
|
|
2645
2681
|
match,
|
|
2646
2682
|
submission,
|
|
@@ -2694,6 +2730,7 @@ function isNewRouteInstance(
|
|
|
2694
2730
|
}
|
|
2695
2731
|
|
|
2696
2732
|
function shouldRevalidateLoader(
|
|
2733
|
+
history: History,
|
|
2697
2734
|
currentLocation: string | Location,
|
|
2698
2735
|
currentMatch: AgnosticDataRouteMatch,
|
|
2699
2736
|
submission: Submission | undefined,
|
|
@@ -2702,9 +2739,9 @@ function shouldRevalidateLoader(
|
|
|
2702
2739
|
isRevalidationRequired: boolean,
|
|
2703
2740
|
actionResult: DataResult | undefined
|
|
2704
2741
|
) {
|
|
2705
|
-
let currentUrl =
|
|
2742
|
+
let currentUrl = history.createURL(currentLocation);
|
|
2706
2743
|
let currentParams = currentMatch.params;
|
|
2707
|
-
let nextUrl =
|
|
2744
|
+
let nextUrl = history.createURL(location);
|
|
2708
2745
|
let nextParams = match.params;
|
|
2709
2746
|
|
|
2710
2747
|
// This is the default implementation as to when we revalidate. If the route
|
|
@@ -2795,8 +2832,7 @@ async function callLoaderOrAction(
|
|
|
2795
2832
|
"Redirects returned/thrown from loaders/actions must have a Location header"
|
|
2796
2833
|
);
|
|
2797
2834
|
|
|
2798
|
-
let isAbsolute =
|
|
2799
|
-
/^[a-z+]+:\/\//i.test(location) || location.startsWith("//");
|
|
2835
|
+
let isAbsolute = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(location);
|
|
2800
2836
|
|
|
2801
2837
|
// Support relative routing in internal redirects
|
|
2802
2838
|
if (!isAbsolute) {
|
|
@@ -2893,11 +2929,12 @@ async function callLoaderOrAction(
|
|
|
2893
2929
|
// client-side navigations and fetches. During SSR we will always have a
|
|
2894
2930
|
// Request instance from the static handler (query/queryRoute)
|
|
2895
2931
|
function createClientSideRequest(
|
|
2932
|
+
history: History,
|
|
2896
2933
|
location: string | Location,
|
|
2897
2934
|
signal: AbortSignal,
|
|
2898
2935
|
submission?: Submission
|
|
2899
2936
|
): Request {
|
|
2900
|
-
let url =
|
|
2937
|
+
let url = history.createURL(stripHashFromPath(location)).toString();
|
|
2901
2938
|
let init: RequestInit = { signal };
|
|
2902
2939
|
|
|
2903
2940
|
if (submission && isMutationMethod(submission.formMethod)) {
|
|
@@ -2933,7 +2970,7 @@ function processRouteLoaderData(
|
|
|
2933
2970
|
matchesToLoad: AgnosticDataRouteMatch[],
|
|
2934
2971
|
results: DataResult[],
|
|
2935
2972
|
pendingError: RouteData | undefined,
|
|
2936
|
-
activeDeferreds
|
|
2973
|
+
activeDeferreds: Map<string, DeferredData>
|
|
2937
2974
|
): {
|
|
2938
2975
|
loaderData: RouterState["loaderData"];
|
|
2939
2976
|
errors: RouterState["errors"] | null;
|
|
@@ -2988,12 +3025,14 @@ function processRouteLoaderData(
|
|
|
2988
3025
|
if (result.headers) {
|
|
2989
3026
|
loaderHeaders[id] = result.headers;
|
|
2990
3027
|
}
|
|
2991
|
-
} else if (isDeferredResult(result)) {
|
|
2992
|
-
activeDeferreds && activeDeferreds.set(id, result.deferredData);
|
|
2993
|
-
loaderData[id] = result.deferredData.data;
|
|
2994
|
-
// TODO: Add statusCode/headers once we wire up streaming in Remix
|
|
2995
3028
|
} else {
|
|
2996
|
-
|
|
3029
|
+
if (isDeferredResult(result)) {
|
|
3030
|
+
activeDeferreds.set(id, result.deferredData);
|
|
3031
|
+
loaderData[id] = result.deferredData.data;
|
|
3032
|
+
} else {
|
|
3033
|
+
loaderData[id] = result.data;
|
|
3034
|
+
}
|
|
3035
|
+
|
|
2997
3036
|
// Error status codes always override success status codes, but if all
|
|
2998
3037
|
// loaders are successful we take the deepest status code.
|
|
2999
3038
|
if (
|
|
@@ -3068,11 +3107,11 @@ function processLoaderData(
|
|
|
3068
3107
|
} else if (isRedirectResult(result)) {
|
|
3069
3108
|
// Should never get here, redirects should get processed above, but we
|
|
3070
3109
|
// keep this to type narrow to a success result in the else
|
|
3071
|
-
|
|
3110
|
+
invariant(false, "Unhandled fetcher revalidation redirect");
|
|
3072
3111
|
} else if (isDeferredResult(result)) {
|
|
3073
3112
|
// Should never get here, deferred data should be awaited for fetchers
|
|
3074
3113
|
// in resolveDeferredResults
|
|
3075
|
-
|
|
3114
|
+
invariant(false, "Unhandled fetcher deferred data");
|
|
3076
3115
|
} else {
|
|
3077
3116
|
let doneFetcher: FetcherStates["Idle"] = {
|
|
3078
3117
|
state: "idle",
|
|
@@ -3163,10 +3202,12 @@ function getInternalRouterError(
|
|
|
3163
3202
|
pathname,
|
|
3164
3203
|
routeId,
|
|
3165
3204
|
method,
|
|
3205
|
+
type,
|
|
3166
3206
|
}: {
|
|
3167
3207
|
pathname?: string;
|
|
3168
3208
|
routeId?: string;
|
|
3169
3209
|
method?: string;
|
|
3210
|
+
type?: "defer-action";
|
|
3170
3211
|
} = {}
|
|
3171
3212
|
) {
|
|
3172
3213
|
let statusText = "Unknown Server Error";
|
|
@@ -3179,6 +3220,8 @@ function getInternalRouterError(
|
|
|
3179
3220
|
`You made a ${method} request to "${pathname}" but ` +
|
|
3180
3221
|
`did not provide a \`loader\` for route "${routeId}", ` +
|
|
3181
3222
|
`so there is no way to handle the request.`;
|
|
3223
|
+
} else if (type === "defer-action") {
|
|
3224
|
+
errorMessage = "defer() is not supported in actions";
|
|
3182
3225
|
} else {
|
|
3183
3226
|
errorMessage = "Cannot submit binary form data using GET";
|
|
3184
3227
|
}
|