@qwik.dev/router 2.0.0-beta.3 → 2.0.0-beta.4
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/lib/index.d.ts +5 -2
- package/lib/index.qwik.cjs +188 -113
- package/lib/index.qwik.mjs +190 -115
- package/lib/middleware/request-handler/index.cjs +138 -61
- package/lib/middleware/request-handler/index.d.ts +7 -0
- package/lib/middleware/request-handler/index.mjs +139 -61
- package/lib/static/node.cjs +4 -2
- package/lib/static/node.mjs +5 -3
- package/lib/vite/index.cjs +141 -61
- package/lib/vite/index.d.ts +3 -0
- package/lib/vite/index.mjs +143 -61
- package/package.json +2 -2
package/lib/index.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { RequestEventCommon } from '@qwik.dev/router/middleware/request-handler'
|
|
|
19
19
|
import { RequestEventLoader } from '@qwik.dev/router/middleware/request-handler';
|
|
20
20
|
import { RequestHandler } from '@qwik.dev/router/middleware/request-handler';
|
|
21
21
|
import type { ResolveSyncValue } from '@qwik.dev/router/middleware/request-handler';
|
|
22
|
+
import type { SerializationStrategy } from '@qwik.dev/core/internal';
|
|
22
23
|
import type * as v from 'valibot';
|
|
23
24
|
import type { ValueOrPromise } from '@qwik.dev/core';
|
|
24
25
|
import { z } from 'zod';
|
|
@@ -450,7 +451,9 @@ declare type LoaderConstructorQRL = {
|
|
|
450
451
|
|
|
451
452
|
/** @public */
|
|
452
453
|
declare type LoaderOptions = {
|
|
453
|
-
id?: string;
|
|
454
|
+
readonly id?: string;
|
|
455
|
+
readonly validation?: DataValidator[];
|
|
456
|
+
readonly serializationStrategy?: SerializationStrategy;
|
|
454
457
|
};
|
|
455
458
|
|
|
456
459
|
/** @public */
|
|
@@ -575,7 +578,7 @@ export declare interface QwikRouterProps {
|
|
|
575
578
|
*
|
|
576
579
|
* @see https://github.com/WICG/view-transitions/blob/main/explainer.md
|
|
577
580
|
* @see https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API
|
|
578
|
-
* @see https://caniuse.com/
|
|
581
|
+
* @see https://caniuse.com/mdn_api_viewtransition
|
|
579
582
|
*/
|
|
580
583
|
viewTransition?: boolean;
|
|
581
584
|
}
|
package/lib/index.qwik.cjs
CHANGED
|
@@ -39,100 +39,19 @@ const ErrorBoundary = core.component$((props) => {
|
|
|
39
39
|
const MODULE_CACHE = /* @__PURE__ */ new WeakMap();
|
|
40
40
|
const CLIENT_DATA_CACHE = /* @__PURE__ */ new Map();
|
|
41
41
|
const QACTION_KEY = "qaction";
|
|
42
|
+
const QLOADER_KEY = "qloaders";
|
|
42
43
|
const QFN_KEY = "qfunc";
|
|
43
44
|
const QDATA_KEY = "qdata";
|
|
44
|
-
const
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
const
|
|
48
|
-
const isSamePathname = ({ pathname: a }, { pathname: b }) => {
|
|
49
|
-
const lDiff = Math.abs(a.length - b.length);
|
|
50
|
-
return lDiff === 0 ? a === b : lDiff === 1 && withSlash(a) === withSlash(b);
|
|
51
|
-
};
|
|
52
|
-
const isSameSearchQuery = (a, b) => a.search === b.search;
|
|
53
|
-
const isSamePath = (a, b) => isSameSearchQuery(a, b) && isSamePathname(a, b);
|
|
54
|
-
const getClientDataPath = (pathname, pageSearch, action) => {
|
|
55
|
-
let search = pageSearch ?? "";
|
|
56
|
-
if (action) {
|
|
57
|
-
search += (search ? "&" : "?") + QACTION_KEY + "=" + encodeURIComponent(action.id);
|
|
58
|
-
}
|
|
59
|
-
return pathname + (pathname.endsWith("/") ? "" : "/") + "q-data.json" + search;
|
|
60
|
-
};
|
|
61
|
-
const getClientNavPath = (props, baseUrl) => {
|
|
62
|
-
const href = props.href;
|
|
63
|
-
if (typeof href === "string" && typeof props.target !== "string" && !props.reload) {
|
|
64
|
-
try {
|
|
65
|
-
const linkUrl = toUrl(href.trim(), baseUrl.url);
|
|
66
|
-
const currentUrl = toUrl("", baseUrl.url);
|
|
67
|
-
if (isSameOrigin(linkUrl, currentUrl)) {
|
|
68
|
-
return toPath(linkUrl);
|
|
69
|
-
}
|
|
70
|
-
} catch (e) {
|
|
71
|
-
console.error(e);
|
|
72
|
-
}
|
|
73
|
-
} else if (props.reload) {
|
|
74
|
-
return toPath(toUrl("", baseUrl.url));
|
|
75
|
-
}
|
|
76
|
-
return null;
|
|
77
|
-
};
|
|
78
|
-
const shouldPreload = (clientNavPath, currentLoc) => {
|
|
79
|
-
if (clientNavPath) {
|
|
80
|
-
const prefetchUrl = toUrl(clientNavPath, currentLoc.url);
|
|
81
|
-
const currentUrl = toUrl("", currentLoc.url);
|
|
82
|
-
return !isSamePathname(prefetchUrl, currentUrl);
|
|
83
|
-
}
|
|
84
|
-
return false;
|
|
85
|
-
};
|
|
86
|
-
const isPromise = (value) => {
|
|
87
|
-
return value && typeof value.then === "function";
|
|
88
|
-
};
|
|
89
|
-
const deepFreeze = (obj) => {
|
|
90
|
-
if (obj == null) {
|
|
91
|
-
return obj;
|
|
92
|
-
}
|
|
93
|
-
Object.getOwnPropertyNames(obj).forEach((prop) => {
|
|
94
|
-
const value = obj[prop];
|
|
95
|
-
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
96
|
-
deepFreeze(value);
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
return Object.freeze(obj);
|
|
100
|
-
};
|
|
101
|
-
const clientNavigate = (win, navType, fromURL, toURL, replaceState = false) => {
|
|
102
|
-
if (navType !== "popstate") {
|
|
103
|
-
const samePath = isSamePath(fromURL, toURL);
|
|
104
|
-
const sameHash = fromURL.hash === toURL.hash;
|
|
105
|
-
if (!samePath || !sameHash) {
|
|
106
|
-
const newState = {
|
|
107
|
-
_qRouterScroll: newScrollState()
|
|
108
|
-
};
|
|
109
|
-
if (replaceState) {
|
|
110
|
-
win.history.replaceState(newState, "", toPath(toURL));
|
|
111
|
-
} else {
|
|
112
|
-
win.history.pushState(newState, "", toPath(toURL));
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
};
|
|
117
|
-
const newScrollState = () => {
|
|
118
|
-
return {
|
|
119
|
-
x: 0,
|
|
120
|
-
y: 0,
|
|
121
|
-
w: 0,
|
|
122
|
-
h: 0
|
|
123
|
-
};
|
|
124
|
-
};
|
|
125
|
-
const prefetchSymbols = (path) => {
|
|
126
|
-
if (core.isBrowser) {
|
|
127
|
-
path = path.endsWith("/") ? path : path + "/";
|
|
128
|
-
path = path.length > 1 && path.startsWith("/") ? path.slice(1) : path;
|
|
129
|
-
preloader.p(path, 0.8);
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
const loadClientData = async (url, element, opts) => {
|
|
45
|
+
const Q_ROUTE = "q:route";
|
|
46
|
+
const DEFAULT_LOADERS_SERIALIZATION_STRATEGY = globalThis.__DEFAULT_LOADERS_SERIALIZATION_STRATEGY__ || "never";
|
|
47
|
+
const MAX_Q_DATA_RETRY_COUNT = 3;
|
|
48
|
+
const loadClientData = async (url, element, opts, retryCount = 0) => {
|
|
133
49
|
const pagePathname = url.pathname;
|
|
134
50
|
const pageSearch = url.search;
|
|
135
|
-
const clientDataPath = getClientDataPath(pagePathname, pageSearch,
|
|
51
|
+
const clientDataPath = getClientDataPath(pagePathname, pageSearch, {
|
|
52
|
+
actionId: opts?.action?.id,
|
|
53
|
+
loaderIds: opts?.loaderIds
|
|
54
|
+
});
|
|
136
55
|
let qData;
|
|
137
56
|
if (!opts?.action) {
|
|
138
57
|
qData = CLIENT_DATA_CACHE.get(clientDataPath);
|
|
@@ -147,6 +66,10 @@ const loadClientData = async (url, element, opts) => {
|
|
|
147
66
|
opts.action.data = void 0;
|
|
148
67
|
}
|
|
149
68
|
qData = fetch(clientDataPath, fetchOptions).then((rsp) => {
|
|
69
|
+
if (rsp.status === 404 && opts?.loaderIds && retryCount < MAX_Q_DATA_RETRY_COUNT) {
|
|
70
|
+
opts.loaderIds = void 0;
|
|
71
|
+
return loadClientData(url, element, opts, retryCount + 1);
|
|
72
|
+
}
|
|
150
73
|
if (rsp.redirected) {
|
|
151
74
|
const redirectedURL = new URL(rsp.url);
|
|
152
75
|
const isQData = redirectedURL.pathname.endsWith("/q-data.json");
|
|
@@ -227,6 +150,115 @@ const getFetchOptions = (action, noCache) => {
|
|
|
227
150
|
};
|
|
228
151
|
}
|
|
229
152
|
};
|
|
153
|
+
const toPath = (url) => url.pathname + url.search + url.hash;
|
|
154
|
+
const toUrl = (url, baseUrl) => new URL(url, baseUrl.href);
|
|
155
|
+
const isSameOrigin = (a, b) => a.origin === b.origin;
|
|
156
|
+
const withSlash = (path) => path.endsWith("/") ? path : path + "/";
|
|
157
|
+
const isSamePathname = ({ pathname: a }, { pathname: b }) => {
|
|
158
|
+
const lDiff = Math.abs(a.length - b.length);
|
|
159
|
+
return lDiff === 0 ? a === b : lDiff === 1 && withSlash(a) === withSlash(b);
|
|
160
|
+
};
|
|
161
|
+
const isSameSearchQuery = (a, b) => a.search === b.search;
|
|
162
|
+
const isSamePath = (a, b) => isSameSearchQuery(a, b) && isSamePathname(a, b);
|
|
163
|
+
const getClientDataPath = (pathname, pageSearch, options) => {
|
|
164
|
+
let search = pageSearch ?? "";
|
|
165
|
+
if (options?.actionId) {
|
|
166
|
+
search += (search ? "&" : "?") + QACTION_KEY + "=" + encodeURIComponent(options.actionId);
|
|
167
|
+
}
|
|
168
|
+
if (options?.loaderIds) {
|
|
169
|
+
for (const loaderId of options.loaderIds) {
|
|
170
|
+
search += (search ? "&" : "?") + QLOADER_KEY + "=" + encodeURIComponent(loaderId);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return pathname + (pathname.endsWith("/") ? "" : "/") + "q-data.json" + search;
|
|
174
|
+
};
|
|
175
|
+
const getClientNavPath = (props, baseUrl) => {
|
|
176
|
+
const href = props.href;
|
|
177
|
+
if (typeof href === "string" && typeof props.target !== "string" && !props.reload) {
|
|
178
|
+
try {
|
|
179
|
+
const linkUrl = toUrl(href.trim(), baseUrl.url);
|
|
180
|
+
const currentUrl = toUrl("", baseUrl.url);
|
|
181
|
+
if (isSameOrigin(linkUrl, currentUrl)) {
|
|
182
|
+
return toPath(linkUrl);
|
|
183
|
+
}
|
|
184
|
+
} catch (e) {
|
|
185
|
+
console.error(e);
|
|
186
|
+
}
|
|
187
|
+
} else if (props.reload) {
|
|
188
|
+
return toPath(toUrl("", baseUrl.url));
|
|
189
|
+
}
|
|
190
|
+
return null;
|
|
191
|
+
};
|
|
192
|
+
const shouldPreload = (clientNavPath, currentLoc) => {
|
|
193
|
+
if (clientNavPath) {
|
|
194
|
+
const prefetchUrl = toUrl(clientNavPath, currentLoc.url);
|
|
195
|
+
const currentUrl = toUrl("", currentLoc.url);
|
|
196
|
+
return !isSamePathname(prefetchUrl, currentUrl);
|
|
197
|
+
}
|
|
198
|
+
return false;
|
|
199
|
+
};
|
|
200
|
+
const isPromise = (value) => {
|
|
201
|
+
return value && typeof value.then === "function";
|
|
202
|
+
};
|
|
203
|
+
const deepFreeze = (obj) => {
|
|
204
|
+
if (obj == null) {
|
|
205
|
+
return obj;
|
|
206
|
+
}
|
|
207
|
+
Object.getOwnPropertyNames(obj).forEach((prop) => {
|
|
208
|
+
const value = obj[prop];
|
|
209
|
+
if (value && typeof value === "object" && !Object.isFrozen(value)) {
|
|
210
|
+
deepFreeze(value);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
return Object.freeze(obj);
|
|
214
|
+
};
|
|
215
|
+
const createLoaderSignal = (loadersObject, loaderId, url, serializationStrategy, container) => {
|
|
216
|
+
return core.createAsyncComputed$(async () => {
|
|
217
|
+
if (core.isBrowser && loadersObject[loaderId] === internal._UNINITIALIZED) {
|
|
218
|
+
const data = await loadClientData(url, void 0, {
|
|
219
|
+
loaderIds: [
|
|
220
|
+
loaderId
|
|
221
|
+
]
|
|
222
|
+
});
|
|
223
|
+
loadersObject[loaderId] = data?.loaders[loaderId] ?? internal._UNINITIALIZED;
|
|
224
|
+
}
|
|
225
|
+
return loadersObject[loaderId];
|
|
226
|
+
}, {
|
|
227
|
+
container,
|
|
228
|
+
serializationStrategy
|
|
229
|
+
});
|
|
230
|
+
};
|
|
231
|
+
const clientNavigate = (win, navType, fromURL, toURL, replaceState = false) => {
|
|
232
|
+
if (navType !== "popstate") {
|
|
233
|
+
const samePath = isSamePath(fromURL, toURL);
|
|
234
|
+
const sameHash = fromURL.hash === toURL.hash;
|
|
235
|
+
if (!samePath || !sameHash) {
|
|
236
|
+
const newState = {
|
|
237
|
+
_qRouterScroll: newScrollState()
|
|
238
|
+
};
|
|
239
|
+
if (replaceState) {
|
|
240
|
+
win.history.replaceState(newState, "", toPath(toURL));
|
|
241
|
+
} else {
|
|
242
|
+
win.history.pushState(newState, "", toPath(toURL));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
const newScrollState = () => {
|
|
248
|
+
return {
|
|
249
|
+
x: 0,
|
|
250
|
+
y: 0,
|
|
251
|
+
w: 0,
|
|
252
|
+
h: 0
|
|
253
|
+
};
|
|
254
|
+
};
|
|
255
|
+
const prefetchSymbols = (path) => {
|
|
256
|
+
if (core.isBrowser) {
|
|
257
|
+
path = path.endsWith("/") ? path : path + "/";
|
|
258
|
+
path = path.length > 1 && path.startsWith("/") ? path.slice(1) : path;
|
|
259
|
+
preloader.p(path, 0.8);
|
|
260
|
+
}
|
|
261
|
+
};
|
|
230
262
|
const RouteStateContext = /* @__PURE__ */ core.createContextId("qc-s");
|
|
231
263
|
const ContentContext = /* @__PURE__ */ core.createContextId("qc-c");
|
|
232
264
|
const ContentInternalContext = /* @__PURE__ */ core.createContextId("qc-ic");
|
|
@@ -278,7 +310,7 @@ const Link = core.component$((props) => {
|
|
|
278
310
|
}
|
|
279
311
|
}
|
|
280
312
|
}) : void 0;
|
|
281
|
-
const preventDefault = clientNavPath ? core.sync$((event
|
|
313
|
+
const preventDefault = clientNavPath ? core.sync$((event) => {
|
|
282
314
|
if (!(event.metaKey || event.ctrlKey || event.shiftKey || event.altKey)) {
|
|
283
315
|
event.preventDefault();
|
|
284
316
|
}
|
|
@@ -508,18 +540,30 @@ function lastIndexOf(text, start, match, searchIdx, notFoundIdx) {
|
|
|
508
540
|
}
|
|
509
541
|
return idx > start ? idx : notFoundIdx;
|
|
510
542
|
}
|
|
543
|
+
var RouteDataProp = /* @__PURE__ */ function(RouteDataProp2) {
|
|
544
|
+
RouteDataProp2[RouteDataProp2["RouteName"] = 0] = "RouteName";
|
|
545
|
+
RouteDataProp2[RouteDataProp2["Loaders"] = 1] = "Loaders";
|
|
546
|
+
RouteDataProp2[RouteDataProp2["OriginalPathname"] = 2] = "OriginalPathname";
|
|
547
|
+
RouteDataProp2[RouteDataProp2["RouteBundleNames"] = 3] = "RouteBundleNames";
|
|
548
|
+
return RouteDataProp2;
|
|
549
|
+
}({});
|
|
550
|
+
var MenuDataProp = /* @__PURE__ */ function(MenuDataProp2) {
|
|
551
|
+
MenuDataProp2[MenuDataProp2["Pathname"] = 0] = "Pathname";
|
|
552
|
+
MenuDataProp2[MenuDataProp2["MenuLoader"] = 1] = "MenuLoader";
|
|
553
|
+
return MenuDataProp2;
|
|
554
|
+
}({});
|
|
511
555
|
const loadRoute = async (routes, menus, cacheModules, pathname) => {
|
|
512
556
|
if (!Array.isArray(routes)) {
|
|
513
557
|
return null;
|
|
514
558
|
}
|
|
515
559
|
for (const routeData of routes) {
|
|
516
|
-
const routeName = routeData[
|
|
560
|
+
const routeName = routeData[RouteDataProp.RouteName];
|
|
517
561
|
const params = matchRoute(routeName, pathname);
|
|
518
562
|
if (!params) {
|
|
519
563
|
continue;
|
|
520
564
|
}
|
|
521
|
-
const loaders = routeData[
|
|
522
|
-
const routeBundleNames = routeData[
|
|
565
|
+
const loaders = routeData[RouteDataProp.Loaders];
|
|
566
|
+
const routeBundleNames = routeData[RouteDataProp.RouteBundleNames];
|
|
523
567
|
const modules = new Array(loaders.length);
|
|
524
568
|
const pendingLoads = [];
|
|
525
569
|
loaders.forEach((moduleLoader, i) => {
|
|
@@ -564,9 +608,9 @@ const loadModule = (moduleLoader, pendingLoads, moduleSetter, cacheModules) => {
|
|
|
564
608
|
const getMenuLoader = (menus, pathname) => {
|
|
565
609
|
if (menus) {
|
|
566
610
|
pathname = pathname.endsWith("/") ? pathname : pathname + "/";
|
|
567
|
-
const menu = menus.find((m) => m[
|
|
611
|
+
const menu = menus.find((m) => m[MenuDataProp.Pathname] === pathname || pathname.startsWith(m[MenuDataProp.Pathname] + (pathname.endsWith("/") ? "" : "/")));
|
|
568
612
|
if (menu) {
|
|
569
|
-
return menu[
|
|
613
|
+
return menu[MenuDataProp.MenuLoader];
|
|
570
614
|
}
|
|
571
615
|
}
|
|
572
616
|
};
|
|
@@ -833,9 +877,23 @@ const QwikRouterProvider = core.component$((props) => {
|
|
|
833
877
|
deep: false
|
|
834
878
|
});
|
|
835
879
|
const navResolver = {};
|
|
836
|
-
const
|
|
837
|
-
|
|
838
|
-
|
|
880
|
+
const container = internal._getContextContainer();
|
|
881
|
+
const getSerializationStrategy = (loaderId) => {
|
|
882
|
+
return env.response.loadersSerializationStrategy.get(loaderId) || DEFAULT_LOADERS_SERIALIZATION_STRATEGY;
|
|
883
|
+
};
|
|
884
|
+
const loadersObject = {};
|
|
885
|
+
const loaderState = {};
|
|
886
|
+
for (const [key, value] of Object.entries(env.response.loaders)) {
|
|
887
|
+
loadersObject[key] = value;
|
|
888
|
+
loaderState[key] = createLoaderSignal(loadersObject, key, url, getSerializationStrategy(key), container);
|
|
889
|
+
}
|
|
890
|
+
loadersObject[internal.SerializerSymbol] = (obj) => {
|
|
891
|
+
const loadersSerializationObject = {};
|
|
892
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
893
|
+
loadersSerializationObject[k] = getSerializationStrategy(k) === "always" ? v : internal._UNINITIALIZED;
|
|
894
|
+
}
|
|
895
|
+
return loadersSerializationObject;
|
|
896
|
+
};
|
|
839
897
|
const routeInternal = core.useSignal({
|
|
840
898
|
type: "initial",
|
|
841
899
|
dest: url,
|
|
@@ -928,7 +986,7 @@ const QwikRouterProvider = core.component$((props) => {
|
|
|
928
986
|
let scroller = document.getElementById(QWIK_ROUTER_SCROLLER);
|
|
929
987
|
if (!scroller) {
|
|
930
988
|
scroller = document.getElementById(QWIK_CITY_SCROLLER);
|
|
931
|
-
if (scroller) {
|
|
989
|
+
if (scroller && core.isDev) {
|
|
932
990
|
console.warn(`Please update your scroller ID to "${QWIK_ROUTER_SCROLLER}" as "${QWIK_CITY_SCROLLER}" is deprecated and will be removed in V3`);
|
|
933
991
|
}
|
|
934
992
|
}
|
|
@@ -1069,11 +1127,21 @@ const QwikRouterProvider = core.component$((props) => {
|
|
|
1069
1127
|
document.__q_scroll_restore__ = () => restoreScroll(navType, trackUrl, prevUrl, scroller, scrollState);
|
|
1070
1128
|
}
|
|
1071
1129
|
const loaders = clientPageData?.loaders;
|
|
1072
|
-
const win = window;
|
|
1073
1130
|
if (loaders) {
|
|
1074
|
-
|
|
1131
|
+
const container2 = internal._getContextContainer();
|
|
1132
|
+
for (const [key, value] of Object.entries(loaders)) {
|
|
1133
|
+
const signal = loaderState[key];
|
|
1134
|
+
const awaitedValue = await value;
|
|
1135
|
+
loadersObject[key] = awaitedValue;
|
|
1136
|
+
if (!signal) {
|
|
1137
|
+
loaderState[key] = createLoaderSignal(loadersObject, key, trackUrl, DEFAULT_LOADERS_SERIALIZATION_STRATEGY, container2);
|
|
1138
|
+
} else {
|
|
1139
|
+
signal.invalidate();
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1075
1142
|
}
|
|
1076
1143
|
CLIENT_DATA_CACHE.clear();
|
|
1144
|
+
const win = window;
|
|
1077
1145
|
if (!win._qRouterSPA) {
|
|
1078
1146
|
win._qRouterSPA = true;
|
|
1079
1147
|
history.scrollRestoration = "manual";
|
|
@@ -1203,8 +1271,8 @@ const QwikRouterProvider = core.component$((props) => {
|
|
|
1203
1271
|
}
|
|
1204
1272
|
};
|
|
1205
1273
|
_waitNextPage().then(() => {
|
|
1206
|
-
const
|
|
1207
|
-
|
|
1274
|
+
const container2 = internal._getQContainerElement(elm);
|
|
1275
|
+
container2.setAttribute(Q_ROUTE, routeName);
|
|
1208
1276
|
const scrollState2 = currentScrollState(scroller);
|
|
1209
1277
|
saveScrollHistory(scrollState2);
|
|
1210
1278
|
win._qRouterScrollEnabled = true;
|
|
@@ -1237,7 +1305,7 @@ const QwikRouterMockProvider = core.component$((props) => {
|
|
|
1237
1305
|
}, {
|
|
1238
1306
|
deep: false
|
|
1239
1307
|
});
|
|
1240
|
-
const loaderState =
|
|
1308
|
+
const loaderState = {};
|
|
1241
1309
|
const routeInternal = core.useSignal({
|
|
1242
1310
|
type: "initial",
|
|
1243
1311
|
dest: url
|
|
@@ -1482,24 +1550,26 @@ const globalActionQrl = (actionQrl, ...rest) => {
|
|
|
1482
1550
|
const routeAction$ = /* @__PURE__ */ core.implicit$FirstArg(routeActionQrl);
|
|
1483
1551
|
const globalAction$ = /* @__PURE__ */ core.implicit$FirstArg(globalActionQrl);
|
|
1484
1552
|
const routeLoaderQrl = (loaderQrl, ...rest) => {
|
|
1485
|
-
const { id, validators } = getValidators(rest, loaderQrl);
|
|
1553
|
+
const { id, validators, serializationStrategy } = getValidators(rest, loaderQrl);
|
|
1486
1554
|
function loader() {
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1555
|
+
const iCtx = internal._useInvokeContext();
|
|
1556
|
+
const state = iCtx.$container$.resolveContext(iCtx.$hostElement$, RouteStateContext);
|
|
1557
|
+
if (!(id in state)) {
|
|
1558
|
+
throw new Error(`routeLoader$ "${loaderQrl.getSymbol()}" was invoked in a route where it was not declared.
|
|
1490
1559
|
This is because the routeLoader$ was not exported in a 'layout.tsx' or 'index.tsx' file of the existing route.
|
|
1491
1560
|
For more information check: https://qwik.dev/docs/route-loader/
|
|
1492
1561
|
|
|
1493
1562
|
If your are managing reusable logic or a library it is essential that this function is re-exported from within 'layout.tsx' or 'index.tsx file of the existing route otherwise it will not run or throw exception.
|
|
1494
1563
|
For more information check: https://qwik.dev/docs/re-exporting-loaders/`);
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1564
|
+
}
|
|
1565
|
+
core.untrack(() => state[id].value);
|
|
1566
|
+
return state[id];
|
|
1498
1567
|
}
|
|
1499
1568
|
loader.__brand = "server_loader";
|
|
1500
1569
|
loader.__qrl = loaderQrl;
|
|
1501
1570
|
loader.__validators = validators;
|
|
1502
1571
|
loader.__id = id;
|
|
1572
|
+
loader.__serializationStrategy = serializationStrategy;
|
|
1503
1573
|
Object.freeze(loader);
|
|
1504
1574
|
return loader;
|
|
1505
1575
|
};
|
|
@@ -1728,6 +1798,7 @@ const serverQrl = (qrl, options) => {
|
|
|
1728
1798
|
const server$ = /* @__PURE__ */ core.implicit$FirstArg(serverQrl);
|
|
1729
1799
|
const getValidators = (rest, qrl) => {
|
|
1730
1800
|
let id;
|
|
1801
|
+
let serializationStrategy = DEFAULT_LOADERS_SERIALIZATION_STRATEGY;
|
|
1731
1802
|
const validators = [];
|
|
1732
1803
|
if (rest.length === 1) {
|
|
1733
1804
|
const options = rest[0];
|
|
@@ -1736,6 +1807,9 @@ const getValidators = (rest, qrl) => {
|
|
|
1736
1807
|
validators.push(options);
|
|
1737
1808
|
} else {
|
|
1738
1809
|
id = options.id;
|
|
1810
|
+
if (options.serializationStrategy) {
|
|
1811
|
+
serializationStrategy = options.serializationStrategy;
|
|
1812
|
+
}
|
|
1739
1813
|
if (options.validation) {
|
|
1740
1814
|
validators.push(...options.validation);
|
|
1741
1815
|
}
|
|
@@ -1756,7 +1830,8 @@ const getValidators = (rest, qrl) => {
|
|
|
1756
1830
|
}
|
|
1757
1831
|
return {
|
|
1758
1832
|
validators: validators.reverse(),
|
|
1759
|
-
id
|
|
1833
|
+
id,
|
|
1834
|
+
serializationStrategy
|
|
1760
1835
|
};
|
|
1761
1836
|
};
|
|
1762
1837
|
const deserializeStream = async function* (stream, ctxElm, abortSignal) {
|