Skip to content

Commit 7ab23fd

Browse files
committed
fix: lazy state deserialization again
1 parent 53cec56 commit 7ab23fd

4 files changed

Lines changed: 46 additions & 14 deletions

File tree

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,9 @@ import { assertTrue } from '../shared/error/assert';
66
import { QError, qError } from '../shared/error/error';
77
import { ERROR_CONTEXT, isRecoverable } from '../shared/error/error-handling';
88
import type { QRL } from '../shared/qrl/qrl.public';
9-
import { eagerDeserializeStateIterator } from '../shared/serdes/inflate';
10-
import { getObjectById, parseQRL, preprocessState } from '../shared/serdes/index';
9+
import { wrapDeserializerProxy } from '../shared/serdes/deser-proxy';
10+
import { getObjectById, parseQRL } from '../shared/serdes/index';
11+
import { preprocessStateIterator } from '../shared/serdes/preprocess-state';
1112
import {
1213
createMacroTask,
1314
runYieldingIterator,
@@ -227,9 +228,8 @@ export class DomContainer extends _SharedContainer implements IClientContainer {
227228
if (qwikStates.length !== 0) {
228229
const lastState = qwikStates[qwikStates.length - 1];
229230
this.$rawStateData$ = JSON.parse(lastState.textContent!);
230-
preprocessState(this.$rawStateData$, this);
231-
this.$stateData$ = Array(this.$rawStateData$.length / 2);
232-
yield* eagerDeserializeStateIterator(this, this.$rawStateData$, this.$stateData$);
231+
yield* preprocessStateIterator(this.$rawStateData$, this);
232+
this.$stateData$ = wrapDeserializerProxy(this, this.$rawStateData$) as unknown[];
233233
}
234234
this.$hoistStyles$();
235235
element.setAttribute(QContainerAttr, QContainerValue.RESUMED);

packages/qwik/src/core/client/process-vnode-data.unit.tsx

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -90,20 +90,35 @@ describe('processVnodeData', () => {
9090
});
9191
});
9292

93-
it('should yield while eagerly deserializing container state before resume', async () => {
94-
const serializedItems: unknown[] = [];
95-
const expectedItems: number[] = [];
93+
it('should yield while preprocessing container state without eager deserialization', async () => {
94+
const stateItems: unknown[] = [TypeIds.VNode, '4'];
9695
for (let i = 0; i < 128; i++) {
97-
serializedItems.push(TypeIds.Plain, i);
98-
expectedItems.push(i);
96+
stateItems.push(TypeIds.Plain, i);
9997
}
100-
const stateData = JSON.stringify([TypeIds.Array, serializedItems]);
98+
const stateData = JSON.stringify(stateItems);
99+
const vData =
100+
emitVNodeSeparators(0, 2) +
101+
'G2' +
102+
emitVNodeSeparators(2, 4) +
103+
VNodeDataSeparator.REFERENCE_CH +
104+
emitVNodeSeparators(4, 5) +
105+
'FB';
101106
const document = createDocument({
102107
html: `
103108
<html q:container="paused" q:locale="" q:base="" q:instance="" q:manifest-hash="">
104109
<head :></head>
105110
<body :>
106-
<script type="qwik/vnode"></script>
111+
<!--q:ignore=abc-->
112+
<section>
113+
<div>
114+
<!--q:container-island=some-id-2-->
115+
<span :><button :>Click</button></span>
116+
<!--/q:container-island-->
117+
</div>
118+
</section>
119+
<!--/q:ignore-->
120+
<b :>After!</b>
121+
<script type="qwik/vnode">${vData}</script>
107122
<script type="qwik/state">${stateData}</script>
108123
</body>
109124
</html>
@@ -130,7 +145,10 @@ describe('processVnodeData', () => {
130145

131146
await ready;
132147
expect(chunks).toBeGreaterThan(1);
133-
expect(container.$getObjectById$(0)).toEqual(expectedItems);
148+
expect(container.$getObjectById$(1)).toBe(0);
149+
expect((document.documentElement as ContainerElement).qVNodeRefs?.get(4)).toBe(
150+
document.querySelector('button')
151+
);
134152
expect(document.documentElement.getAttribute(QContainerAttr)).toBe(QContainerValue.RESUMED);
135153
});
136154
});

packages/qwik/src/core/shared/serdes/preprocess-state.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,16 @@ import { TypeIds } from './constants';
5252
*/
5353

5454
export function preprocessState(data: unknown[], container: DeserializeContainer) {
55+
const iterator = preprocessStateIterator(data, container);
56+
while (!iterator.next().done) {
57+
// Run synchronously for non-browser and non-container deserialization paths.
58+
}
59+
}
60+
61+
export function* preprocessStateIterator(
62+
data: unknown[],
63+
container: DeserializeContainer
64+
): Generator<void, void, void> {
5565
const isRootDeepRef = (type: TypeIds, value: unknown) => {
5666
return type === TypeIds.RootRef && typeof value === 'string';
5767
};
@@ -99,5 +109,6 @@ export function preprocessState(data: unknown[], container: DeserializeContainer
99109
} else if (isForwardRefsMap(data[i] as TypeIds)) {
100110
container.$forwardRefs$ = data[i + 1] as number[];
101111
}
112+
yield;
102113
}
103114
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1035,11 +1035,14 @@ describe('shared-serialization', () => {
10351035
const restoredComputed = state[1] as ComputedSignalImpl<number>;
10361036
const restoredSerializer = state[2] as SerializerSignalImpl<MyCustomSerializable, number>;
10371037

1038-
for (const restored of [restoredSignal, restoredComputed, restoredSerializer]) {
1038+
const signals = [restoredSignal, restoredComputed, restoredSerializer];
1039+
for (let i = 0; i < signals.length; i++) {
1040+
const restored = signals[i];
10391041
const effect = [...restored.$effects$!][0];
10401042
expect(effect.backRef).toBeDefined();
10411043
expect(effect.backRef!.has(restored)).toBe(true);
10421044
}
1045+
10431046
expect(restoredComputed.$computeQrl$).toBeDefined();
10441047
expect(restoredSerializer.$computeQrl$).toBeDefined();
10451048
});

0 commit comments

Comments
 (0)