@remix-run/router 1.2.1-pre.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 +11 -5
- 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/CHANGELOG.md
CHANGED
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
# `@remix-run/router`
|
|
2
2
|
|
|
3
|
-
## 1.
|
|
3
|
+
## 1.3.0-pre.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Expose deferred information from createStaticHandler ([#9760](https://github.com/remix-run/react-router/pull/9760))
|
|
4
8
|
|
|
5
9
|
### Patch Changes
|
|
6
10
|
|
|
7
|
-
-
|
|
8
|
-
- Fix
|
|
11
|
+
- Improved absolute redirect url detection in actions/loaders ([#9829](https://github.com/remix-run/react-router/pull/9829))
|
|
12
|
+
- Fix URL creation with memory histories ([#9814](https://github.com/remix-run/react-router/pull/9814))
|
|
13
|
+
- Fix `generatePath` when optional params are present ([#9764](https://github.com/remix-run/react-router/pull/9764))
|
|
9
14
|
|
|
10
|
-
## 1.2.1
|
|
15
|
+
## 1.2.1
|
|
11
16
|
|
|
12
17
|
### Patch Changes
|
|
13
18
|
|
|
14
|
-
- Include submission info in `shouldRevalidate` on action redirects ([#9777](https://github.com/remix-run/react-router/pull/9777))
|
|
19
|
+
- Include submission info in `shouldRevalidate` on action redirects ([#9777](https://github.com/remix-run/react-router/pull/9777), [#9782](https://github.com/remix-run/react-router/pull/9782))
|
|
20
|
+
- Reset `actionData` on action redirect to current location ([#9772](https://github.com/remix-run/react-router/pull/9772))
|
|
15
21
|
|
|
16
22
|
## 1.2.0
|
|
17
23
|
|
package/dist/history.d.ts
CHANGED
|
@@ -106,6 +106,12 @@ export interface History {
|
|
|
106
106
|
* @param to - The destination URL
|
|
107
107
|
*/
|
|
108
108
|
createHref(to: To): string;
|
|
109
|
+
/**
|
|
110
|
+
* Returns a URL for the given `to` value
|
|
111
|
+
*
|
|
112
|
+
* @param to - The destination URL
|
|
113
|
+
*/
|
|
114
|
+
createURL(to: To): URL;
|
|
109
115
|
/**
|
|
110
116
|
* Encode a location the same way window.history would do (no-op for memory
|
|
111
117
|
* history) so we ensure our PUSH/REPLACE navigations for data routers
|
|
@@ -231,7 +237,6 @@ export declare function createPath({ pathname, search, hash, }: Partial<Path>):
|
|
|
231
237
|
* Parses a string URL path into its separate pathname, search, and hash components.
|
|
232
238
|
*/
|
|
233
239
|
export declare function parsePath(path: string): Partial<Path>;
|
|
234
|
-
export declare function createClientSideURL(location: Location | string): URL;
|
|
235
240
|
export interface UrlHistory extends History {
|
|
236
241
|
}
|
|
237
242
|
export declare type UrlHistoryOptions = {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { convertRoutesToDataRoutes, getPathContributingMatches } from "./utils";
|
|
2
1
|
export type { ActionFunction, ActionFunctionArgs, AgnosticDataIndexRouteObject, AgnosticDataNonIndexRouteObject, AgnosticDataRouteMatch, AgnosticDataRouteObject, AgnosticIndexRouteObject, AgnosticNonIndexRouteObject, AgnosticRouteMatch, AgnosticRouteObject, TrackedPromise, FormEncType, FormMethod, JsonFunction, LoaderFunction, LoaderFunctionArgs, ParamParseKey, Params, PathMatch, PathPattern, RedirectFunction, ShouldRevalidateFunction, Submission, } from "./utils";
|
|
3
2
|
export { AbortedDeferredError, ErrorResponse, defer, generatePath, getToPathname, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, redirect, resolvePath, resolveTo, stripBasename, warning, } from "./utils";
|
|
4
3
|
export type { BrowserHistory, BrowserHistoryOptions, HashHistory, HashHistoryOptions, History, InitialEntry, Location, MemoryHistory, MemoryHistoryOptions, Path, To, } from "./history";
|
|
5
4
|
export { Action, createBrowserHistory, createPath, createHashHistory, createMemoryHistory, invariant, parsePath, } from "./history";
|
|
6
5
|
export * from "./router";
|
|
7
6
|
/** @internal */
|
|
8
|
-
export { convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes, getPathContributingMatches as UNSAFE_getPathContributingMatches, };
|
|
7
|
+
export { DeferredData as UNSAFE_DeferredData, convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes, getPathContributingMatches as UNSAFE_getPathContributingMatches, } from "./utils";
|
package/dist/router.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/router v1.
|
|
2
|
+
* @remix-run/router v1.3.0-pre.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -96,6 +96,10 @@ function createMemoryHistory(options) {
|
|
|
96
96
|
return location;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
function createHref(to) {
|
|
100
|
+
return typeof to === "string" ? to : createPath(to);
|
|
101
|
+
}
|
|
102
|
+
|
|
99
103
|
let history = {
|
|
100
104
|
get index() {
|
|
101
105
|
return index;
|
|
@@ -109,8 +113,10 @@ function createMemoryHistory(options) {
|
|
|
109
113
|
return getCurrentLocation();
|
|
110
114
|
},
|
|
111
115
|
|
|
112
|
-
createHref
|
|
113
|
-
|
|
116
|
+
createHref,
|
|
117
|
+
|
|
118
|
+
createURL(to) {
|
|
119
|
+
return new URL(createHref(to), "http://localhost");
|
|
114
120
|
},
|
|
115
121
|
|
|
116
122
|
encodeLocation(to) {
|
|
@@ -389,15 +395,6 @@ function parsePath(path) {
|
|
|
389
395
|
|
|
390
396
|
return parsedPath;
|
|
391
397
|
}
|
|
392
|
-
function createClientSideURL(location) {
|
|
393
|
-
// window.location.origin is "null" (the literal string value) in Firefox
|
|
394
|
-
// under certain conditions, notably when serving from a local HTML file
|
|
395
|
-
// See https://bugzilla.mozilla.org/show_bug.cgi?id=878297
|
|
396
|
-
let base = typeof window !== "undefined" && typeof window.location !== "undefined" && window.location.origin !== "null" ? window.location.origin : window.location.href;
|
|
397
|
-
let href = typeof location === "string" ? location : createPath(location);
|
|
398
|
-
invariant(base, "No window.location.(origin|href) available to create URL for href: " + href);
|
|
399
|
-
return new URL(href, base);
|
|
400
|
-
}
|
|
401
398
|
|
|
402
399
|
function getUrlBasedHistory(getLocation, createHref, validateLocation, options) {
|
|
403
400
|
if (options === void 0) {
|
|
@@ -462,6 +459,16 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
|
|
|
462
459
|
}
|
|
463
460
|
}
|
|
464
461
|
|
|
462
|
+
function createURL(to) {
|
|
463
|
+
// window.location.origin is "null" (the literal string value) in Firefox
|
|
464
|
+
// under certain conditions, notably when serving from a local HTML file
|
|
465
|
+
// See https://bugzilla.mozilla.org/show_bug.cgi?id=878297
|
|
466
|
+
let base = window.location.origin !== "null" ? window.location.origin : window.location.href;
|
|
467
|
+
let href = typeof to === "string" ? to : createPath(to);
|
|
468
|
+
invariant(base, "No window.location.(origin|href) available to create URL for href: " + href);
|
|
469
|
+
return new URL(href, base);
|
|
470
|
+
}
|
|
471
|
+
|
|
465
472
|
let history = {
|
|
466
473
|
get action() {
|
|
467
474
|
return action;
|
|
@@ -488,9 +495,11 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
|
|
|
488
495
|
return createHref(window, to);
|
|
489
496
|
},
|
|
490
497
|
|
|
498
|
+
createURL,
|
|
499
|
+
|
|
491
500
|
encodeLocation(to) {
|
|
492
501
|
// Encode a Location the same way window.location would
|
|
493
|
-
let url =
|
|
502
|
+
let url = createURL(to);
|
|
494
503
|
return {
|
|
495
504
|
pathname: url.pathname,
|
|
496
505
|
search: url.search,
|
|
@@ -807,13 +816,32 @@ function generatePath(originalPath, params) {
|
|
|
807
816
|
path = path.replace(/\*$/, "/*");
|
|
808
817
|
}
|
|
809
818
|
|
|
810
|
-
return path.replace(/^:(\w+)/g, (_, key) => {
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
819
|
+
return path.replace(/^:(\w+)(\??)/g, (_, key, optional) => {
|
|
820
|
+
let param = params[key];
|
|
821
|
+
|
|
822
|
+
if (optional === "?") {
|
|
823
|
+
return param == null ? "" : param;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
if (param == null) {
|
|
827
|
+
invariant(false, "Missing \":" + key + "\" param");
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
return param;
|
|
831
|
+
}).replace(/\/:(\w+)(\??)/g, (_, key, optional) => {
|
|
832
|
+
let param = params[key];
|
|
833
|
+
|
|
834
|
+
if (optional === "?") {
|
|
835
|
+
return param == null ? "" : "/" + param;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
if (param == null) {
|
|
839
|
+
invariant(false, "Missing \":" + key + "\" param");
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
return "/" + param;
|
|
843
|
+
}) // Remove any optional markers from optional static segments
|
|
844
|
+
.replace(/\?/g, "").replace(/(\/?)\*/, (_, prefix, __, str) => {
|
|
817
845
|
const star = "*";
|
|
818
846
|
|
|
819
847
|
if (params[star] == null) {
|
|
@@ -1160,9 +1188,10 @@ const json = function json(data, init) {
|
|
|
1160
1188
|
};
|
|
1161
1189
|
class AbortedDeferredError extends Error {}
|
|
1162
1190
|
class DeferredData {
|
|
1163
|
-
constructor(data) {
|
|
1164
|
-
this.
|
|
1165
|
-
this.
|
|
1191
|
+
constructor(data, responseInit) {
|
|
1192
|
+
this.pendingKeysSet = new Set();
|
|
1193
|
+
this.subscribers = new Set();
|
|
1194
|
+
this.deferredKeys = [];
|
|
1166
1195
|
invariant(data && typeof data === "object" && !Array.isArray(data), "defer() only accepts plain objects"); // Set up an AbortController + Promise we can race against to exit early
|
|
1167
1196
|
// cancellation
|
|
1168
1197
|
|
|
@@ -1181,6 +1210,7 @@ class DeferredData {
|
|
|
1181
1210
|
[key]: this.trackPromise(key, value)
|
|
1182
1211
|
});
|
|
1183
1212
|
}, {});
|
|
1213
|
+
this.init = responseInit;
|
|
1184
1214
|
}
|
|
1185
1215
|
|
|
1186
1216
|
trackPromise(key, value) {
|
|
@@ -1188,7 +1218,8 @@ class DeferredData {
|
|
|
1188
1218
|
return value;
|
|
1189
1219
|
}
|
|
1190
1220
|
|
|
1191
|
-
this.
|
|
1221
|
+
this.deferredKeys.push(key);
|
|
1222
|
+
this.pendingKeysSet.add(key); // We store a little wrapper promise that will be extended with
|
|
1192
1223
|
// _data/_error props upon resolve/reject
|
|
1193
1224
|
|
|
1194
1225
|
let promise = Promise.race([value, this.abortPromise]).then(data => this.onSettle(promise, key, null, data), error => this.onSettle(promise, key, error)); // Register rejection listeners to avoid uncaught promise rejections on
|
|
@@ -1210,39 +1241,41 @@ class DeferredData {
|
|
|
1210
1241
|
return Promise.reject(error);
|
|
1211
1242
|
}
|
|
1212
1243
|
|
|
1213
|
-
this.
|
|
1244
|
+
this.pendingKeysSet.delete(key);
|
|
1214
1245
|
|
|
1215
1246
|
if (this.done) {
|
|
1216
1247
|
// Nothing left to abort!
|
|
1217
1248
|
this.unlistenAbortSignal();
|
|
1218
1249
|
}
|
|
1219
1250
|
|
|
1220
|
-
const subscriber = this.subscriber;
|
|
1221
|
-
|
|
1222
1251
|
if (error) {
|
|
1223
1252
|
Object.defineProperty(promise, "_error", {
|
|
1224
1253
|
get: () => error
|
|
1225
1254
|
});
|
|
1226
|
-
|
|
1255
|
+
this.emit(false, key);
|
|
1227
1256
|
return Promise.reject(error);
|
|
1228
1257
|
}
|
|
1229
1258
|
|
|
1230
1259
|
Object.defineProperty(promise, "_data", {
|
|
1231
1260
|
get: () => data
|
|
1232
1261
|
});
|
|
1233
|
-
|
|
1262
|
+
this.emit(false, key);
|
|
1234
1263
|
return data;
|
|
1235
1264
|
}
|
|
1236
1265
|
|
|
1266
|
+
emit(aborted, settledKey) {
|
|
1267
|
+
this.subscribers.forEach(subscriber => subscriber(aborted, settledKey));
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1237
1270
|
subscribe(fn) {
|
|
1238
|
-
this.
|
|
1271
|
+
this.subscribers.add(fn);
|
|
1272
|
+
return () => this.subscribers.delete(fn);
|
|
1239
1273
|
}
|
|
1240
1274
|
|
|
1241
1275
|
cancel() {
|
|
1242
1276
|
this.controller.abort();
|
|
1243
|
-
this.
|
|
1244
|
-
|
|
1245
|
-
subscriber && subscriber(true);
|
|
1277
|
+
this.pendingKeysSet.forEach((v, k) => this.pendingKeysSet.delete(k));
|
|
1278
|
+
this.emit(true);
|
|
1246
1279
|
}
|
|
1247
1280
|
|
|
1248
1281
|
async resolveData(signal) {
|
|
@@ -1267,7 +1300,7 @@ class DeferredData {
|
|
|
1267
1300
|
}
|
|
1268
1301
|
|
|
1269
1302
|
get done() {
|
|
1270
|
-
return this.
|
|
1303
|
+
return this.pendingKeysSet.size === 0;
|
|
1271
1304
|
}
|
|
1272
1305
|
|
|
1273
1306
|
get unwrappedData() {
|
|
@@ -1280,6 +1313,10 @@ class DeferredData {
|
|
|
1280
1313
|
}, {});
|
|
1281
1314
|
}
|
|
1282
1315
|
|
|
1316
|
+
get pendingKeys() {
|
|
1317
|
+
return Array.from(this.pendingKeysSet);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1283
1320
|
}
|
|
1284
1321
|
|
|
1285
1322
|
function isTrackedPromise(value) {
|
|
@@ -1298,9 +1335,16 @@ function unwrapTrackedPromise(value) {
|
|
|
1298
1335
|
return value._data;
|
|
1299
1336
|
}
|
|
1300
1337
|
|
|
1301
|
-
function defer(data) {
|
|
1302
|
-
|
|
1303
|
-
}
|
|
1338
|
+
const defer = function defer(data, init) {
|
|
1339
|
+
if (init === void 0) {
|
|
1340
|
+
init = {};
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
let responseInit = typeof init === "number" ? {
|
|
1344
|
+
status: init
|
|
1345
|
+
} : init;
|
|
1346
|
+
return new DeferredData(data, responseInit);
|
|
1347
|
+
};
|
|
1304
1348
|
|
|
1305
1349
|
/**
|
|
1306
1350
|
* A redirect response. Sets the status code and the `Location` header.
|
|
@@ -1726,7 +1770,7 @@ function createRouter(init) {
|
|
|
1726
1770
|
|
|
1727
1771
|
|
|
1728
1772
|
pendingNavigationController = new AbortController();
|
|
1729
|
-
let request = createClientSideRequest(location, pendingNavigationController.signal, opts && opts.submission);
|
|
1773
|
+
let request = createClientSideRequest(init.history, location, pendingNavigationController.signal, opts && opts.submission);
|
|
1730
1774
|
let pendingActionData;
|
|
1731
1775
|
let pendingError;
|
|
1732
1776
|
|
|
@@ -1867,7 +1911,9 @@ function createRouter(init) {
|
|
|
1867
1911
|
}
|
|
1868
1912
|
|
|
1869
1913
|
if (isDeferredResult(result)) {
|
|
1870
|
-
throw
|
|
1914
|
+
throw getInternalRouterError(400, {
|
|
1915
|
+
type: "defer-action"
|
|
1916
|
+
});
|
|
1871
1917
|
}
|
|
1872
1918
|
|
|
1873
1919
|
return {
|
|
@@ -1904,7 +1950,7 @@ function createRouter(init) {
|
|
|
1904
1950
|
formData: loadingNavigation.formData,
|
|
1905
1951
|
formEncType: loadingNavigation.formEncType
|
|
1906
1952
|
} : undefined;
|
|
1907
|
-
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(state, matches, activeSubmission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, pendingActionData, pendingError, fetchLoadMatches); // Cancel pending deferreds for no-longer-matched routes or routes we're
|
|
1953
|
+
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, pendingActionData, pendingError, fetchLoadMatches); // Cancel pending deferreds for no-longer-matched routes or routes we're
|
|
1908
1954
|
// about to reload. Note that if this is an action reload we would have
|
|
1909
1955
|
// already cancelled all pending deferreds so this would be a no-op
|
|
1910
1956
|
|
|
@@ -2086,7 +2132,7 @@ function createRouter(init) {
|
|
|
2086
2132
|
}); // Call the action for the fetcher
|
|
2087
2133
|
|
|
2088
2134
|
let abortController = new AbortController();
|
|
2089
|
-
let fetchRequest = createClientSideRequest(path, abortController.signal, submission);
|
|
2135
|
+
let fetchRequest = createClientSideRequest(init.history, path, abortController.signal, submission);
|
|
2090
2136
|
fetchControllers.set(key, abortController);
|
|
2091
2137
|
let actionResult = await callLoaderOrAction("action", fetchRequest, match, requestMatches, router.basename);
|
|
2092
2138
|
|
|
@@ -2127,13 +2173,15 @@ function createRouter(init) {
|
|
|
2127
2173
|
}
|
|
2128
2174
|
|
|
2129
2175
|
if (isDeferredResult(actionResult)) {
|
|
2130
|
-
|
|
2176
|
+
throw getInternalRouterError(400, {
|
|
2177
|
+
type: "defer-action"
|
|
2178
|
+
});
|
|
2131
2179
|
} // Start the data load for current matches, or the next location if we're
|
|
2132
2180
|
// in the middle of a navigation
|
|
2133
2181
|
|
|
2134
2182
|
|
|
2135
2183
|
let nextLocation = state.navigation.location || state.location;
|
|
2136
|
-
let revalidationRequest = createClientSideRequest(nextLocation, abortController.signal);
|
|
2184
|
+
let revalidationRequest = createClientSideRequest(init.history, nextLocation, abortController.signal);
|
|
2137
2185
|
let matches = state.navigation.state !== "idle" ? matchRoutes(dataRoutes, state.navigation.location, init.basename) : state.matches;
|
|
2138
2186
|
invariant(matches, "Didn't find any matches after fetcher action");
|
|
2139
2187
|
let loadId = ++incrementingLoadId;
|
|
@@ -2147,7 +2195,7 @@ function createRouter(init) {
|
|
|
2147
2195
|
});
|
|
2148
2196
|
|
|
2149
2197
|
state.fetchers.set(key, loadFetcher);
|
|
2150
|
-
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, {
|
|
2198
|
+
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, {
|
|
2151
2199
|
[match.route.id]: actionResult.data
|
|
2152
2200
|
}, undefined, // No need to send through errors since we short circuit above
|
|
2153
2201
|
fetchLoadMatches); // Put all revalidating fetchers into the loading state, except for the
|
|
@@ -2260,9 +2308,9 @@ function createRouter(init) {
|
|
|
2260
2308
|
}); // Call the loader for this fetcher route match
|
|
2261
2309
|
|
|
2262
2310
|
let abortController = new AbortController();
|
|
2263
|
-
let fetchRequest = createClientSideRequest(path, abortController.signal);
|
|
2311
|
+
let fetchRequest = createClientSideRequest(init.history, path, abortController.signal);
|
|
2264
2312
|
fetchControllers.set(key, abortController);
|
|
2265
|
-
let result = await callLoaderOrAction("loader", fetchRequest, match, matches, router.basename); // Deferred isn't supported
|
|
2313
|
+
let result = await callLoaderOrAction("loader", fetchRequest, match, matches, router.basename); // Deferred isn't supported for fetcher loads, await everything and treat it
|
|
2266
2314
|
// as a normal load. resolveDeferredData will return undefined if this
|
|
2267
2315
|
// fetcher gets aborted, so we just leave result untouched and short circuit
|
|
2268
2316
|
// below if that happens
|
|
@@ -2362,7 +2410,7 @@ function createRouter(init) {
|
|
|
2362
2410
|
invariant(redirectLocation, "Expected a location on the redirect navigation"); // Check if this an external redirect that goes to a new origin
|
|
2363
2411
|
|
|
2364
2412
|
if (typeof ((_window = window) == null ? void 0 : _window.location) !== "undefined") {
|
|
2365
|
-
let newOrigin =
|
|
2413
|
+
let newOrigin = init.history.createURL(redirect.location).origin;
|
|
2366
2414
|
|
|
2367
2415
|
if (window.location.origin !== newOrigin) {
|
|
2368
2416
|
if (replace) {
|
|
@@ -2428,7 +2476,7 @@ function createRouter(init) {
|
|
|
2428
2476
|
// accordingly
|
|
2429
2477
|
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, router.basename)), ...fetchersToLoad.map(_ref8 => {
|
|
2430
2478
|
let [, href, match, fetchMatches] = _ref8;
|
|
2431
|
-
return callLoaderOrAction("loader", createClientSideRequest(href, request.signal), match, fetchMatches, router.basename);
|
|
2479
|
+
return callLoaderOrAction("loader", createClientSideRequest(init.history, href, request.signal), match, fetchMatches, router.basename);
|
|
2432
2480
|
})]);
|
|
2433
2481
|
let loaderResults = results.slice(0, matchesToLoad.length);
|
|
2434
2482
|
let fetcherResults = results.slice(matchesToLoad.length);
|
|
@@ -2637,6 +2685,7 @@ function createRouter(init) {
|
|
|
2637
2685
|
//#region createStaticHandler
|
|
2638
2686
|
////////////////////////////////////////////////////////////////////////////////
|
|
2639
2687
|
|
|
2688
|
+
const UNSAFE_DEFERRED_SYMBOL = Symbol("deferred");
|
|
2640
2689
|
function createStaticHandler(routes, opts) {
|
|
2641
2690
|
invariant(routes.length > 0, "You must provide a non-empty routes array to createStaticHandler");
|
|
2642
2691
|
let dataRoutes = convertRoutesToDataRoutes(routes);
|
|
@@ -2689,7 +2738,8 @@ function createStaticHandler(routes, opts) {
|
|
|
2689
2738
|
},
|
|
2690
2739
|
statusCode: error.status,
|
|
2691
2740
|
loaderHeaders: {},
|
|
2692
|
-
actionHeaders: {}
|
|
2741
|
+
actionHeaders: {},
|
|
2742
|
+
activeDeferreds: null
|
|
2693
2743
|
};
|
|
2694
2744
|
} else if (!matches) {
|
|
2695
2745
|
let error = getInternalRouterError(404, {
|
|
@@ -2710,7 +2760,8 @@ function createStaticHandler(routes, opts) {
|
|
|
2710
2760
|
},
|
|
2711
2761
|
statusCode: error.status,
|
|
2712
2762
|
loaderHeaders: {},
|
|
2713
|
-
actionHeaders: {}
|
|
2763
|
+
actionHeaders: {},
|
|
2764
|
+
activeDeferreds: null
|
|
2714
2765
|
};
|
|
2715
2766
|
}
|
|
2716
2767
|
|
|
@@ -2801,8 +2852,23 @@ function createStaticHandler(routes, opts) {
|
|
|
2801
2852
|
} // Pick off the right state value to return
|
|
2802
2853
|
|
|
2803
2854
|
|
|
2804
|
-
|
|
2805
|
-
|
|
2855
|
+
if (result.actionData) {
|
|
2856
|
+
return Object.values(result.actionData)[0];
|
|
2857
|
+
}
|
|
2858
|
+
|
|
2859
|
+
if (result.loaderData) {
|
|
2860
|
+
var _result$activeDeferre;
|
|
2861
|
+
|
|
2862
|
+
let data = Object.values(result.loaderData)[0];
|
|
2863
|
+
|
|
2864
|
+
if ((_result$activeDeferre = result.activeDeferreds) != null && _result$activeDeferre[match.route.id]) {
|
|
2865
|
+
data[UNSAFE_DEFERRED_SYMBOL] = result.activeDeferreds[match.route.id];
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2868
|
+
return data;
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2871
|
+
return undefined;
|
|
2806
2872
|
}
|
|
2807
2873
|
|
|
2808
2874
|
async function queryImpl(request, location, matches, requestContext, routeMatch) {
|
|
@@ -2882,7 +2948,18 @@ function createStaticHandler(routes, opts) {
|
|
|
2882
2948
|
}
|
|
2883
2949
|
|
|
2884
2950
|
if (isDeferredResult(result)) {
|
|
2885
|
-
|
|
2951
|
+
let error = getInternalRouterError(400, {
|
|
2952
|
+
type: "defer-action"
|
|
2953
|
+
});
|
|
2954
|
+
|
|
2955
|
+
if (isRouteRequest) {
|
|
2956
|
+
throw error;
|
|
2957
|
+
}
|
|
2958
|
+
|
|
2959
|
+
result = {
|
|
2960
|
+
type: ResultType.error,
|
|
2961
|
+
error
|
|
2962
|
+
};
|
|
2886
2963
|
}
|
|
2887
2964
|
|
|
2888
2965
|
if (isRouteRequest) {
|
|
@@ -2903,7 +2980,8 @@ function createStaticHandler(routes, opts) {
|
|
|
2903
2980
|
// return the raw Response or value
|
|
2904
2981
|
statusCode: 200,
|
|
2905
2982
|
loaderHeaders: {},
|
|
2906
|
-
actionHeaders: {}
|
|
2983
|
+
actionHeaders: {},
|
|
2984
|
+
activeDeferreds: null
|
|
2907
2985
|
};
|
|
2908
2986
|
}
|
|
2909
2987
|
|
|
@@ -2966,7 +3044,8 @@ function createStaticHandler(routes, opts) {
|
|
|
2966
3044
|
}), {}),
|
|
2967
3045
|
errors: pendingActionError || null,
|
|
2968
3046
|
statusCode: 200,
|
|
2969
|
-
loaderHeaders: {}
|
|
3047
|
+
loaderHeaders: {},
|
|
3048
|
+
activeDeferreds: null
|
|
2970
3049
|
};
|
|
2971
3050
|
}
|
|
2972
3051
|
|
|
@@ -2975,27 +3054,21 @@ function createStaticHandler(routes, opts) {
|
|
|
2975
3054
|
if (request.signal.aborted) {
|
|
2976
3055
|
let method = isRouteRequest ? "queryRoute" : "query";
|
|
2977
3056
|
throw new Error(method + "() call aborted");
|
|
2978
|
-
}
|
|
3057
|
+
} // Process and commit output from loaders
|
|
2979
3058
|
|
|
2980
|
-
let executedLoaders = new Set();
|
|
2981
|
-
results.forEach((result, i) => {
|
|
2982
|
-
executedLoaders.add(matchesToLoad[i].route.id); // Can't do anything with these without the Remix side of things, so just
|
|
2983
|
-
// cancel them for now
|
|
2984
3059
|
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
}
|
|
2988
|
-
}); // Process and commit output from loaders
|
|
2989
|
-
|
|
2990
|
-
let context = processRouteLoaderData(matches, matchesToLoad, results, pendingActionError); // Add a null for any non-loader matches for proper revalidation on the client
|
|
3060
|
+
let activeDeferreds = new Map();
|
|
3061
|
+
let context = processRouteLoaderData(matches, matchesToLoad, results, pendingActionError, activeDeferreds); // Add a null for any non-loader matches for proper revalidation on the client
|
|
2991
3062
|
|
|
3063
|
+
let executedLoaders = new Set(matchesToLoad.map(match => match.route.id));
|
|
2992
3064
|
matches.forEach(match => {
|
|
2993
3065
|
if (!executedLoaders.has(match.route.id)) {
|
|
2994
3066
|
context.loaderData[match.route.id] = null;
|
|
2995
3067
|
}
|
|
2996
3068
|
});
|
|
2997
3069
|
return _extends({}, context, {
|
|
2998
|
-
matches
|
|
3070
|
+
matches,
|
|
3071
|
+
activeDeferreds: activeDeferreds.size > 0 ? Object.fromEntries(activeDeferreds.entries()) : null
|
|
2999
3072
|
});
|
|
3000
3073
|
}
|
|
3001
3074
|
|
|
@@ -3114,13 +3187,13 @@ function getLoaderMatchesUntilBoundary(matches, boundaryId) {
|
|
|
3114
3187
|
return boundaryMatches;
|
|
3115
3188
|
}
|
|
3116
3189
|
|
|
3117
|
-
function getMatchesToLoad(state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, pendingActionData, pendingError, fetchLoadMatches) {
|
|
3190
|
+
function getMatchesToLoad(history, state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, pendingActionData, pendingError, fetchLoadMatches) {
|
|
3118
3191
|
let actionResult = pendingError ? Object.values(pendingError)[0] : pendingActionData ? Object.values(pendingActionData)[0] : undefined; // Pick navigation matches that are net-new or qualify for revalidation
|
|
3119
3192
|
|
|
3120
3193
|
let boundaryId = pendingError ? Object.keys(pendingError)[0] : undefined;
|
|
3121
3194
|
let boundaryMatches = getLoaderMatchesUntilBoundary(matches, boundaryId);
|
|
3122
3195
|
let navigationMatches = boundaryMatches.filter((match, index) => match.route.loader != null && (isNewLoader(state.loaderData, state.matches[index], match) || // If this route had a pending deferred cancelled it must be revalidated
|
|
3123
|
-
cancelledDeferredRoutes.some(id => id === match.route.id) || shouldRevalidateLoader(state.location, state.matches[index], submission, location, match, isRevalidationRequired, actionResult))); // Pick fetcher.loads that need to be revalidated
|
|
3196
|
+
cancelledDeferredRoutes.some(id => id === match.route.id) || shouldRevalidateLoader(history, state.location, state.matches[index], submission, location, match, isRevalidationRequired, actionResult))); // Pick fetcher.loads that need to be revalidated
|
|
3124
3197
|
|
|
3125
3198
|
let revalidatingFetchers = [];
|
|
3126
3199
|
fetchLoadMatches && fetchLoadMatches.forEach((_ref10, key) => {
|
|
@@ -3130,7 +3203,7 @@ function getMatchesToLoad(state, matches, submission, location, isRevalidationRe
|
|
|
3130
3203
|
if (cancelledFetcherLoads.includes(key)) {
|
|
3131
3204
|
revalidatingFetchers.push([key, href, match, fetchMatches]);
|
|
3132
3205
|
} else if (isRevalidationRequired) {
|
|
3133
|
-
let shouldRevalidate = shouldRevalidateLoader(href, match, submission, href, match, isRevalidationRequired, actionResult);
|
|
3206
|
+
let shouldRevalidate = shouldRevalidateLoader(history, href, match, submission, href, match, isRevalidationRequired, actionResult);
|
|
3134
3207
|
|
|
3135
3208
|
if (shouldRevalidate) {
|
|
3136
3209
|
revalidatingFetchers.push([key, href, match, fetchMatches]);
|
|
@@ -3160,10 +3233,10 @@ function isNewRouteInstance(currentMatch, match) {
|
|
|
3160
3233
|
);
|
|
3161
3234
|
}
|
|
3162
3235
|
|
|
3163
|
-
function shouldRevalidateLoader(currentLocation, currentMatch, submission, location, match, isRevalidationRequired, actionResult) {
|
|
3164
|
-
let currentUrl =
|
|
3236
|
+
function shouldRevalidateLoader(history, currentLocation, currentMatch, submission, location, match, isRevalidationRequired, actionResult) {
|
|
3237
|
+
let currentUrl = history.createURL(currentLocation);
|
|
3165
3238
|
let currentParams = currentMatch.params;
|
|
3166
|
-
let nextUrl =
|
|
3239
|
+
let nextUrl = history.createURL(location);
|
|
3167
3240
|
let nextParams = match.params; // This is the default implementation as to when we revalidate. If the route
|
|
3168
3241
|
// provides it's own implementation, then we give them full control but
|
|
3169
3242
|
// provide this value so they can leverage it if needed after they check
|
|
@@ -3240,7 +3313,7 @@ async function callLoaderOrAction(type, request, match, matches, basename, isSta
|
|
|
3240
3313
|
if (redirectStatusCodes.has(status)) {
|
|
3241
3314
|
let location = result.headers.get("Location");
|
|
3242
3315
|
invariant(location, "Redirects returned/thrown from loaders/actions must have a Location header");
|
|
3243
|
-
let isAbsolute = /^[a-z
|
|
3316
|
+
let isAbsolute = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(location); // Support relative routing in internal redirects
|
|
3244
3317
|
|
|
3245
3318
|
if (!isAbsolute) {
|
|
3246
3319
|
let activeMatches = matches.slice(0, matches.indexOf(match) + 1);
|
|
@@ -3333,8 +3406,8 @@ async function callLoaderOrAction(type, request, match, matches, basename, isSta
|
|
|
3333
3406
|
// Request instance from the static handler (query/queryRoute)
|
|
3334
3407
|
|
|
3335
3408
|
|
|
3336
|
-
function createClientSideRequest(location, signal, submission) {
|
|
3337
|
-
let url =
|
|
3409
|
+
function createClientSideRequest(history, location, signal, submission) {
|
|
3410
|
+
let url = history.createURL(stripHashFromPath(location)).toString();
|
|
3338
3411
|
let init = {
|
|
3339
3412
|
signal
|
|
3340
3413
|
};
|
|
@@ -3407,13 +3480,16 @@ function processRouteLoaderData(matches, matchesToLoad, results, pendingError, a
|
|
|
3407
3480
|
if (result.headers) {
|
|
3408
3481
|
loaderHeaders[id] = result.headers;
|
|
3409
3482
|
}
|
|
3410
|
-
} else if (isDeferredResult(result)) {
|
|
3411
|
-
activeDeferreds && activeDeferreds.set(id, result.deferredData);
|
|
3412
|
-
loaderData[id] = result.deferredData.data; // TODO: Add statusCode/headers once we wire up streaming in Remix
|
|
3413
3483
|
} else {
|
|
3414
|
-
|
|
3484
|
+
if (isDeferredResult(result)) {
|
|
3485
|
+
activeDeferreds.set(id, result.deferredData);
|
|
3486
|
+
loaderData[id] = result.deferredData.data;
|
|
3487
|
+
} else {
|
|
3488
|
+
loaderData[id] = result.data;
|
|
3489
|
+
} // Error status codes always override success status codes, but if all
|
|
3415
3490
|
// loaders are successful we take the deepest status code.
|
|
3416
3491
|
|
|
3492
|
+
|
|
3417
3493
|
if (result.statusCode != null && result.statusCode !== 200 && !foundError) {
|
|
3418
3494
|
statusCode = result.statusCode;
|
|
3419
3495
|
}
|
|
@@ -3463,11 +3539,11 @@ function processLoaderData(state, matches, matchesToLoad, results, pendingError,
|
|
|
3463
3539
|
} else if (isRedirectResult(result)) {
|
|
3464
3540
|
// Should never get here, redirects should get processed above, but we
|
|
3465
3541
|
// keep this to type narrow to a success result in the else
|
|
3466
|
-
|
|
3542
|
+
invariant(false, "Unhandled fetcher revalidation redirect");
|
|
3467
3543
|
} else if (isDeferredResult(result)) {
|
|
3468
3544
|
// Should never get here, deferred data should be awaited for fetchers
|
|
3469
3545
|
// in resolveDeferredResults
|
|
3470
|
-
|
|
3546
|
+
invariant(false, "Unhandled fetcher deferred data");
|
|
3471
3547
|
} else {
|
|
3472
3548
|
let doneFetcher = {
|
|
3473
3549
|
state: "idle",
|
|
@@ -3539,7 +3615,8 @@ function getInternalRouterError(status, _temp4) {
|
|
|
3539
3615
|
let {
|
|
3540
3616
|
pathname,
|
|
3541
3617
|
routeId,
|
|
3542
|
-
method
|
|
3618
|
+
method,
|
|
3619
|
+
type
|
|
3543
3620
|
} = _temp4 === void 0 ? {} : _temp4;
|
|
3544
3621
|
let statusText = "Unknown Server Error";
|
|
3545
3622
|
let errorMessage = "Unknown @remix-run/router error";
|
|
@@ -3549,6 +3626,8 @@ function getInternalRouterError(status, _temp4) {
|
|
|
3549
3626
|
|
|
3550
3627
|
if (method && pathname && routeId) {
|
|
3551
3628
|
errorMessage = "You made a " + method + " request to \"" + pathname + "\" but " + ("did not provide a `loader` for route \"" + routeId + "\", ") + "so there is no way to handle the request.";
|
|
3629
|
+
} else if (type === "defer-action") {
|
|
3630
|
+
errorMessage = "defer() is not supported in actions";
|
|
3552
3631
|
} else {
|
|
3553
3632
|
errorMessage = "Cannot submit binary form data using GET";
|
|
3554
3633
|
}
|
|
@@ -3722,6 +3801,8 @@ exports.AbortedDeferredError = AbortedDeferredError;
|
|
|
3722
3801
|
exports.ErrorResponse = ErrorResponse;
|
|
3723
3802
|
exports.IDLE_FETCHER = IDLE_FETCHER;
|
|
3724
3803
|
exports.IDLE_NAVIGATION = IDLE_NAVIGATION;
|
|
3804
|
+
exports.UNSAFE_DEFERRED_SYMBOL = UNSAFE_DEFERRED_SYMBOL;
|
|
3805
|
+
exports.UNSAFE_DeferredData = DeferredData;
|
|
3725
3806
|
exports.UNSAFE_convertRoutesToDataRoutes = convertRoutesToDataRoutes;
|
|
3726
3807
|
exports.UNSAFE_getPathContributingMatches = getPathContributingMatches;
|
|
3727
3808
|
exports.createBrowserHistory = createBrowserHistory;
|