@tanstack/react-router 0.0.1-beta.272 → 0.0.1-beta.274
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/build/cjs/Matches.js.map +1 -1
- package/build/cjs/RouterProvider.js +14 -9
- package/build/cjs/RouterProvider.js.map +1 -1
- package/build/cjs/index.js +4 -1
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/route.js.map +1 -1
- package/build/cjs/router.js +150 -100
- package/build/cjs/router.js.map +1 -1
- package/build/esm/index.js +162 -106
- package/build/esm/index.js.map +1 -1
- package/build/stats-html.html +1 -1
- package/build/stats-react.json +353 -353
- package/build/types/Matches.d.ts +2 -2
- package/build/types/RouterProvider.d.ts +1 -1
- package/build/types/route.d.ts +2 -2
- package/build/types/router.d.ts +3 -1
- package/build/umd/index.development.js +164 -109
- package/build/umd/index.development.js.map +1 -1
- package/build/umd/index.production.js +1 -1
- package/build/umd/index.production.js.map +1 -1
- package/package.json +2 -2
- package/src/Matches.tsx +2 -2
- package/src/RouterProvider.tsx +18 -10
- package/src/route.ts +2 -2
- package/src/router.ts +197 -128
package/build/esm/index.js
CHANGED
|
@@ -472,9 +472,13 @@ function useLoaderData(opts) {
|
|
|
472
472
|
});
|
|
473
473
|
}
|
|
474
474
|
|
|
475
|
-
|
|
475
|
+
let routerContext = /*#__PURE__*/React.createContext(null);
|
|
476
476
|
if (typeof document !== 'undefined') {
|
|
477
|
-
window.__TSR_ROUTER_CONTEXT__
|
|
477
|
+
if (window.__TSR_ROUTER_CONTEXT__) {
|
|
478
|
+
routerContext = window.__TSR_ROUTER_CONTEXT__;
|
|
479
|
+
} else {
|
|
480
|
+
window.__TSR_ROUTER_CONTEXT__ = routerContext;
|
|
481
|
+
}
|
|
478
482
|
}
|
|
479
483
|
function RouterProvider({
|
|
480
484
|
router,
|
|
@@ -561,9 +565,11 @@ function Transitioner() {
|
|
|
561
565
|
pathChanged: routerState.location.href !== routerState.resolvedLocation?.href
|
|
562
566
|
});
|
|
563
567
|
if (document.querySelector) {
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
el
|
|
568
|
+
if (routerState.location.hash !== '') {
|
|
569
|
+
const el = document.getElementById(routerState.location.hash);
|
|
570
|
+
if (el) {
|
|
571
|
+
el.scrollIntoView();
|
|
572
|
+
}
|
|
567
573
|
}
|
|
568
574
|
}
|
|
569
575
|
router.pendingMatches = [];
|
|
@@ -582,7 +588,7 @@ function Transitioner() {
|
|
|
582
588
|
return null;
|
|
583
589
|
}
|
|
584
590
|
function getRouteMatch(state, id) {
|
|
585
|
-
return [...(state.pendingMatches ?? []), ...state.matches].find(d => d.id === id);
|
|
591
|
+
return [...state.preloadMatches, ...(state.pendingMatches ?? []), ...state.matches].find(d => d.id === id);
|
|
586
592
|
}
|
|
587
593
|
function useRouterState(opts) {
|
|
588
594
|
const router = useRouter();
|
|
@@ -1686,7 +1692,7 @@ class Router {
|
|
|
1686
1692
|
context: undefined,
|
|
1687
1693
|
abortController: new AbortController(),
|
|
1688
1694
|
shouldReloadDeps: undefined,
|
|
1689
|
-
|
|
1695
|
+
fetchCount: 0,
|
|
1690
1696
|
cause
|
|
1691
1697
|
};
|
|
1692
1698
|
|
|
@@ -1895,10 +1901,13 @@ class Router {
|
|
|
1895
1901
|
}) => {
|
|
1896
1902
|
let latestPromise;
|
|
1897
1903
|
let firstBadMatchIndex;
|
|
1898
|
-
const
|
|
1904
|
+
const updateMatch = match => {
|
|
1905
|
+
const isPreload = this.state.preloadMatches.find(d => d.id === match.id);
|
|
1906
|
+
const isPending = this.state.pendingMatches?.find(d => d.id === match.id);
|
|
1907
|
+
const matchesKey = isPreload ? 'preloadMatches' : isPending ? 'pendingMatches' : 'matches';
|
|
1899
1908
|
this.__store.setState(s => ({
|
|
1900
1909
|
...s,
|
|
1901
|
-
|
|
1910
|
+
[matchesKey]: s[matchesKey]?.map(d => d.id === match.id ? match : d)
|
|
1902
1911
|
}));
|
|
1903
1912
|
};
|
|
1904
1913
|
|
|
@@ -1951,7 +1960,7 @@ class Router {
|
|
|
1951
1960
|
from: match.pathname
|
|
1952
1961
|
}),
|
|
1953
1962
|
buildLocation: this.buildLocation,
|
|
1954
|
-
cause: match.cause
|
|
1963
|
+
cause: preload ? 'preload' : match.cause
|
|
1955
1964
|
})) ?? {};
|
|
1956
1965
|
if (isRedirect(beforeLoadContext)) {
|
|
1957
1966
|
throw beforeLoadContext;
|
|
@@ -1981,7 +1990,7 @@ class Router {
|
|
|
1981
1990
|
const validResolvedMatches = matches.slice(0, firstBadMatchIndex);
|
|
1982
1991
|
const matchPromises = [];
|
|
1983
1992
|
validResolvedMatches.forEach((match, index) => {
|
|
1984
|
-
matchPromises.push((async
|
|
1993
|
+
matchPromises.push(new Promise(async resolve => {
|
|
1985
1994
|
const parentMatchPromise = matchPromises[index - 1];
|
|
1986
1995
|
const route = this.looseRoutesById[match.routeId];
|
|
1987
1996
|
const handleErrorAndRedirect = err => {
|
|
@@ -1996,92 +2005,95 @@ class Router {
|
|
|
1996
2005
|
let loadPromise;
|
|
1997
2006
|
matches[index] = match = {
|
|
1998
2007
|
...match,
|
|
1999
|
-
fetchedAt: Date.now(),
|
|
2000
2008
|
showPending: false
|
|
2001
2009
|
};
|
|
2010
|
+
let didShowPending = false;
|
|
2002
2011
|
const pendingMs = route.options.pendingMs ?? this.options.defaultPendingMs;
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
};
|
|
2012
|
+
const pendingMinMs = route.options.pendingMinMs ?? this.options.defaultPendingMinMs;
|
|
2013
|
+
const shouldPending = !preload && pendingMs && (route.options.pendingComponent ?? this.options.defaultPendingComponent);
|
|
2014
|
+
const fetch = async () => {
|
|
2015
|
+
if (match.isFetching) {
|
|
2016
|
+
loadPromise = getRouteMatch(this.state, match.id)?.loadPromise;
|
|
2017
|
+
} else {
|
|
2018
|
+
const loaderContext = {
|
|
2019
|
+
params: match.params,
|
|
2020
|
+
search: match.search,
|
|
2021
|
+
preload: !!preload,
|
|
2022
|
+
parentMatchPromise,
|
|
2023
|
+
abortController: match.abortController,
|
|
2024
|
+
context: match.context,
|
|
2025
|
+
location: this.state.location,
|
|
2026
|
+
navigate: opts => this.navigate({
|
|
2027
|
+
...opts,
|
|
2028
|
+
from: match.pathname
|
|
2029
|
+
}),
|
|
2030
|
+
cause: preload ? 'preload' : match.cause
|
|
2031
|
+
};
|
|
2024
2032
|
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2033
|
+
// Default to reloading the route all the time
|
|
2034
|
+
let shouldLoad = true;
|
|
2035
|
+
const shouldReloadFn = route.options.shouldReload;
|
|
2036
|
+
let shouldReloadDeps = typeof shouldReloadFn === 'function' ? shouldReloadFn(loaderContext) : !!(shouldReloadFn ?? true);
|
|
2037
|
+
const compareDeps = () => {
|
|
2038
|
+
if (typeof shouldReloadDeps === 'object') {
|
|
2039
|
+
// compare the deps to see if they've changed
|
|
2040
|
+
shouldLoad = !deepEqual(shouldReloadDeps, match.shouldReloadDeps);
|
|
2041
|
+
} else {
|
|
2042
|
+
shouldLoad = !!shouldReloadDeps;
|
|
2043
|
+
}
|
|
2044
|
+
};
|
|
2045
|
+
|
|
2046
|
+
// If it's the first preload, or the route is entering, or we're
|
|
2047
|
+
// invalidating, we definitely need to load the route
|
|
2048
|
+
if (invalidate) ; else if (preload) {
|
|
2049
|
+
if (!match.fetchCount) ; else {
|
|
2050
|
+
compareDeps();
|
|
2051
|
+
}
|
|
2052
|
+
} else if (match.cause === 'enter') {
|
|
2053
|
+
if (!match.fetchCount) ; else {
|
|
2054
|
+
compareDeps();
|
|
2055
|
+
}
|
|
2035
2056
|
} else {
|
|
2036
|
-
|
|
2057
|
+
compareDeps();
|
|
2058
|
+
}
|
|
2059
|
+
if (typeof shouldReloadDeps === 'object') {
|
|
2060
|
+
matches[index] = match = {
|
|
2061
|
+
...match,
|
|
2062
|
+
shouldReloadDeps
|
|
2063
|
+
};
|
|
2037
2064
|
}
|
|
2038
|
-
}
|
|
2039
2065
|
|
|
2040
|
-
|
|
2041
|
-
|
|
2066
|
+
// If the user doesn't want the route to reload, just
|
|
2067
|
+
// resolve with the existing loader data
|
|
2042
2068
|
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
...match,
|
|
2049
|
-
isFetching: true
|
|
2050
|
-
};
|
|
2051
|
-
const componentsPromise = Promise.all(componentTypes.map(async type => {
|
|
2052
|
-
const component = route.options[type];
|
|
2053
|
-
if (component?.preload) {
|
|
2054
|
-
await component.preload();
|
|
2069
|
+
if (!shouldLoad) {
|
|
2070
|
+
loadPromise = Promise.resolve(match.loaderData);
|
|
2071
|
+
} else {
|
|
2072
|
+
if (match.fetchCount && match.status === 'success') {
|
|
2073
|
+
resolve();
|
|
2055
2074
|
}
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
loadPromise = Promise.all([componentsPromise, loaderPromise]).then(d => d[1]);
|
|
2059
|
-
}
|
|
2060
|
-
}
|
|
2061
|
-
matches[index] = match = {
|
|
2062
|
-
...match,
|
|
2063
|
-
loadPromise
|
|
2064
|
-
};
|
|
2065
|
-
if (!preload) {
|
|
2066
|
-
updatePendingMatch(match);
|
|
2067
|
-
}
|
|
2068
|
-
let didShowPending = false;
|
|
2069
|
-
const pendingMinMs = route.options.pendingMinMs ?? this.options.defaultPendingMinMs;
|
|
2070
|
-
await new Promise(async resolve => {
|
|
2071
|
-
// If the route has a pending component and a pendingMs option,
|
|
2072
|
-
// forcefully show the pending component
|
|
2073
|
-
if (pendingPromise) {
|
|
2074
|
-
pendingPromise.then(() => {
|
|
2075
|
-
if (latestPromise = checkLatest()) return;
|
|
2076
|
-
didShowPending = true;
|
|
2075
|
+
|
|
2076
|
+
// Otherwise, load the route
|
|
2077
2077
|
matches[index] = match = {
|
|
2078
2078
|
...match,
|
|
2079
|
-
|
|
2079
|
+
isFetching: true,
|
|
2080
|
+
fetchCount: match.fetchCount + 1
|
|
2080
2081
|
};
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2082
|
+
const componentsPromise = Promise.all(componentTypes.map(async type => {
|
|
2083
|
+
const component = route.options[type];
|
|
2084
|
+
if (component?.preload) {
|
|
2085
|
+
await component.preload();
|
|
2086
|
+
}
|
|
2087
|
+
}));
|
|
2088
|
+
const loaderPromise = route.options.loader?.(loaderContext);
|
|
2089
|
+
loadPromise = Promise.all([componentsPromise, loaderPromise]).then(d => d[1]);
|
|
2090
|
+
}
|
|
2084
2091
|
}
|
|
2092
|
+
matches[index] = match = {
|
|
2093
|
+
...match,
|
|
2094
|
+
loadPromise
|
|
2095
|
+
};
|
|
2096
|
+
updateMatch(match);
|
|
2085
2097
|
try {
|
|
2086
2098
|
const loaderData = await loadPromise;
|
|
2087
2099
|
if (latestPromise = checkLatest()) return await latestPromise;
|
|
@@ -2122,18 +2134,38 @@ class Router {
|
|
|
2122
2134
|
// we already moved the pendingMatches to the matches
|
|
2123
2135
|
// state, so we need to update that specific match
|
|
2124
2136
|
if (didShowPending && pendingMinMs && match.showPending) {
|
|
2125
|
-
|
|
2126
|
-
...s,
|
|
2127
|
-
matches: s.matches?.map(d => d.id === match.id ? match : d)
|
|
2128
|
-
}));
|
|
2137
|
+
updateMatch(match);
|
|
2129
2138
|
}
|
|
2130
2139
|
}
|
|
2131
|
-
|
|
2132
|
-
|
|
2140
|
+
updateMatch(match);
|
|
2141
|
+
};
|
|
2142
|
+
if (match.fetchCount && match.status === 'success') {
|
|
2143
|
+
// Background Fetching
|
|
2144
|
+
fetch();
|
|
2145
|
+
} else {
|
|
2146
|
+
// Critical Fetching
|
|
2147
|
+
|
|
2148
|
+
// If we need to potentially show the pending component,
|
|
2149
|
+
// start a timer to show it after the pendingMs
|
|
2150
|
+
if (shouldPending) {
|
|
2151
|
+
new Promise(r => setTimeout(r, pendingMs)).then(async () => {
|
|
2152
|
+
if (latestPromise = checkLatest()) return latestPromise;
|
|
2153
|
+
didShowPending = true;
|
|
2154
|
+
matches[index] = match = {
|
|
2155
|
+
...match,
|
|
2156
|
+
showPending: true
|
|
2157
|
+
};
|
|
2158
|
+
updateMatch(match);
|
|
2159
|
+
resolve();
|
|
2160
|
+
});
|
|
2133
2161
|
}
|
|
2134
|
-
|
|
2135
|
-
}
|
|
2136
|
-
|
|
2162
|
+
await fetch();
|
|
2163
|
+
}
|
|
2164
|
+
resolve();
|
|
2165
|
+
// No Fetching
|
|
2166
|
+
|
|
2167
|
+
resolve();
|
|
2168
|
+
}));
|
|
2137
2169
|
});
|
|
2138
2170
|
await Promise.all(matchPromises);
|
|
2139
2171
|
return matches;
|
|
@@ -2156,20 +2188,32 @@ class Router {
|
|
|
2156
2188
|
toLocation: next,
|
|
2157
2189
|
pathChanged: pathDidChange
|
|
2158
2190
|
});
|
|
2159
|
-
|
|
2160
|
-
// Match the routes
|
|
2161
|
-
let pendingMatches = this.matchRoutes(next.pathname, next.search, {
|
|
2162
|
-
debug: true
|
|
2163
|
-
});
|
|
2191
|
+
let pendingMatches;
|
|
2164
2192
|
const previousMatches = this.state.matches;
|
|
2193
|
+
this.__store.batch(() => {
|
|
2194
|
+
this.__store.setState(s => ({
|
|
2195
|
+
...s,
|
|
2196
|
+
preloadMatches: s.preloadMatches.filter(d => {
|
|
2197
|
+
return Date.now() - d.updatedAt < (this.options.defaultPreloadMaxAge ?? 3000);
|
|
2198
|
+
})
|
|
2199
|
+
}));
|
|
2165
2200
|
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2201
|
+
// Match the routes
|
|
2202
|
+
pendingMatches = this.matchRoutes(next.pathname, next.search, {
|
|
2203
|
+
debug: true
|
|
2204
|
+
});
|
|
2205
|
+
|
|
2206
|
+
// Ingest the new matches
|
|
2207
|
+
this.__store.setState(s => ({
|
|
2208
|
+
...s,
|
|
2209
|
+
isLoading: true,
|
|
2210
|
+
location: next,
|
|
2211
|
+
pendingMatches,
|
|
2212
|
+
preloadMatches: s.preloadMatches.filter(d => {
|
|
2213
|
+
return !pendingMatches.find(e => e.id === d.id);
|
|
2214
|
+
})
|
|
2215
|
+
}));
|
|
2216
|
+
});
|
|
2173
2217
|
try {
|
|
2174
2218
|
try {
|
|
2175
2219
|
// Load the matches
|
|
@@ -2227,6 +2271,17 @@ class Router {
|
|
|
2227
2271
|
let matches = this.matchRoutes(next.pathname, next.search, {
|
|
2228
2272
|
throwOnError: true
|
|
2229
2273
|
});
|
|
2274
|
+
const loadedMatchIds = Object.fromEntries([...this.state.matches, ...(this.state.pendingMatches ?? []), ...this.state.preloadMatches]?.map(d => [d.id, true]));
|
|
2275
|
+
this.__store.batch(() => {
|
|
2276
|
+
matches.forEach(match => {
|
|
2277
|
+
if (!loadedMatchIds[match.id]) {
|
|
2278
|
+
this.__store.setState(s => ({
|
|
2279
|
+
...s,
|
|
2280
|
+
preloadMatches: [...s.preloadMatches, match]
|
|
2281
|
+
}));
|
|
2282
|
+
}
|
|
2283
|
+
});
|
|
2284
|
+
});
|
|
2230
2285
|
matches = await this.loadMatches({
|
|
2231
2286
|
matches,
|
|
2232
2287
|
preload: true,
|
|
@@ -2289,7 +2344,7 @@ class Router {
|
|
|
2289
2344
|
dehydrate = () => {
|
|
2290
2345
|
return {
|
|
2291
2346
|
state: {
|
|
2292
|
-
dehydratedMatches: this.state.matches.map(d => pick(d, ['
|
|
2347
|
+
dehydratedMatches: this.state.matches.map(d => pick(d, ['id', 'status', 'updatedAt', 'loaderData']))
|
|
2293
2348
|
}
|
|
2294
2349
|
};
|
|
2295
2350
|
};
|
|
@@ -2352,6 +2407,7 @@ function getInitialRouterState(location) {
|
|
|
2352
2407
|
location,
|
|
2353
2408
|
matches: [],
|
|
2354
2409
|
pendingMatches: [],
|
|
2410
|
+
preloadMatches: [],
|
|
2355
2411
|
lastUpdated: Date.now()
|
|
2356
2412
|
};
|
|
2357
2413
|
}
|