@solidjs/router 0.11.3 → 0.11.5
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/data/action.js +23 -8
- package/dist/data/cache.js +17 -2
- package/dist/data/response.d.ts +3 -3
- package/dist/data/response.js +9 -7
- package/dist/index.js +86 -16
- package/dist/routers/MemoryRouter.d.ts +3 -0
- package/dist/routers/MemoryRouter.js +2 -0
- package/dist/routers/components.d.ts +3 -1
- package/dist/routers/components.jsx +31 -3
- package/dist/routing.d.ts +1 -0
- package/dist/routing.js +1 -0
- package/dist/types.d.ts +4 -0
- package/dist/utils.d.ts +0 -1
- package/dist/utils.js +0 -1
- package/package.json +1 -1
package/dist/data/action.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { $TRACK, createMemo, createSignal, onCleanup, getOwner } from "solid-js";
|
|
2
2
|
import { isServer } from "solid-js/web";
|
|
3
3
|
import { useRouter } from "../routing.js";
|
|
4
|
-
import {
|
|
5
|
-
import { cacheKeyOp, hashKey, revalidate } from "./cache.js";
|
|
4
|
+
import { mockBase } from "../utils.js";
|
|
5
|
+
import { cacheKeyOp, hashKey, revalidate, cache } from "./cache.js";
|
|
6
6
|
export const actions = /* #__PURE__ */ new Map();
|
|
7
7
|
export function useSubmissions(fn, filter) {
|
|
8
8
|
const router = useRouter();
|
|
@@ -31,10 +31,12 @@ export function useAction(action) {
|
|
|
31
31
|
}
|
|
32
32
|
export function action(fn, name) {
|
|
33
33
|
function mutate(...variables) {
|
|
34
|
-
const
|
|
34
|
+
const router = this;
|
|
35
|
+
const p = (router.singleFlight && fn.withOptions
|
|
36
|
+
? fn.withOptions({ headers: { "X-Single-Flight": "true" } })
|
|
37
|
+
: fn)(...variables);
|
|
35
38
|
const [result, setResult] = createSignal();
|
|
36
39
|
let submission;
|
|
37
|
-
const router = this;
|
|
38
40
|
async function handler(res) {
|
|
39
41
|
const data = await handleResponse(res, router.navigatorFactory());
|
|
40
42
|
data ? setResult({ data }) : submission.clear();
|
|
@@ -95,12 +97,25 @@ const hashString = (s) => s.split("").reduce((a, b) => ((a << 5) - a + b.charCod
|
|
|
95
97
|
async function handleResponse(response, navigate) {
|
|
96
98
|
let data;
|
|
97
99
|
let keys;
|
|
100
|
+
let invalidateKeys;
|
|
98
101
|
if (response instanceof Response) {
|
|
99
102
|
if (response.headers.has("X-Revalidate"))
|
|
100
|
-
keys = response.headers.get("X-Revalidate").split(",");
|
|
101
|
-
if (response.customBody)
|
|
103
|
+
keys = invalidateKeys = response.headers.get("X-Revalidate").split(",");
|
|
104
|
+
if (response.customBody) {
|
|
102
105
|
data = await response.customBody();
|
|
103
|
-
|
|
106
|
+
if (response.headers.has("X-Single-Flight")) {
|
|
107
|
+
keys || (keys = []);
|
|
108
|
+
invalidateKeys || (invalidateKeys = []);
|
|
109
|
+
Object.keys(data).forEach(key => {
|
|
110
|
+
if (key === "_$value")
|
|
111
|
+
return;
|
|
112
|
+
keys.push(key);
|
|
113
|
+
cache.set(key, data[key]);
|
|
114
|
+
});
|
|
115
|
+
data = data._$value;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (response.headers.has("Location")) {
|
|
104
119
|
const locationUrl = response.headers.get("Location") || "/";
|
|
105
120
|
if (locationUrl.startsWith("http")) {
|
|
106
121
|
window.location.href = locationUrl;
|
|
@@ -113,7 +128,7 @@ async function handleResponse(response, navigate) {
|
|
|
113
128
|
else
|
|
114
129
|
data = response;
|
|
115
130
|
// invalidate
|
|
116
|
-
cacheKeyOp(
|
|
131
|
+
cacheKeyOp(invalidateKeys, entry => (entry[0] = 0));
|
|
117
132
|
// trigger revalidation
|
|
118
133
|
await revalidate(keys, false);
|
|
119
134
|
return data;
|
package/dist/data/cache.js
CHANGED
|
@@ -2,7 +2,6 @@ import { createSignal, getListener, getOwner, onCleanup, sharedConfig, startTran
|
|
|
2
2
|
import { createStore, reconcile } from "solid-js/store";
|
|
3
3
|
import { getRequestEvent, isServer } from "solid-js/web";
|
|
4
4
|
import { useNavigate, getIntent } from "../routing.js";
|
|
5
|
-
import { redirectStatusCodes } from "../utils.js";
|
|
6
5
|
const LocationHeader = "Location";
|
|
7
6
|
const PRELOAD_TIMEOUT = 5000;
|
|
8
7
|
const CACHE_TIMEOUT = 180000;
|
|
@@ -56,6 +55,21 @@ export function cache(fn, name, options) {
|
|
|
56
55
|
const key = name + hashKey(args);
|
|
57
56
|
let cached = cache.get(key);
|
|
58
57
|
let tracking;
|
|
58
|
+
if (isServer) {
|
|
59
|
+
const e = getRequestEvent();
|
|
60
|
+
if (e) {
|
|
61
|
+
const dataOnly = (e.router || (e.router = {})).dataOnly;
|
|
62
|
+
if (dataOnly) {
|
|
63
|
+
const data = e && (e.router.data || (e.router.data = {}));
|
|
64
|
+
if (data && key in data)
|
|
65
|
+
return data[key];
|
|
66
|
+
if (Array.isArray(dataOnly) && !dataOnly.includes(key)) {
|
|
67
|
+
data[key] = undefined;
|
|
68
|
+
return Promise.resolve();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
59
73
|
if (getListener() && !isServer) {
|
|
60
74
|
tracking = true;
|
|
61
75
|
onCleanup(() => cached[3].count--);
|
|
@@ -91,6 +105,7 @@ export function cache(fn, name, options) {
|
|
|
91
105
|
sharedConfig.context.async &&
|
|
92
106
|
!sharedConfig.context.noHydrate) {
|
|
93
107
|
const e = getRequestEvent();
|
|
108
|
+
e && e.router.dataOnly && (e.router.data[key] = res);
|
|
94
109
|
(!e || !e.serverOnly) && sharedConfig.context.serialize(key, res);
|
|
95
110
|
}
|
|
96
111
|
if (cached) {
|
|
@@ -117,7 +132,7 @@ export function cache(fn, name, options) {
|
|
|
117
132
|
function handleResponse(error) {
|
|
118
133
|
return async (v) => {
|
|
119
134
|
if (v instanceof Response) {
|
|
120
|
-
if (
|
|
135
|
+
if (v.headers.has("Location")) {
|
|
121
136
|
if (navigate) {
|
|
122
137
|
startTransition(() => {
|
|
123
138
|
let url = v.headers.get(LocationHeader);
|
package/dist/data/response.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export type RouterResponseInit = ResponseInit & {
|
|
1
|
+
export type RouterResponseInit = Omit<ResponseInit, "body"> & {
|
|
2
2
|
revalidate?: string | string[];
|
|
3
3
|
};
|
|
4
4
|
export declare function redirect(url: string, init?: number | RouterResponseInit): never;
|
|
5
|
-
export declare function reload(init
|
|
6
|
-
export declare function json<T>(data: T, init?:
|
|
5
|
+
export declare function reload(init?: RouterResponseInit): never;
|
|
6
|
+
export declare function json<T>(data: T, init?: RouterResponseInit): T;
|
package/dist/data/response.js
CHANGED
|
@@ -19,20 +19,22 @@ export function redirect(url, init = 302) {
|
|
|
19
19
|
});
|
|
20
20
|
return response;
|
|
21
21
|
}
|
|
22
|
-
export function reload(init) {
|
|
22
|
+
export function reload(init = {}) {
|
|
23
23
|
const { revalidate, ...responseInit } = init;
|
|
24
|
+
const headers = new Headers(responseInit.headers);
|
|
25
|
+
revalidate && headers.set("X-Revalidate", revalidate.toString());
|
|
24
26
|
return new Response(null, {
|
|
25
27
|
...responseInit,
|
|
26
|
-
|
|
27
|
-
? { headers: new Headers(responseInit.headers).set("X-Revalidate", revalidate.toString()) }
|
|
28
|
-
: {})
|
|
28
|
+
headers
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
|
-
export function json(data, init) {
|
|
32
|
-
const
|
|
31
|
+
export function json(data, init = {}) {
|
|
32
|
+
const { revalidate, ...responseInit } = init;
|
|
33
|
+
const headers = new Headers(responseInit.headers);
|
|
34
|
+
revalidate && headers.set("X-Revalidate", revalidate.toString());
|
|
33
35
|
headers.set("Content-Type", "application/json");
|
|
34
36
|
const response = new Response(JSON.stringify(data), {
|
|
35
|
-
...
|
|
37
|
+
...responseInit,
|
|
36
38
|
headers
|
|
37
39
|
});
|
|
38
40
|
response.customBody = () => data;
|
package/dist/index.js
CHANGED
|
@@ -79,7 +79,6 @@ function notifyIfNotBlocked(notify, block) {
|
|
|
79
79
|
const hasSchemeRegex = /^(?:[a-z0-9]+:)?\/\//i;
|
|
80
80
|
const trimPathRegex = /^\/+|(\/)\/+$/g;
|
|
81
81
|
const mockBase = "http://sr";
|
|
82
|
-
const redirectStatusCodes = new Set([204, 301, 302, 303, 307, 308]);
|
|
83
82
|
function normalizePath(path, omitSlash = false) {
|
|
84
83
|
const s = path.replace(trimPathRegex, "$1");
|
|
85
84
|
return s ? omitSlash || /^[?#]/.test(s) ? s : "/" + s : "";
|
|
@@ -477,6 +476,7 @@ function createRouterContext(integration, getBranches, options = {}) {
|
|
|
477
476
|
navigatorFactory,
|
|
478
477
|
beforeLeave,
|
|
479
478
|
preloadRoute,
|
|
479
|
+
singleFlight: options.singleFlight === undefined ? true : options.singleFlight,
|
|
480
480
|
submissions
|
|
481
481
|
};
|
|
482
482
|
function navigateFromRoute(route, to, options) {
|
|
@@ -641,10 +641,12 @@ const createRouterComponent = router => props => {
|
|
|
641
641
|
const routeDefs = children(() => props.children);
|
|
642
642
|
const branches = createMemo(() => createBranches(props.root ? {
|
|
643
643
|
component: props.root,
|
|
644
|
+
load: props.rootLoad,
|
|
644
645
|
children: routeDefs()
|
|
645
646
|
} : routeDefs(), props.base || ""));
|
|
646
647
|
const routerState = createRouterContext(router, branches, {
|
|
647
|
-
base
|
|
648
|
+
base,
|
|
649
|
+
singleFlight: props.singleFlight
|
|
648
650
|
});
|
|
649
651
|
router.create && router.create(routerState);
|
|
650
652
|
return createComponent$1(RouterContextObj.Provider, {
|
|
@@ -663,6 +665,10 @@ function Routes(props) {
|
|
|
663
665
|
const matches = createMemo(() => getRouteMatches(props.branches, props.routerState.location.pathname));
|
|
664
666
|
if (isServer) {
|
|
665
667
|
const e = getRequestEvent();
|
|
668
|
+
if (e && e.router && e.router.dataOnly) {
|
|
669
|
+
dataOnly(e, props.branches);
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
666
672
|
e && ((e.router || (e.router = {})).matches || (e.router.matches = matches().map(({
|
|
667
673
|
route,
|
|
668
674
|
path,
|
|
@@ -747,6 +753,32 @@ const Route = props => {
|
|
|
747
753
|
});
|
|
748
754
|
};
|
|
749
755
|
|
|
756
|
+
// for data only mode with single flight mutations
|
|
757
|
+
function dataOnly(event, branches) {
|
|
758
|
+
const url = new URL(event.request.url);
|
|
759
|
+
const prevMatches = getRouteMatches(branches, new URL(event.router.previousUrl || event.request.url).pathname);
|
|
760
|
+
const matches = getRouteMatches(branches, url.pathname);
|
|
761
|
+
for (let match = 0; match < matches.length; match++) {
|
|
762
|
+
if (!prevMatches[match] || matches[match].route !== prevMatches[match].route) event.router.dataOnly = true;
|
|
763
|
+
const {
|
|
764
|
+
route,
|
|
765
|
+
params
|
|
766
|
+
} = matches[match];
|
|
767
|
+
route.load && route.load({
|
|
768
|
+
params,
|
|
769
|
+
location: {
|
|
770
|
+
pathname: url.pathname,
|
|
771
|
+
search: url.search,
|
|
772
|
+
hash: url.hash,
|
|
773
|
+
query: extractSearchParams(url),
|
|
774
|
+
state: null,
|
|
775
|
+
key: ""
|
|
776
|
+
},
|
|
777
|
+
intent: "preload"
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
750
782
|
function intercept([value, setValue], get, set) {
|
|
751
783
|
return [get ? () => get(value()) : value, set ? v => setValue(set(v)) : setValue];
|
|
752
784
|
}
|
|
@@ -860,6 +892,20 @@ function cache(fn, name, options) {
|
|
|
860
892
|
const key = name + hashKey(args);
|
|
861
893
|
let cached = cache.get(key);
|
|
862
894
|
let tracking;
|
|
895
|
+
if (isServer) {
|
|
896
|
+
const e = getRequestEvent();
|
|
897
|
+
if (e) {
|
|
898
|
+
const dataOnly = (e.router || (e.router = {})).dataOnly;
|
|
899
|
+
if (dataOnly) {
|
|
900
|
+
const data = e && (e.router.data || (e.router.data = {}));
|
|
901
|
+
if (data && key in data) return data[key];
|
|
902
|
+
if (Array.isArray(dataOnly) && !dataOnly.includes(key)) {
|
|
903
|
+
data[key] = undefined;
|
|
904
|
+
return Promise.resolve();
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
}
|
|
908
|
+
}
|
|
863
909
|
if (getListener() && !isServer) {
|
|
864
910
|
tracking = true;
|
|
865
911
|
onCleanup(() => cached[3].count--);
|
|
@@ -885,6 +931,7 @@ function cache(fn, name, options) {
|
|
|
885
931
|
// serialize on server
|
|
886
932
|
if (isServer && sharedConfig.context && sharedConfig.context.async && !sharedConfig.context.noHydrate) {
|
|
887
933
|
const e = getRequestEvent();
|
|
934
|
+
e && e.router.dataOnly && (e.router.data[key] = res);
|
|
888
935
|
(!e || !e.serverOnly) && sharedConfig.context.serialize(key, res);
|
|
889
936
|
}
|
|
890
937
|
if (cached) {
|
|
@@ -907,7 +954,7 @@ function cache(fn, name, options) {
|
|
|
907
954
|
function handleResponse(error) {
|
|
908
955
|
return async v => {
|
|
909
956
|
if (v instanceof Response) {
|
|
910
|
-
if (
|
|
957
|
+
if (v.headers.has("Location")) {
|
|
911
958
|
if (navigate) {
|
|
912
959
|
startTransition(() => {
|
|
913
960
|
let url = v.headers.get(LocationHeader);
|
|
@@ -995,10 +1042,14 @@ function useAction(action) {
|
|
|
995
1042
|
}
|
|
996
1043
|
function action(fn, name) {
|
|
997
1044
|
function mutate(...variables) {
|
|
998
|
-
const
|
|
1045
|
+
const router = this;
|
|
1046
|
+
const p = (router.singleFlight && fn.withOptions ? fn.withOptions({
|
|
1047
|
+
headers: {
|
|
1048
|
+
"X-Single-Flight": "true"
|
|
1049
|
+
}
|
|
1050
|
+
}) : fn)(...variables);
|
|
999
1051
|
const [result, setResult] = createSignal();
|
|
1000
1052
|
let submission;
|
|
1001
|
-
const router = this;
|
|
1002
1053
|
async function handler(res) {
|
|
1003
1054
|
const data = await handleResponse(res, router.navigatorFactory());
|
|
1004
1055
|
data ? setResult({
|
|
@@ -1055,10 +1106,23 @@ const hashString = s => s.split("").reduce((a, b) => (a << 5) - a + b.charCodeAt
|
|
|
1055
1106
|
async function handleResponse(response, navigate) {
|
|
1056
1107
|
let data;
|
|
1057
1108
|
let keys;
|
|
1109
|
+
let invalidateKeys;
|
|
1058
1110
|
if (response instanceof Response) {
|
|
1059
|
-
if (response.headers.has("X-Revalidate")) keys = response.headers.get("X-Revalidate").split(",");
|
|
1060
|
-
if (response.customBody)
|
|
1061
|
-
|
|
1111
|
+
if (response.headers.has("X-Revalidate")) keys = invalidateKeys = response.headers.get("X-Revalidate").split(",");
|
|
1112
|
+
if (response.customBody) {
|
|
1113
|
+
data = await response.customBody();
|
|
1114
|
+
if (response.headers.has("X-Single-Flight")) {
|
|
1115
|
+
keys || (keys = []);
|
|
1116
|
+
invalidateKeys || (invalidateKeys = []);
|
|
1117
|
+
Object.keys(data).forEach(key => {
|
|
1118
|
+
if (key === "_$value") return;
|
|
1119
|
+
keys.push(key);
|
|
1120
|
+
cache.set(key, data[key]);
|
|
1121
|
+
});
|
|
1122
|
+
data = data._$value;
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
if (response.headers.has("Location")) {
|
|
1062
1126
|
const locationUrl = response.headers.get("Location") || "/";
|
|
1063
1127
|
if (locationUrl.startsWith("http")) {
|
|
1064
1128
|
window.location.href = locationUrl;
|
|
@@ -1068,7 +1132,7 @@ async function handleResponse(response, navigate) {
|
|
|
1068
1132
|
}
|
|
1069
1133
|
} else data = response;
|
|
1070
1134
|
// invalidate
|
|
1071
|
-
cacheKeyOp(
|
|
1135
|
+
cacheKeyOp(invalidateKeys, entry => entry[0] = 0);
|
|
1072
1136
|
// trigger revalidation
|
|
1073
1137
|
await revalidate(keys, false);
|
|
1074
1138
|
return data;
|
|
@@ -1310,6 +1374,7 @@ function MemoryRouter(props) {
|
|
|
1310
1374
|
get: memoryHistory.get,
|
|
1311
1375
|
set: memoryHistory.set,
|
|
1312
1376
|
init: memoryHistory.listen,
|
|
1377
|
+
create: setupNativeEvents(props.preload, props.explicitLinks, props.actionBase),
|
|
1313
1378
|
utils: {
|
|
1314
1379
|
go: memoryHistory.go
|
|
1315
1380
|
}
|
|
@@ -1455,23 +1520,28 @@ function redirect(url, init = 302) {
|
|
|
1455
1520
|
});
|
|
1456
1521
|
return response;
|
|
1457
1522
|
}
|
|
1458
|
-
function reload(init) {
|
|
1523
|
+
function reload(init = {}) {
|
|
1459
1524
|
const {
|
|
1460
1525
|
revalidate,
|
|
1461
1526
|
...responseInit
|
|
1462
1527
|
} = init;
|
|
1528
|
+
const headers = new Headers(responseInit.headers);
|
|
1529
|
+
revalidate && headers.set("X-Revalidate", revalidate.toString());
|
|
1463
1530
|
return new Response(null, {
|
|
1464
1531
|
...responseInit,
|
|
1465
|
-
|
|
1466
|
-
headers: new Headers(responseInit.headers).set("X-Revalidate", revalidate.toString())
|
|
1467
|
-
} : {})
|
|
1532
|
+
headers
|
|
1468
1533
|
});
|
|
1469
1534
|
}
|
|
1470
|
-
function json(data, init) {
|
|
1471
|
-
const
|
|
1535
|
+
function json(data, init = {}) {
|
|
1536
|
+
const {
|
|
1537
|
+
revalidate,
|
|
1538
|
+
...responseInit
|
|
1539
|
+
} = init;
|
|
1540
|
+
const headers = new Headers(responseInit.headers);
|
|
1541
|
+
revalidate && headers.set("X-Revalidate", revalidate.toString());
|
|
1472
1542
|
headers.set("Content-Type", "application/json");
|
|
1473
1543
|
const response = new Response(JSON.stringify(data), {
|
|
1474
|
-
...
|
|
1544
|
+
...responseInit,
|
|
1475
1545
|
headers
|
|
1476
1546
|
});
|
|
1477
1547
|
response.customBody = () => data;
|
|
@@ -17,5 +17,8 @@ export declare function createMemoryHistory(): {
|
|
|
17
17
|
};
|
|
18
18
|
export type MemoryRouterProps = BaseRouterProps & {
|
|
19
19
|
history?: MemoryHistory;
|
|
20
|
+
actionBase?: string;
|
|
21
|
+
explicitLinks?: boolean;
|
|
22
|
+
preload?: boolean;
|
|
20
23
|
};
|
|
21
24
|
export declare function MemoryRouter(props: MemoryRouterProps): JSX.Element;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createRouter, scrollToHash } from "./createRouter.js";
|
|
2
|
+
import { setupNativeEvents } from "../data/events.js";
|
|
2
3
|
export function createMemoryHistory() {
|
|
3
4
|
const entries = ["/"];
|
|
4
5
|
let index = 0;
|
|
@@ -45,6 +46,7 @@ export function MemoryRouter(props) {
|
|
|
45
46
|
get: memoryHistory.get,
|
|
46
47
|
set: memoryHistory.set,
|
|
47
48
|
init: memoryHistory.listen,
|
|
49
|
+
create: setupNativeEvents(props.preload, props.explicitLinks, props.actionBase),
|
|
48
50
|
utils: {
|
|
49
51
|
go: memoryHistory.go
|
|
50
52
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { Component, JSX } from "solid-js";
|
|
2
|
-
import type { MatchFilters, RouteLoadFunc, RouteDefinition, RouterIntegration, RouteSectionProps } from "../types.
|
|
2
|
+
import type { MatchFilters, RouteLoadFunc, RouteDefinition, RouterIntegration, RouteSectionProps } from "../types.js";
|
|
3
3
|
export type BaseRouterProps = {
|
|
4
4
|
base?: string;
|
|
5
5
|
/**
|
|
6
6
|
* A component that wraps the content of every route.
|
|
7
7
|
*/
|
|
8
8
|
root?: Component<RouteSectionProps>;
|
|
9
|
+
rootLoad?: RouteLoadFunc;
|
|
10
|
+
singleFlight?: boolean;
|
|
9
11
|
children?: JSX.Element | RouteDefinition | RouteDefinition[];
|
|
10
12
|
};
|
|
11
13
|
export declare const createRouterComponent: (router: RouterIntegration) => (props: BaseRouterProps) => JSX.Element;
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import { getRequestEvent, isServer } from "solid-js/web";
|
|
3
3
|
import { children, createMemo, createRoot, mergeProps, on, Show } from "solid-js";
|
|
4
4
|
import { createBranches, createRouteContext, createRouterContext, getRouteMatches, RouteContextObj, RouterContextObj } from "../routing.js";
|
|
5
|
-
import { createMemoObject } from "../utils.js";
|
|
5
|
+
import { createMemoObject, extractSearchParams } from "../utils.js";
|
|
6
6
|
export const createRouterComponent = (router) => (props) => {
|
|
7
7
|
const { base } = props;
|
|
8
8
|
const routeDefs = children(() => props.children);
|
|
9
|
-
const branches = createMemo(() => createBranches(props.root ? { component: props.root, children: routeDefs() } : routeDefs(), props.base || ""));
|
|
10
|
-
const routerState = createRouterContext(router, branches, { base });
|
|
9
|
+
const branches = createMemo(() => createBranches(props.root ? { component: props.root, load: props.rootLoad, children: routeDefs() } : routeDefs(), props.base || ""));
|
|
10
|
+
const routerState = createRouterContext(router, branches, { base, singleFlight: props.singleFlight });
|
|
11
11
|
router.create && router.create(routerState);
|
|
12
12
|
return (<RouterContextObj.Provider value={routerState}>
|
|
13
13
|
<Routes routerState={routerState} branches={branches()}/>
|
|
@@ -17,6 +17,10 @@ function Routes(props) {
|
|
|
17
17
|
const matches = createMemo(() => getRouteMatches(props.branches, props.routerState.location.pathname));
|
|
18
18
|
if (isServer) {
|
|
19
19
|
const e = getRequestEvent();
|
|
20
|
+
if (e && e.router && e.router.dataOnly) {
|
|
21
|
+
dataOnly(e, props.branches);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
20
24
|
e &&
|
|
21
25
|
((e.router || (e.router = {})).matches ||
|
|
22
26
|
(e.router.matches = matches().map(({ route, path, params }) => ({
|
|
@@ -81,3 +85,27 @@ export const Route = (props) => {
|
|
|
81
85
|
}
|
|
82
86
|
});
|
|
83
87
|
};
|
|
88
|
+
// for data only mode with single flight mutations
|
|
89
|
+
function dataOnly(event, branches) {
|
|
90
|
+
const url = new URL(event.request.url);
|
|
91
|
+
const prevMatches = getRouteMatches(branches, new URL(event.router.previousUrl || event.request.url).pathname);
|
|
92
|
+
const matches = getRouteMatches(branches, url.pathname);
|
|
93
|
+
for (let match = 0; match < matches.length; match++) {
|
|
94
|
+
if (!prevMatches[match] || matches[match].route !== prevMatches[match].route)
|
|
95
|
+
event.router.dataOnly = true;
|
|
96
|
+
const { route, params } = matches[match];
|
|
97
|
+
route.load &&
|
|
98
|
+
route.load({
|
|
99
|
+
params,
|
|
100
|
+
location: {
|
|
101
|
+
pathname: url.pathname,
|
|
102
|
+
search: url.search,
|
|
103
|
+
hash: url.hash,
|
|
104
|
+
query: extractSearchParams(url),
|
|
105
|
+
state: null,
|
|
106
|
+
key: ""
|
|
107
|
+
},
|
|
108
|
+
intent: "preload"
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
package/dist/routing.d.ts
CHANGED
|
@@ -21,5 +21,6 @@ export declare function createLocation(path: Accessor<string>, state: Accessor<a
|
|
|
21
21
|
export declare function getIntent(): Intent | undefined;
|
|
22
22
|
export declare function createRouterContext(integration: RouterIntegration, getBranches?: () => Branch[], options?: {
|
|
23
23
|
base?: string;
|
|
24
|
+
singleFlight?: boolean;
|
|
24
25
|
}): RouterContext;
|
|
25
26
|
export declare function createRouteContext(router: RouterContext, parent: RouteContext, outlet: () => JSX.Element, match: () => RouteMatch, params: Params): RouteContext;
|
package/dist/routing.js
CHANGED
|
@@ -245,6 +245,7 @@ export function createRouterContext(integration, getBranches, options = {}) {
|
|
|
245
245
|
navigatorFactory,
|
|
246
246
|
beforeLeave,
|
|
247
247
|
preloadRoute,
|
|
248
|
+
singleFlight: options.singleFlight === undefined ? true : options.singleFlight,
|
|
248
249
|
submissions
|
|
249
250
|
};
|
|
250
251
|
function navigateFromRoute(route, to, options) {
|
package/dist/types.d.ts
CHANGED
|
@@ -10,6 +10,9 @@ declare module "solid-js/web" {
|
|
|
10
10
|
matches?: OutputMatch[];
|
|
11
11
|
cache?: Map<string, CacheEntry>;
|
|
12
12
|
submission?: Submission<any, any>;
|
|
13
|
+
dataOnly?: boolean | string[];
|
|
14
|
+
data?: Record<string, any>;
|
|
15
|
+
previousUrl?: string;
|
|
13
16
|
};
|
|
14
17
|
serverOnly?: boolean;
|
|
15
18
|
}
|
|
@@ -127,6 +130,7 @@ export interface RouterContext {
|
|
|
127
130
|
parsePath(str: string): string;
|
|
128
131
|
beforeLeave: BeforeLeaveLifecycle;
|
|
129
132
|
preloadRoute: (url: URL, preloadData: boolean) => void;
|
|
133
|
+
singleFlight: boolean;
|
|
130
134
|
submissions: Signal<Submission<any, any>[]>;
|
|
131
135
|
}
|
|
132
136
|
export interface BeforeLeaveEventArgs {
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { MatchFilters, Params, PathMatch, Route, SetParams } from "./types.ts";
|
|
2
2
|
export declare const mockBase = "http://sr";
|
|
3
|
-
export declare const redirectStatusCodes: Set<number>;
|
|
4
3
|
export declare function normalizePath(path: string, omitSlash?: boolean): string;
|
|
5
4
|
export declare function resolvePath(base: string, path: string, from?: string): string | undefined;
|
|
6
5
|
export declare function invariant<T>(value: T | null | undefined, message: string): T;
|
package/dist/utils.js
CHANGED
|
@@ -2,7 +2,6 @@ import { createMemo, getOwner, runWithOwner } from "solid-js";
|
|
|
2
2
|
const hasSchemeRegex = /^(?:[a-z0-9]+:)?\/\//i;
|
|
3
3
|
const trimPathRegex = /^\/+|(\/)\/+$/g;
|
|
4
4
|
export const mockBase = "http://sr";
|
|
5
|
-
export const redirectStatusCodes = new Set([204, 301, 302, 303, 307, 308]);
|
|
6
5
|
export function normalizePath(path, omitSlash = false) {
|
|
7
6
|
const s = path.replace(trimPathRegex, "$1");
|
|
8
7
|
return s ? (omitSlash || /^[?#]/.test(s) ? s : "/" + s) : "";
|