Skip to content

Commit bd4eb50

Browse files
committed
fix: skip serialize functions in noSerialize set
1 parent 6d4e1c9 commit bd4eb50

File tree

3 files changed

+32
-28
lines changed

3 files changed

+32
-28
lines changed

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

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -933,20 +933,21 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
933933
serializationContext.$addRoot$(qrl, null);
934934
};
935935

936-
const outputRootRef = (value: unknown, elseCallback: () => void) => {
936+
const outputRootRef = (value: unknown, rootDepth = 0) => {
937937
const seen = $wasSeen$(value);
938938
const rootRefPath = $pathMap$.get(value);
939-
if (isRootObject() && seen && seen.$parent$ !== null && rootRefPath) {
939+
if (rootDepth === depth && seen && seen.$parent$ !== null && rootRefPath) {
940940
output(TypeIds.RootRef, rootRefPath);
941-
} else if (depth > 0 && seen && seen.$rootIndex$ !== -1) {
941+
return true;
942+
} else if (depth > rootDepth && seen && seen.$rootIndex$ !== -1) {
942943
output(TypeIds.RootRef, seen.$rootIndex$);
943-
} else {
944-
elseCallback();
944+
return true;
945945
}
946+
return false;
946947
};
947948

948949
const writeValue = (value: unknown) => {
949-
if (fastSkipSerialize(value as object)) {
950+
if (fastSkipSerialize(value as object | Function)) {
950951
output(TypeIds.Constant, Constants.Undefined);
951952
} else if (typeof value === 'bigint') {
952953
output(TypeIds.BigInt, value.toString());
@@ -958,7 +959,7 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
958959
} else if (value === Fragment) {
959960
output(TypeIds.Constant, Constants.Fragment);
960961
} else if (isQrl(value)) {
961-
outputRootRef(value, () => {
962+
if (!outputRootRef(value)) {
962963
const qrl = qrlToString(serializationContext, value);
963964
const type = preloadQrls.has(value) ? TypeIds.PreloadQRL : TypeIds.QRL;
964965
if (isRootObject()) {
@@ -967,7 +968,7 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
967968
const id = serializationContext.$addRoot$(qrl);
968969
output(type, id);
969970
}
970-
});
971+
}
971972
} else if (isQwikComponent(value)) {
972973
const [qrl]: [QRLInternal] = (value as any)[SERIALIZABLE_STATE];
973974
serializationContext.$renderSymbols$.add(qrl.$symbol$);
@@ -1011,9 +1012,9 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
10111012
if (value.length === 0) {
10121013
output(TypeIds.Constant, Constants.EmptyString);
10131014
} else {
1014-
outputRootRef(value, () => {
1015+
if (!outputRootRef(value)) {
10151016
output(TypeIds.String, value);
1016-
});
1017+
}
10171018
}
10181019
} else if (typeof value === 'undefined') {
10191020
output(TypeIds.Constant, Constants.Undefined);
@@ -1031,28 +1032,15 @@ async function serialize(serializationContext: SerializationContext): Promise<vo
10311032
* The object writer outputs an array object (without type prefix) and this increases the depth
10321033
* for the objects within (depth 1).
10331034
*/
1034-
const isRootObject = depth === 1;
10351035
// Objects are the only way to create circular dependencies.
10361036
// So the first thing to to is to see if we have a circular dependency.
10371037
// (NOTE: For root objects we need to serialize them regardless if we have seen
10381038
// them before, otherwise the root object reference will point to itself.)
10391039
// Also note that depth will be 1 for objects in root
1040-
if (isRootObject) {
1041-
const seen = $wasSeen$(value);
1042-
const rootPath = $pathMap$.get(value);
1043-
if (rootPath && seen && seen.$parent$ !== null) {
1044-
output(TypeIds.RootRef, rootPath);
1045-
return;
1046-
}
1047-
} else if (depth > 1) {
1048-
const seen = $wasSeen$(value);
1049-
if (seen && seen.$rootIndex$ !== -1) {
1050-
// We have seen this object before, so we can serialize it as a reference.
1051-
// Otherwise serialize as normal
1052-
output(TypeIds.RootRef, seen.$rootIndex$);
1053-
return;
1054-
}
1040+
if (outputRootRef(value, 1)) {
1041+
return;
10551042
}
1043+
10561044
if (isPropsProxy(value)) {
10571045
const varProps = value[_VAR_PROPS];
10581046
const constProps = value[_CONST_PROPS];

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -942,6 +942,18 @@ describe('shared-serialization', () => {
942942
(5 chars)"
943943
`);
944944
});
945+
it('should ignore functions in noSerialize set', async () => {
946+
const obj = { hi: true, ignore: noSerialize(() => console.warn()) };
947+
const state = await serialize(obj);
948+
expect(dumpState(state)).toMatchInlineSnapshot(`
949+
"
950+
0 Object [
951+
String "hi"
952+
Constant true
953+
]
954+
(17 chars)"
955+
`);
956+
});
945957
it('should ignore NoSerializeSymbol', async () => {
946958
const obj = { hi: true, [NoSerializeSymbol]: true };
947959
const state = await serialize(obj);

packages/qwik/src/core/shared/utils/serialize-utils.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,12 @@ export const shouldSerialize = (obj: unknown): boolean => {
9999
return true;
100100
};
101101

102-
export const fastSkipSerialize = (obj: object): boolean => {
103-
return typeof obj === 'object' && obj && (NoSerializeSymbol in obj || noSerializeSet.has(obj));
102+
export const fastSkipSerialize = (obj: object | Function): boolean => {
103+
return (
104+
obj &&
105+
((typeof obj === 'object' && (NoSerializeSymbol in obj || noSerializeSet.has(obj))) ||
106+
(typeof obj === 'function' && noSerializeSet.has(obj)))
107+
);
104108
};
105109

106110
export const fastWeakSerialize = (obj: object): boolean => {

0 commit comments

Comments
 (0)