Skip to content

Commit c091b65

Browse files
Varixowmertens
andcommitted
WIP: serialization weak ref
Co-authored-by: Wout Mertens <Wout.Mertens@gmail.com>
1 parent 564057c commit c091b65

File tree

15 files changed

+181
-532
lines changed

15 files changed

+181
-532
lines changed

eslint.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ export default tseslint.config(
109109
},
110110
},
111111
{
112-
files: ['packages/docs/**/*.{ts,tsx}'],
112+
files: ['packages/docs/demo/**/*.{ts,tsx}'],
113113
rules: {
114114
'no-console': 'off',
115115
},

packages/docs/src/routes/api/qwik/api.json

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -672,20 +672,6 @@
672672
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/jsx/jsx-runtime.ts",
673673
"mdFile": "core.h.md"
674674
},
675-
{
676-
"name": "HTMLElementAttrs",
677-
"id": "htmlelementattrs",
678-
"hierarchy": [
679-
{
680-
"name": "HTMLElementAttrs",
681-
"id": "htmlelementattrs"
682-
}
683-
],
684-
"kind": "Interface",
685-
"content": "```typescript\nexport interface HTMLElementAttrs extends HTMLAttributesBase, FilterBase<HTMLElement> \n```\n**Extends:** HTMLAttributesBase, FilterBase&lt;HTMLElement&gt;",
686-
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/jsx/types/jsx-generated.ts",
687-
"mdFile": "core.htmlelementattrs.md"
688-
},
689675
{
690676
"name": "implicit$FirstArg",
691677
"id": "implicit_firstarg",
@@ -1318,7 +1304,7 @@
13181304
}
13191305
],
13201306
"kind": "TypeAlias",
1321-
"content": "The DOM props without plain handlers, for use inside functions\n\n\n```typescript\nexport type QwikHTMLElements = {\n [tag in keyof HTMLElementTagNameMap]: Augmented<HTMLElementTagNameMap[tag], SpecialAttrs[tag]> & HTMLElementAttrs & QwikAttributes<HTMLElementTagNameMap[tag]>;\n};\n```\n**References:** [HTMLElementAttrs](#htmlelementattrs)<!-- -->, [QwikAttributes](#qwikattributes)",
1307+
"content": "The DOM props without plain handlers, for use inside functions\n\n\n```typescript\nexport type QwikHTMLElements = {\n [tag in keyof HTMLElementTagNameMap]: Augmented<HTMLElementTagNameMap[tag], SpecialAttrs[tag]> & HTMLElementAttrs & QwikAttributes<HTMLElementTagNameMap[tag]>;\n};\n```\n**References:** [QwikAttributes](#qwikattributes)",
13221308
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/jsx/types/jsx-generated.ts",
13231309
"mdFile": "core.qwikhtmlelements.md"
13241310
},
@@ -1458,7 +1444,7 @@
14581444
}
14591445
],
14601446
"kind": "TypeAlias",
1461-
"content": "The SVG props without plain handlers, for use inside functions\n\n\n```typescript\nexport type QwikSVGElements = {\n [K in keyof Omit<SVGElementTagNameMap, keyof HTMLElementTagNameMap>]: SVGProps<SVGElementTagNameMap[K]>;\n};\n```\n**References:** [SVGProps](#svgprops)",
1447+
"content": "The SVG props without plain handlers, for use inside functions\n\n\n```typescript\nexport type QwikSVGElements = {\n [K in keyof Omit<SVGElementTagNameMap, keyof HTMLElementTagNameMap>]: SVGProps<SVGElementTagNameMap[K]>;\n};\n```",
14621448
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/jsx/types/jsx-generated.ts",
14631449
"mdFile": "core.qwiksvgelements.md"
14641450
},
@@ -2008,20 +1994,6 @@
20081994
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/jsx/types/jsx-generated.ts",
20091995
"mdFile": "core.svgattributes.md"
20101996
},
2011-
{
2012-
"name": "SVGProps",
2013-
"id": "svgprops",
2014-
"hierarchy": [
2015-
{
2016-
"name": "SVGProps",
2017-
"id": "svgprops"
2018-
}
2019-
],
2020-
"kind": "Interface",
2021-
"content": "```typescript\nexport interface SVGProps<T extends Element> extends SVGAttributes, QwikAttributes<T> \n```\n**Extends:** [SVGAttributes](#svgattributes)<!-- -->, [QwikAttributes](#qwikattributes)<!-- -->&lt;T&gt;",
2022-
"editUrl": "https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/jsx/types/jsx-generated.ts",
2023-
"mdFile": "core.svgprops.md"
2024-
},
20251997
{
20261998
"name": "sync$",
20271999
"id": "sync_",

packages/docs/src/routes/api/qwik/index.mdx

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,16 +1333,6 @@ any[]
13331333
13341334
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/jsx/jsx-runtime.ts)
13351335
1336-
## HTMLElementAttrs
1337-
1338-
```typescript
1339-
export interface HTMLElementAttrs extends HTMLAttributesBase, FilterBase<HTMLElement>
1340-
```
1341-
1342-
**Extends:** HTMLAttributesBase, FilterBase&lt;HTMLElement&gt;
1343-
1344-
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/jsx/types/jsx-generated.ts)
1345-
13461336
## implicit$FirstArg
13471337
13481338
Create a `____$(...)` convenience method from `___(...)`.
@@ -2586,7 +2576,7 @@ export type QwikHTMLElements = {
25862576
};
25872577
```
25882578
2589-
**References:** [HTMLElementAttrs](#htmlelementattrs), [QwikAttributes](#qwikattributes)
2579+
**References:** [QwikAttributes](#qwikattributes)
25902580
25912581
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/jsx/types/jsx-generated.ts)
25922582
@@ -2784,8 +2774,6 @@ export type QwikSVGElements = {
27842774
};
27852775
```
27862776
2787-
**References:** [SVGProps](#svgprops)
2788-
27892777
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/jsx/types/jsx-generated.ts)
27902778
27912779
## QwikSymbolEvent
@@ -8121,16 +8109,6 @@ _(Optional)_
81218109
81228110
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/jsx/types/jsx-generated.ts)
81238111
8124-
## SVGProps
8125-
8126-
```typescript
8127-
export interface SVGProps<T extends Element> extends SVGAttributes, QwikAttributes<T>
8128-
```
8129-
8130-
**Extends:** [SVGAttributes](#svgattributes), [QwikAttributes](#qwikattributes)&lt;T&gt;
8131-
8132-
[Edit this section](https://github.com/QwikDev/qwik/tree/main/packages/qwik/src/core/shared/jsx/types/jsx-generated.ts)
8133-
81348112
## sync$
81358113
81368114
Extract function into a synchronously loadable QRL.

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

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { type QRL } from '@qwik.dev/core';
2-
import { SerializerSymbol, _UNINITIALIZED } from '@qwik.dev/core/internal';
32
import type { Render, RenderToStringResult } from '@qwik.dev/core/server';
43
import { QACTION_KEY, QFN_KEY, QLOADER_KEY } from '../../runtime/src/constants';
54
import {
@@ -598,9 +597,6 @@ export async function renderQData(requestEv: RequestEvent) {
598597
for (const loaderId in allLoaders) {
599598
const loader = allLoaders[loaderId];
600599
if (loader !== null) {
601-
if (typeof loader === 'object' && SerializerSymbol in loader) {
602-
(loader as any)[SerializerSymbol] = undefined;
603-
}
604600
loaders[loaderId] = loader;
605601
}
606602
}

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

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { SerializerSymbol } from '@qwik.dev/core';
2-
import { _UNINITIALIZED } from '@qwik.dev/core/internal';
31
import type { QwikRouterEnvData } from '../../runtime/src/types';
42
import {
53
getRequestLoaders,
@@ -35,14 +33,6 @@ export function getQwikRouterServerData(requestEv: RequestEvent) {
3533

3634
const loaders = getRequestLoaders(requestEv);
3735

38-
// shallow serialize loaders data
39-
for (const key in loaders) {
40-
const loader = loaders[key];
41-
if (typeof loader === 'object' && loader !== null) {
42-
(loader as any)[SerializerSymbol] = () => _UNINITIALIZED;
43-
}
44-
}
45-
4636
return {
4737
url: reconstructedUrl.href,
4838
requestHeaders,

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ import type {
1010
RouteStateInternal,
1111
} from './types';
1212

13-
export const RouteStateContext = /*#__PURE__*/ createContextId<Record<string, any>>('qc-s');
13+
export const RouteStateContext =
14+
/*#__PURE__*/ createContextId<Record<string, Signal<unknown>>>('qc-s');
1415

1516
export const ContentContext = /*#__PURE__*/ createContextId<ContentState>('qc-c');
1617
export const ContentInternalContext =

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

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,13 @@ import {
1919
import {
2020
_getContextElement,
2121
_getQContainerElement,
22+
_UNINITIALIZED,
2223
_waitUntilRendered,
24+
SerializerSymbol,
25+
_serializationWeakRef,
2326
type _ElementVNode,
27+
createSignal,
28+
type Signal,
2429
} from '@qwik.dev/core/internal';
2530
import { clientNavigate } from './client-navigate';
2631
import { CLIENT_DATA_CACHE, Q_ROUTE } from './constants';
@@ -145,7 +150,21 @@ export const QwikRouterProvider = component$<QwikRouterProps>((props) => {
145150
{ deep: false }
146151
);
147152
const navResolver: { r?: () => void } = {};
148-
const loaderState = useStore(env.response.loaders, { deep: false });
153+
const loaderState = Object.fromEntries(
154+
Object.entries(env.response.loaders).map(([k, v]) => {
155+
const value = createSignal(v);
156+
return [k, value];
157+
})
158+
);
159+
160+
(loaderState as any)[SerializerSymbol] = async (o: Record<string, unknown>) => {
161+
const resultPs = Object.entries(o).map(async ([k, val]) => {
162+
const v = await val;
163+
return [k, _serializationWeakRef(v)];
164+
});
165+
return Object.fromEntries(await Promise.all(resultPs));
166+
};
167+
149168
const routeInternal = useSignal<RouteStateInternal>({
150169
type: 'initial',
151170
dest: url,
@@ -278,7 +297,7 @@ export const QwikRouterProvider = component$<QwikRouterProps>((props) => {
278297
let scroller = document.getElementById(QWIK_ROUTER_SCROLLER);
279298
if (!scroller) {
280299
scroller = document.getElementById(QWIK_CITY_SCROLLER);
281-
if (scroller) {
300+
if (scroller && isDev) {
282301
console.warn(
283302
`Please update your scroller ID to "${QWIK_ROUTER_SCROLLER}" as "${QWIK_CITY_SCROLLER}" is deprecated and will be removed in V3`
284303
);
@@ -460,12 +479,17 @@ export const QwikRouterProvider = component$<QwikRouterProps>((props) => {
460479
}
461480

462481
const loaders = clientPageData?.loaders;
463-
const win = window as ClientSPAWindow;
464482
if (loaders) {
465-
Object.assign(loaderState, loaders);
483+
for (const [key, value] of Object.entries(loaders)) {
484+
const signal = loaderState[key] as Signal<unknown> | typeof _UNINITIALIZED;
485+
if (signal && signal !== _UNINITIALIZED) {
486+
signal.value = value;
487+
}
488+
}
466489
}
467490
CLIENT_DATA_CACHE.clear();
468491

492+
const win = window as ClientSPAWindow;
469493
if (!win._qRouterSPA) {
470494
// only add event listener once
471495
win._qRouterSPA = true;
@@ -698,7 +722,7 @@ export const QwikRouterMockProvider = component$<QwikRouterMockProps>((props) =>
698722
{ deep: false }
699723
);
700724

701-
const loaderState = useSignal({});
725+
const loaderState = {};
702726
const routeInternal = useSignal<RouteStateInternal>({ type: 'initial', dest: url });
703727

704728
const goto: RouteNavigate =

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ import {
1515
_getContextElement,
1616
_getContextEvent,
1717
_serialize,
18-
_wrapStore,
1918
_useInvokeContext,
2019
_UNINITIALIZED,
2120
} from '@qwik.dev/core/internal';
@@ -209,15 +208,17 @@ export const routeLoaderQrl = ((
209208
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.
210209
For more information check: https://qwik.dev/docs/re-exporting-loaders/`);
211210
}
212-
const data = untrack(() => state[id]);
213-
if (data === _UNINITIALIZED && isBrowser) {
211+
const loaderData = untrack(() => state[id].value);
212+
if (loaderData === _UNINITIALIZED && isBrowser) {
213+
// Request the loader data from the server and throw the Promise
214+
// so the client can load it synchronously.
214215
throw loadClientData(location.url, iCtx.$hostElement$, {
215216
loaderIds: [id],
216-
}).then((data) => {
217-
state[id] = data?.loaders[id];
217+
}).then((clientData) => {
218+
state[id].value = clientData?.loaders[id];
218219
});
219220
}
220-
return _wrapStore(state, id);
221+
return state[id];
221222
}
222223
loader.__brand = 'server_loader' as const;
223224
loader.__qrl = loaderQrl;

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,7 @@ export type GetValidatorType<VALIDATOR extends TypedDataValidator> =
401401
export interface CommonLoaderActionOptions {
402402
readonly id?: string;
403403
readonly validation?: DataValidator[];
404+
readonly persist?: boolean;
404405
}
405406

406407
/** @public */

packages/qwik/src/core/index.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,8 +85,6 @@ export type {
8585
QwikHTMLElements,
8686
QwikSVGElements,
8787
SVGAttributes,
88-
HTMLElementAttrs,
89-
SVGProps,
9088
} from './shared/jsx/types/jsx-generated';
9189
export { render } from './client/dom-render';
9290
export { getDomContainer, _getQContainerElement } from './client/dom-container';

packages/qwik/src/core/internal.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export type {
1616
VNodeFlags as _VNodeFlags,
1717
} from './client/types';
1818
export { vnode_toString as _vnode_toString } from './client/vnode';
19-
export { _wrapProp, _wrapSignal, _wrapStore } from './reactive-primitives/internal-api';
19+
export { _wrapProp, _wrapSignal } from './reactive-primitives/internal-api';
2020
export { SubscriptionData as _SubscriptionData } from './reactive-primitives/subscription-data';
2121
export { _EFFECT_BACK_REF } from './reactive-primitives/types';
2222
export {
@@ -37,6 +37,7 @@ export {
3737
_deserialize,
3838
dumpState as _dumpState,
3939
preprocessState as _preprocessState,
40+
_serializationWeakRef,
4041
_serialize,
4142
} from './shared/shared-serialization';
4243
export { _CONST_PROPS, _IMMUTABLE, _VAR_PROPS, _UNINITIALIZED } from './shared/utils/constants';

packages/qwik/src/core/qwik.core.api.md

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -336,13 +336,6 @@ function h<TYPE extends string | FunctionComponent<PROPS>, PROPS extends {} = {}
336336
export { h as createElement }
337337
export { h }
338338

339-
// Warning: (ae-forgotten-export) The symbol "HTMLAttributesBase" needs to be exported by the entry point index.d.ts
340-
// Warning: (ae-forgotten-export) The symbol "FilterBase" needs to be exported by the entry point index.d.ts
341-
//
342-
// @public (undocumented)
343-
export interface HTMLElementAttrs extends HTMLAttributesBase, FilterBase<HTMLElement> {
344-
}
345-
346339
// @internal @deprecated (undocumented)
347340
export const _IMMUTABLE: unique symbol;
348341

@@ -637,6 +630,7 @@ export type QwikFocusEvent<T = Element> = NativeFocusEvent;
637630

638631
// Warning: (ae-forgotten-export) The symbol "Augmented" needs to be exported by the entry point index.d.ts
639632
// Warning: (ae-forgotten-export) The symbol "SpecialAttrs" needs to be exported by the entry point index.d.ts
633+
// Warning: (ae-forgotten-export) The symbol "HTMLElementAttrs" needs to be exported by the entry point index.d.ts
640634
//
641635
// @public
642636
export type QwikHTMLElements = {
@@ -693,6 +687,8 @@ export type QwikPointerEvent<T = Element> = NativePointerEvent;
693687
// @public @deprecated (undocumented)
694688
export type QwikSubmitEvent<T = Element> = SubmitEvent;
695689

690+
// Warning: (ae-forgotten-export) The symbol "SVGProps" needs to be exported by the entry point index.d.ts
691+
//
696692
// @public
697693
export type QwikSVGElements = {
698694
[K in keyof Omit<SVGElementTagNameMap, keyof HTMLElementTagNameMap>]: SVGProps<SVGElementTagNameMap[K]>;
@@ -842,6 +838,11 @@ export const _restProps: (props: PropsProxy, omit: string[], target?: Props) =>
842838
// @internal
843839
export const _run: (...args: unknown[]) => ValueOrPromise_2<void>;
844840

841+
// Warning: (ae-forgotten-export) The symbol "SerializationWeakRef" needs to be exported by the entry point index.d.ts
842+
//
843+
// @internal (undocumented)
844+
export const _serializationWeakRef: (obj: unknown) => SerializationWeakRef;
845+
845846
// @internal
846847
export function _serialize(data: unknown[]): Promise<string>;
847848

@@ -1559,10 +1560,6 @@ export interface SVGAttributes<T extends Element = Element> extends AriaAttribut
15591560
zoomAndPan?: string | undefined;
15601561
}
15611562

1562-
// @public (undocumented)
1563-
export interface SVGProps<T extends Element> extends SVGAttributes, QwikAttributes<T> {
1564-
}
1565-
15661563
// @public
15671564
export const sync$: <T extends Function>(fn: T) => SyncQRL<T>;
15681565

@@ -1844,9 +1841,6 @@ export const _wrapProp: <T extends Record<any, any>, P extends keyof T>(...args:
18441841
// @internal @deprecated (undocumented)
18451842
export const _wrapSignal: <T extends Record<any, any>, P extends keyof T>(obj: T, prop: P) => any;
18461843

1847-
// @internal (undocumented)
1848-
export const _wrapStore: <T extends Record<any, any>, P extends keyof T>(obj: T, prop: P) => Signal<T>;
1849-
18501844
// (No @packageDocumentation comment for this package)
18511845

18521846
```

0 commit comments

Comments
 (0)