Skip to content

Commit 8ade957

Browse files
authored
Merge pull request #8175 from QwikDev/v2-fixes
fix(core): qresume and serializer
2 parents 0bdbd8f + f48c13b commit 8ade957

File tree

4 files changed

+89
-52
lines changed

4 files changed

+89
-52
lines changed

packages/qwik/src/core/client/dom-container.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,16 +148,16 @@ export class DomContainer extends _SharedContainer implements IClientContainer {
148148
this.$setServerData$();
149149
element.setAttribute(QContainerAttr, QContainerValue.RESUMED);
150150
element.qContainer = this;
151-
if (!qTest && element.isConnected) {
152-
element.dispatchEvent(new CustomEvent('qresume', { bubbles: true }));
153-
}
154151
const qwikStates = element.querySelectorAll('script[type="qwik/state"]');
155152
if (qwikStates.length !== 0) {
156153
const lastState = qwikStates[qwikStates.length - 1];
157154
this.$rawStateData$ = JSON.parse(lastState.textContent!);
158155
preprocessState(this.$rawStateData$, this);
159156
this.$stateData$ = wrapDeserializerProxy(this, this.$rawStateData$) as unknown[];
160157
}
158+
if (!qTest && element.isConnected) {
159+
element.dispatchEvent(new CustomEvent('qresume', { bubbles: true }));
160+
}
161161
}
162162

163163
$setRawState$(id: number, vParent: ElementVNode | VirtualVNode): void {

packages/qwik/src/core/shared/serdes/serdes.unit.ts

Lines changed: 60 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
import { $, componentQrl, noSerialize } from '@qwik.dev/core';
22
import { describe, expect, it, vi } from 'vitest';
3-
import { _createDeserializeContainer } from './serdes.public';
4-
import { _dumpState } from './dump-state';
5-
import { createSerializationContext } from './serialization-context';
6-
import { _typeIdNames } from './constants';
7-
import { TypeIds } from './constants';
83
import { _fnSignal, _wrapProp } from '../../internal';
4+
import type { SerializerSignalImpl } from '../../reactive-primitives/impl/serializer-signal-impl';
95
import { type SignalImpl } from '../../reactive-primitives/impl/signal-impl';
106
import { createStore } from '../../reactive-primitives/impl/store';
117
import { createAsyncComputedSignal } from '../../reactive-primitives/signal-api';
128
import {
139
createComputedQrl,
14-
createSerializerQrl,
10+
createSerializer$,
1511
createSignal,
1612
isSignal,
1713
} from '../../reactive-primitives/signal.public';
@@ -29,9 +25,12 @@ import { createQRL, type QRLInternal } from '../qrl/qrl-class';
2925
import { isQrl } from '../qrl/qrl-utils';
3026
import { EMPTY_ARRAY, EMPTY_OBJ } from '../utils/flyweight';
3127
import { retryOnPromise } from '../utils/promises';
32-
import { NoSerializeSymbol, SerializerSymbol, verifySerializable } from './verify';
33-
import { _constants } from './constants';
28+
import { _constants, _typeIdNames, TypeIds } from './constants';
29+
import { _dumpState } from './dump-state';
30+
import { _createDeserializeContainer } from './serdes.public';
31+
import { createSerializationContext } from './serialization-context';
3432
import { _serializationWeakRef } from './serialize';
33+
import { NoSerializeSymbol, SerializerSymbol, verifySerializable } from './verify';
3534

3635
const DEBUG = false;
3736

@@ -561,37 +560,65 @@ describe('shared-serialization', () => {
561560
`);
562561
});
563562
it(title(TypeIds.SerializerSignal), async () => {
564-
const custom = createSerializerQrl(
565-
inlinedQrl<{
566-
serialize: (data: any | undefined) => any;
567-
deserialize: (data: any) => any;
568-
initial?: any;
569-
}>(
570-
{
571-
deserialize: (n?: number) => new MyCustomSerializable(n || 3),
572-
serialize: (obj) => obj.n,
573-
},
574-
'custom_createSerializer_qrl'
575-
)
576-
);
563+
const plain = createSerializer$({
564+
deserialize: (n?: number) => new MyCustomSerializable(n || 3),
565+
serialize: (obj) => obj.n,
566+
});
577567
// Force the value to be created
578-
custom.value.inc();
579-
const objs = await serialize(custom);
568+
plain.value.inc();
569+
const unread = createSerializer$({
570+
deserialize: (n?: number) => new MyCustomSerializable(n || 3),
571+
serialize: (obj) => obj.n,
572+
});
573+
const thunked = createSerializer$(() => ({
574+
deserialize: (n?: number) => new MyCustomSerializable(n || 3),
575+
serialize: (obj) => obj.n,
576+
}));
577+
const promised = createSerializer$(() => ({
578+
deserialize: (n?: number) => new MyCustomSerializable(n || 3),
579+
serialize: (obj) => obj.n,
580+
})) as any as SerializerSignalImpl<number, MyCustomSerializable>;
581+
promised.$computeQrl$.resolved = Promise.resolve(promised.$computeQrl$.resolved) as any;
582+
583+
const objs = await serialize([plain, unread, thunked, promised]);
580584
expect(_dumpState(objs)).toMatchInlineSnapshot(`
581585
"
582-
0 ForwardRef 0
583-
1 PreloadQRL "2 3"
584-
2 {string} "mock-chunk"
585-
3 {string} "custom_createSerializer_qrl"
586-
4 SerializerSignal [
587-
RootRef 1
586+
0 Array [
587+
SerializerSignal [
588+
RootRef 1
589+
Constant undefined
590+
{number} 4
591+
]
592+
SerializerSignal [
593+
RootRef 2
594+
Constant undefined
595+
Constant NEEDS_COMPUTATION
596+
]
597+
SerializerSignal [
598+
RootRef 3
599+
Constant undefined
600+
Constant NEEDS_COMPUTATION
601+
]
602+
ForwardRef 0
603+
]
604+
1 PreloadQRL "5 6"
605+
2 PreloadQRL "5 7"
606+
3 PreloadQRL "5 8"
607+
4 PreloadQRL "5 9"
608+
5 {string} "mock-chunk"
609+
6 {string} "describe_describe_it_plain_createSerializer_IrZN04alftE"
610+
7 {string} "describe_describe_it_unread_createSerializer_oYdaCRjw9Q0"
611+
8 {string} "describe_describe_it_thunked_createSerializer_ufw7hr9vFDo"
612+
9 {string} "describe_describe_it_promised_createSerializer_YCkDOYPyCO0"
613+
10 SerializerSignal [
614+
RootRef 4
588615
Constant undefined
589-
{number} 4
616+
Constant NEEDS_COMPUTATION
590617
]
591-
5 ForwardRefs [
592-
4
618+
11 ForwardRefs [
619+
10
593620
]
594-
(85 chars)"
621+
(382 chars)"
595622
`);
596623
});
597624
it(title(TypeIds.AsyncComputedSignal), async () => {

packages/qwik/src/core/shared/serdes/serialize.ts

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import { isQrl, isSyncQrl } from '../qrl/qrl-utils';
3434
import { _OWNER, _PROPS_HANDLER, _UNINITIALIZED } from '../utils/constants';
3535
import { EMPTY_ARRAY, EMPTY_OBJ } from '../utils/flyweight';
3636
import { ELEMENT_ID, ELEMENT_PROPS, QBackRefs } from '../utils/markers';
37-
import { isPromise } from '../utils/promises';
37+
import { isPromise, maybeThen } from '../utils/promises';
3838
import { fastSkipSerialize, SerializerSymbol } from './verify';
3939
import { Constants, TypeIds } from './constants';
4040
import { qrlToString } from './qrl-to-string';
@@ -386,20 +386,21 @@ export async function serialize(serializationContext: SerializationContext): Pro
386386
} else if (value instanceof SignalImpl) {
387387
if (value instanceof SerializerSignalImpl) {
388388
addPreloadQrl(value.$computeQrl$);
389-
const forwardRefId = resolvePromise(
390-
getCustomSerializerPromise(value, value.$untrackedValue$),
391-
$addRoot$,
392-
(resolved, resolvedValue) => {
389+
const maybeValue = getCustomSerializerPromise(value, value.$untrackedValue$);
390+
if (isPromise(maybeValue)) {
391+
const forwardRefId = resolvePromise(maybeValue, $addRoot$, (resolved, resolvedValue) => {
393392
return new PromiseResult(
394393
TypeIds.SerializerSignal,
395394
resolved,
396395
resolvedValue,
397396
value.$effects$,
398397
value.$computeQrl$
399398
);
400-
}
401-
);
402-
output(TypeIds.ForwardRef, forwardRefId);
399+
});
400+
output(TypeIds.ForwardRef, forwardRefId);
401+
} else {
402+
output(TypeIds.SerializerSignal, [value.$computeQrl$, value.$effects$, maybeValue]);
403+
}
403404
return;
404405
}
405406

@@ -606,7 +607,7 @@ export async function serialize(serializationContext: SerializationContext): Pro
606607
function resolvePromise(
607608
promise: Promise<unknown>,
608609
$addRoot$: (obj: unknown) => number,
609-
classCreator: (resolved: boolean, resolvedValue: unknown) => PromiseResult
610+
classCreator: (didResolve: boolean, resolvedValue: unknown) => PromiseResult
610611
) {
611612
const forwardRefId = forwardRefsId++;
612613
promise
@@ -686,20 +687,27 @@ export class PromiseResult {
686687
) {}
687688
}
688689
function getCustomSerializerPromise<T, S>(signal: SerializerSignalImpl<T, S>, value: any) {
689-
return new Promise((resolve) => {
690-
(signal.$computeQrl$ as QRLInternal<SerializerArg<T, S>>).resolve().then((arg) => {
690+
return maybeThen(
691+
(signal.$computeQrl$.resolved || signal.$computeQrl$.resolve()) as any as SerializerArg<
692+
unknown,
693+
unknown
694+
>,
695+
(arg) => {
691696
let data;
692-
if ((arg as any).serialize) {
697+
if (typeof arg === 'function') {
698+
arg = arg();
699+
}
700+
if (arg.serialize) {
693701
data = (arg as any).serialize(value);
694-
} else if (SerializerSymbol in value) {
702+
} else if (typeof value === 'object' && SerializerSymbol in value) {
695703
data = (value as any)[SerializerSymbol](value);
696704
}
697705
if (data === undefined) {
698706
data = NEEDS_COMPUTATION;
699707
}
700-
resolve(data);
701-
});
702-
});
708+
return data;
709+
}
710+
);
703711
}
704712

705713
const discoverValuesForVNodeData = (vnodeData: VNodeData, callback: (value: unknown) => void) => {

starters/apps/e2e/src/components/no-resume/no-resume.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ export const NoResume = component$(() => {
77
<div>This turns red on resume</div>
88
<button
99
document:onQResume$={() => {
10+
// this should not crash
11+
void sig.value;
1012
document.body.style.color = "red";
1113
}}
1214
onClick$={() => {

0 commit comments

Comments
 (0)