Skip to content

Commit 6d61cf6

Browse files
committed
feat: use custom serialization
1 parent 377de9a commit 6d61cf6

File tree

13 files changed

+108
-96
lines changed

13 files changed

+108
-96
lines changed

packages/qwik-router/src/middleware/request-handler/request-event.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import type { ValueOrPromise } from '@qwik.dev/core';
22
import type { QwikManifest, ResolvedManifest } from '@qwik.dev/core/optimizer';
33
import { QDATA_KEY } from '../../runtime/src/constants';
4-
import type {
5-
ActionInternal,
6-
FailReturn,
7-
JSONValue,
8-
LoadedRoute,
9-
LoaderInternal,
4+
import {
5+
LoadedRouteProp,
6+
type ActionInternal,
7+
type FailReturn,
8+
type JSONValue,
9+
type LoadedRoute,
10+
type LoaderInternal,
1011
} from '../../runtime/src/types';
1112
import { isPromise } from '../../runtime/src/utils';
1213
import { createCacheControl } from './cache-control';
@@ -149,7 +150,7 @@ export function createRequestEvent(
149150
env,
150151
method: request.method,
151152
signal: request.signal,
152-
params: loadedRoute?.[1] ?? {},
153+
params: loadedRoute?.[LoadedRouteProp.Params] ?? {},
153154
pathname: url.pathname,
154155
platform,
155156
query: url.searchParams,

packages/qwik-router/src/middleware/request-handler/resolve-request-handlers.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import type { QRL } from '@qwik.dev/core';
1+
import { type QRL } from '@qwik.dev/core';
2+
import { SerializerSymbol, _UNINITIALIZED } from '@qwik.dev/core/internal';
23
import type { Render, RenderToStringResult } from '@qwik.dev/core/server';
34
import { QACTION_KEY, QFN_KEY, QLOADER_KEY } from '../../runtime/src/constants';
45
import {
@@ -30,7 +31,6 @@ import {
3031
import { getQwikRouterServerData } from './response-page';
3132
import type { QwikSerializer, RequestEvent, RequestEventBase, RequestHandler } from './types';
3233
import { IsQData, QDATA_JSON } from './user-response';
33-
import { _UNINITIALIZED } from '@qwik.dev/core/internal';
3434

3535
export const resolveRequestHandlers = (
3636
serverPlugins: RouteModule[] | undefined,
@@ -595,6 +595,9 @@ export async function renderQData(requestEv: RequestEvent) {
595595
const loaders: Record<string, unknown> = {};
596596
for (const loaderId in allLoaders) {
597597
const loader = allLoaders[loaderId];
598+
if (typeof loader === 'object' && loader !== null && SerializerSymbol in loader) {
599+
delete (loader as any)[SerializerSymbol];
600+
}
598601
if (loader !== _UNINITIALIZED) {
599602
loaders[loaderId] = loader;
600603
}

packages/qwik-router/src/middleware/request-handler/response-page.ts

+20-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { SerializerSymbol } from '@qwik.dev/core';
2+
import { _UNINITIALIZED } from '@qwik.dev/core/internal';
13
import type { QwikRouterEnvData } from '../../runtime/src/types';
24
import {
35
getRequestLoaders,
@@ -8,6 +10,7 @@ import {
810
RequestRouteName,
911
} from './request-event';
1012
import type { RequestEvent } from './types';
13+
import { Q_ROUTE } from '../../runtime/src/constants';
1114

1215
export function getQwikRouterServerData(requestEv: RequestEvent) {
1316
const { url, params, request, status, locale } = requestEv;
@@ -30,13 +33,28 @@ export function getQwikRouterServerData(requestEv: RequestEvent) {
3033
reconstructedUrl.protocol = protocol;
3134
}
3235

36+
const loaders = getRequestLoaders(requestEv);
37+
38+
// shallow serialize loaders data
39+
(loaders as any)[SerializerSymbol] = (loaders: Record<string, unknown>) => {
40+
const result: Record<string, unknown> = {};
41+
for (const key in loaders) {
42+
const loader = loaders[key];
43+
if (typeof loader === 'object' && loader !== null) {
44+
(loader as any)[SerializerSymbol] = () => _UNINITIALIZED;
45+
}
46+
result[key] = _UNINITIALIZED;
47+
}
48+
return result;
49+
};
50+
3351
return {
3452
url: reconstructedUrl.href,
3553
requestHeaders,
3654
locale: locale(),
3755
nonce,
3856
containerAttributes: {
39-
'q:route': routeName,
57+
[Q_ROUTE]: routeName,
4058
},
4159
qwikrouter: {
4260
routeName,
@@ -45,7 +63,7 @@ export function getQwikRouterServerData(requestEv: RequestEvent) {
4563
loadedRoute: getRequestRoute(requestEv),
4664
response: {
4765
status: status(),
48-
loaders: getRequestLoaders(requestEv),
66+
loaders,
4967
action,
5068
formData,
5169
},

packages/qwik-router/src/runtime/src/constants.ts

+2
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,5 @@ export const QLOADER_KEY = 'qloader';
1313
export const QFN_KEY = 'qfunc';
1414

1515
export const QDATA_KEY = 'qdata';
16+
17+
export const Q_ROUTE = 'q:route';

packages/qwik-router/src/runtime/src/qwik-router-component.tsx

+3-4
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,10 @@ import {
2020
_getContextElement,
2121
_getQContainerElement,
2222
_waitUntilRendered,
23-
_weakSerialize,
2423
type _ElementVNode,
2524
} from '@qwik.dev/core/internal';
2625
import { clientNavigate } from './client-navigate';
27-
import { CLIENT_DATA_CACHE } from './constants';
26+
import { CLIENT_DATA_CACHE, Q_ROUTE } from './constants';
2827
import {
2928
ContentContext,
3029
ContentInternalContext,
@@ -146,7 +145,7 @@ export const QwikRouterProvider = component$<QwikRouterProps>((props) => {
146145
{ deep: false }
147146
);
148147
const navResolver: { r?: () => void } = {};
149-
const loaderState = useStore(_weakSerialize(env.response.loaders), { deep: false });
148+
const loaderState = useStore(env.response.loaders, { deep: false });
150149
const routeInternal = useSignal<RouteStateInternal>({
151150
type: 'initial',
152151
dest: url,
@@ -641,7 +640,7 @@ export const QwikRouterProvider = component$<QwikRouterProps>((props) => {
641640
clientNavigate(window, navType, prevUrl, trackUrl, replaceState);
642641
_waitUntilRendered(elm as Element).then(() => {
643642
const container = _getQContainerElement(elm as _ElementVNode)!;
644-
container.setAttribute('q:route', routeName);
643+
container.setAttribute(Q_ROUTE, routeName);
645644
const scrollState = currentScrollState(scroller);
646645
saveScrollHistory(scrollState);
647646
win._qRouterScrollEnabled = true;

packages/qwik-router/src/runtime/src/server-functions.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ import {
77
type ValueOrPromise,
88
untrack,
99
isBrowser,
10+
isDev,
11+
isServer,
1012
} from '@qwik.dev/core';
1113
import {
1214
_deserialize,
1315
_getContextElement,
1416
_getContextEvent,
1517
_serialize,
1618
_wrapStore,
19+
_useInvokeContext,
1720
_UNINITIALIZED,
1821
} from '@qwik.dev/core/internal';
1922

@@ -54,9 +57,6 @@ import type {
5457
} from './types';
5558
import { useAction, useLocation, useQwikRouterEnv } from './use-functions';
5659

57-
import { isDev, isServer } from '@qwik.dev/core';
58-
import { _useInvokeContext } from '@qwik.dev/core/internal';
59-
6060
import type { FormSubmitCompletedDetail } from './form-component';
6161
import { deepFreeze } from './utils';
6262
import { loadClientData } from './use-endpoint';

packages/qwik-router/src/runtime/src/utils.ts

+7-12
Original file line numberDiff line numberDiff line change
@@ -36,21 +36,16 @@ export const getClientDataPath = (
3636
loaderIds?: string[];
3737
}
3838
) => {
39-
const search = new URLSearchParams(pageSearch);
39+
let search = pageSearch ?? '';
4040
if (options?.actionId) {
41-
search.set(QACTION_KEY, options.actionId);
42-
} else if (options?.loaderIds) {
43-
for (const id of options.loaderIds) {
44-
search.append(QLOADER_KEY, id);
41+
search += (search ? '&' : '?') + QACTION_KEY + '=' + encodeURIComponent(options.actionId);
42+
}
43+
if (options?.loaderIds) {
44+
for (const loaderId of options.loaderIds) {
45+
search += (search ? '&' : '?') + QLOADER_KEY + '=' + encodeURIComponent(loaderId);
4546
}
4647
}
47-
const searchString = search.toString();
48-
return (
49-
pathname +
50-
(pathname.endsWith('/') ? '' : '/') +
51-
'q-data.json' +
52-
(searchString.length ? '?' + searchString : '')
53-
);
48+
return pathname + (pathname.endsWith('/') ? '' : '/') + 'q-data.json' + search;
5449
};
5550

5651
export const getClientNavPath = (props: Record<string, any>, baseUrl: { url: URL }) => {

packages/qwik/src/core/api.md

+37-8
Original file line numberDiff line numberDiff line change
@@ -244,11 +244,9 @@ export class _EffectData {
244244
data: NodePropData;
245245
}
246246

247-
// Warning: (ae-forgotten-export) The symbol "VNodeFlags" needs to be exported by the entry point index.d.ts
248-
//
249247
// @internal (undocumented)
250248
export type _ElementVNode = [
251-
VNodeFlags.Element,
249+
_VNodeFlags.Element,
252250
////////////// 0 - Flags
253251
_VNode | null,
254252
/////////////// 1 - Parent
@@ -1568,7 +1566,7 @@ export type TaskFn = (ctx: TaskCtx) => ValueOrPromise<void | (() => void)>;
15681566

15691567
// @internal (undocumented)
15701568
export type _TextVNode = [
1571-
VNodeFlags.Text | VNodeFlags.Inflated,
1569+
_VNodeFlags.Text | _VNodeFlags.Inflated,
15721570
// 0 - Flags
15731571
_VNode | null,
15741572
///////////////// 1 - Parent
@@ -1740,7 +1738,7 @@ export const version: string;
17401738

17411739
// @internal (undocumented)
17421740
export type _VirtualVNode = [
1743-
VNodeFlags.Virtual,
1741+
_VNodeFlags.Virtual,
17441742
///////////// 0 - Flags
17451743
_VNode | null,
17461744
/////////////// 1 - Parent
@@ -1762,6 +1760,40 @@ export type VisibleTaskStrategy = 'intersection-observer' | 'document-ready' | '
17621760
// @internal (undocumented)
17631761
export type _VNode = _ElementVNode | _TextVNode | _VirtualVNode;
17641762

1763+
// @internal
1764+
export const enum _VNodeFlags {
1765+
// (undocumented)
1766+
Deleted = 32,
1767+
// (undocumented)
1768+
Element = 1,
1769+
// (undocumented)
1770+
ELEMENT_OR_TEXT_MASK = 5,
1771+
// (undocumented)
1772+
ELEMENT_OR_VIRTUAL_MASK = 3,
1773+
// (undocumented)
1774+
Inflated = 8,
1775+
// (undocumented)
1776+
INFLATED_TYPE_MASK = 15,
1777+
// (undocumented)
1778+
NAMESPACE_MASK = 192,
1779+
// (undocumented)
1780+
NEGATED_NAMESPACE_MASK = -193,
1781+
// (undocumented)
1782+
NS_html = 0,
1783+
// (undocumented)
1784+
NS_math = 128,
1785+
// (undocumented)
1786+
NS_svg = 64,
1787+
// (undocumented)
1788+
Resolved = 16,
1789+
// (undocumented)
1790+
Text = 4,// http://www.w3.org/1999/xhtml
1791+
// (undocumented)
1792+
TYPE_MASK = 7,// http://www.w3.org/2000/svg
1793+
// (undocumented)
1794+
Virtual = 2
1795+
}
1796+
17651797
// @internal (undocumented)
17661798
export const _waitUntilRendered: (elm: Element) => Promise<void>;
17671799

@@ -1773,9 +1805,6 @@ export function _walkJSX(ssr: SSRContainer, value: JSXOutput, options: {
17731805
parentComponentFrame: ISsrComponentFrame | null;
17741806
}): Promise<void>;
17751807

1776-
// @internal (undocumented)
1777-
export const _weakSerialize: <T extends object>(input: T) => Partial<T>;
1778-
17791808
// @public
17801809
export function withLocale<T>(locale: string, fn: () => T): T;
17811810

packages/qwik/src/core/internal.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ export { _wrapSignal, _wrapProp, _wrapStore } from './signal/signal-utils';
77
export { _restProps } from './shared/utils/prop';
88
export { _IMMUTABLE, _UNINITIALIZED } from './shared/utils/constants';
99
export { _CONST_PROPS, _VAR_PROPS } from './shared/utils/constants';
10-
export { _weakSerialize } from './shared/utils/serialize-utils';
1110
export { verifySerializable as _verifySerializable } from './shared/utils/serialize-utils';
1211
export {
1312
_getContextElement,
@@ -21,6 +20,7 @@ export { _fnSignal } from './shared/qrl/inlined-fn';
2120
export type {
2221
ContainerElement as _ContainerElement,
2322
VNode as _VNode,
23+
VNodeFlags as _VNodeFlags,
2424
VirtualVNode as _VirtualVNode,
2525
TextVNode as _TextVNode,
2626
QDocument as _QDocument,

packages/qwik/src/core/shared/shared-serialization.ts

+3-25
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ import { isElement, isNode } from './utils/element';
5656
import { EMPTY_ARRAY, EMPTY_OBJ } from './utils/flyweight';
5757
import { ELEMENT_ID } from './utils/markers';
5858
import { isPromise } from './utils/promises';
59-
import { SerializerSymbol, fastSkipSerialize, fastWeakSerialize } from './utils/serialize-utils';
59+
import { SerializerSymbol, fastSkipSerialize } from './utils/serialize-utils';
6060
import { type ValueOrPromise } from './utils/types';
6161

6262
const deserializedProxyMap = new WeakMap<object, unknown[]>();
@@ -400,16 +400,6 @@ const inflate = (
400400
effectData.data.$isConst$ = (data as any[])[1];
401401
break;
402402
}
403-
case TypeIds.WeakObject: {
404-
const objectKeys = data as string[];
405-
target = Object.fromEntries(
406-
objectKeys.map((v) =>
407-
// initialize values with null
408-
[v, _UNINITIALIZED]
409-
)
410-
);
411-
break;
412-
}
413403
default:
414404
throw qError(QError.serializeErrorNotImplemented, [typeId]);
415405
}
@@ -472,7 +462,6 @@ const allocate = (container: DeserializeContainer, typeId: number, value: unknow
472462
case TypeIds.Array:
473463
return wrapDeserializerProxy(container as any, value as any[]);
474464
case TypeIds.Object:
475-
case TypeIds.WeakObject:
476465
return {};
477466
case TypeIds.QRL:
478467
const qrl = container.$getObjectById$(value as number);
@@ -827,20 +816,15 @@ export const createSerializationContext = (
827816
vnode_isVNode(obj) ||
828817
(typeof FormData !== 'undefined' && obj instanceof FormData) ||
829818
// Ignore the no serialize objects
830-
fastSkipSerialize(obj as object) ||
831-
// only keys will be serialized
832-
fastWeakSerialize(obj)
819+
fastSkipSerialize(obj as object)
833820
) {
834821
// ignore
835822
} else if (obj instanceof Error) {
836823
discoveredValues.push(...Object.values(obj));
837824
} else if (isStore(obj)) {
838825
const target = getStoreTarget(obj)!;
839826
const effects = getStoreHandler(obj)!.$effects$;
840-
if (!fastWeakSerialize(target)) {
841-
discoveredValues.push(target);
842-
}
843-
discoveredValues.push(effects);
827+
discoveredValues.push(target, effects);
844828

845829
for (const prop in target) {
846830
const propValue = (target as any)[prop];
@@ -936,8 +920,6 @@ export const createSerializationContext = (
936920
}
937921
);
938922
promises.push(obj);
939-
} else if (obj instanceof SubscriptionData) {
940-
discoveredValues.push(obj.data);
941923
} else if (Array.isArray(obj)) {
942924
discoveredValues.push(...obj);
943925
} else if (isSerializerObj(obj)) {
@@ -1225,8 +1207,6 @@ function serialize(serializationContext: SerializationContext): void {
12251207
} else if (isObjectLiteral(value)) {
12261208
if (Array.isArray(value)) {
12271209
output(TypeIds.Array, value);
1228-
} else if (fastWeakSerialize(value)) {
1229-
output(TypeIds.WeakObject, Object.keys(value));
12301210
} else {
12311211
const out: any[] = [];
12321212
for (const key in value) {
@@ -1744,7 +1724,6 @@ export const enum TypeIds {
17441724
JSXNode,
17451725
PropsProxy,
17461726
SubscriptionData,
1747-
WeakObject,
17481727
}
17491728
export const _typeIdNames = [
17501729
'RootRef',
@@ -1779,7 +1758,6 @@ export const _typeIdNames = [
17791758
'JSXNode',
17801759
'PropsProxy',
17811760
'SubscriptionData',
1782-
'WeakObject',
17831761
];
17841762

17851763
export const enum Constants {

0 commit comments

Comments
 (0)