Skip to content

Commit 2434280

Browse files
authored
Merge pull request #7964 from QwikDev/v2-small-fixes
fix: [v2]: small fixes
2 parents 7e9594b + 51b76e9 commit 2434280

27 files changed

+2344
-2312
lines changed

e2e/adapters-e2e/src/root.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ export default component$(() => {
1111
<head>
1212
<meta charset="utf-8" />
1313

14-
<DocumentHeadTags />
15-
1614
<link rel="canonical" href={loc.url.href} />
1715
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
16+
17+
<DocumentHeadTags />
1818
</head>
1919
<body>
2020
<RouterOutlet />

e2e/adapters-e2e/src/routes/service-worker.ts

Whitespace-only changes.

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

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ import { loadClientData } from './use-endpoint';
7474
import { useQwikRouterEnv } from './use-functions';
7575
import { createLoaderSignal, isSameOrigin, isSamePath, toUrl } from './utils';
7676
import { startViewTransition } from './view-transition';
77+
import transitionCss from './qwik-view-transition.css?inline';
7778

7879
/**
7980
* @deprecated Use `QWIK_ROUTER_SCROLLER` instead (will be removed in V3)
@@ -121,18 +122,7 @@ const internalState = { navCount: 0 };
121122
* This hook should be used once, at the root of your application.
122123
*/
123124
export const useQwikRouter = (props?: QwikRouterProps) => {
124-
useStyles$(`
125-
@layer qwik {
126-
@supports selector(html:active-view-transition-type(type)) {
127-
html:active-view-transition-type(qwik-navigation) {
128-
:root{view-transition-name:none}
129-
}
130-
}
131-
@supports not selector(html:active-view-transition-type(type)) {
132-
:root{view-transition-name:none}
133-
}
134-
}
135-
`);
125+
useStyles$(transitionCss);
136126
const env = useQwikRouterEnv();
137127
if (!env?.params) {
138128
throw new Error(
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
@layer qwik {
2+
@supports selector(html:active-view-transition-type(type)) {
3+
html:active-view-transition-type(qwik-navigation) {
4+
:root {
5+
view-transition-name: none;
6+
}
7+
}
8+
}
9+
@supports not selector(html:active-view-transition-type(type)) {
10+
:root {
11+
view-transition-name: none;
12+
}
13+
}
14+
}

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

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,8 @@ 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';
99
import { _SharedContainer } from '../shared/shared-container';
10-
import {
11-
getObjectById,
12-
inflateQRL,
13-
parseQRL,
14-
preprocessState,
15-
wrapDeserializerProxy,
16-
} from '../shared/shared-serialization';
10+
import { getObjectById, inflateQRL, parseQRL, preprocessState } from '../shared/serdes/index';
11+
import { wrapDeserializerProxy } from '../shared/serdes/deser-proxy';
1712
import { QContainerValue, type HostElement, type ObjToProxyMap } from '../shared/types';
1813
import { EMPTY_ARRAY } from '../shared/utils/flyweight';
1914
import {

packages/qwik/src/core/internal.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export {
6060
preprocessState as _preprocessState,
6161
_serializationWeakRef,
6262
_serialize,
63-
} from './shared/shared-serialization';
63+
} from './shared/serdes/index';
6464
export { _CONST_PROPS, _IMMUTABLE, _VAR_PROPS, _UNINITIALIZED } from './shared/utils/constants';
6565
export { EMPTY_ARRAY as _EMPTY_ARRAY } from './shared/utils/flyweight';
6666
export { _restProps } from './shared/utils/prop';

packages/qwik/src/core/shared/component-execution.ts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -299,20 +299,7 @@ function injectPlaceholderElement(
299299
return [null, jsx];
300300
}
301301

302-
/**
303-
* Creates a <script> element with a placeholder type.
304-
*
305-
* @returns A <script> element with a placeholder type.
306-
*/
302+
/** @returns An empty <script> element for adding qwik metadata attributes to */
307303
function createPlaceholderScriptNode(): JSXNodeInternal<string> {
308-
return new JSXNodeImpl(
309-
'script',
310-
{},
311-
{
312-
type: 'placeholder',
313-
hidden: '',
314-
},
315-
null,
316-
3
317-
);
304+
return new JSXNodeImpl('script', {}, { hidden: '' }, null, 3);
318305
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { qrl } from './qrl';
33
import { describe, test, assert, assertType, expectTypeOf } from 'vitest';
44
import { $, type QRL } from './qrl.public';
55
import { useLexicalScope } from '../../use/use-lexical-scope.public';
6-
import { createSerializationContext, parseQRL, qrlToString } from '../shared-serialization';
6+
import { createSerializationContext, parseQRL, qrlToString } from '../serdes/index';
77

88
function matchProps(obj: any, properties: Record<string, any>) {
99
for (const [key, value] of Object.entries(properties)) {
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
import { TypeIds, _constants, type Constants, parseQRL, deserializeData, resolvers } from './index';
2+
import type { DomContainer } from '../../client/dom-container';
3+
import type { ElementVNode, VNode } from '../../client/types';
4+
import { vnode_isVNode, ensureMaterialized, vnode_getNode, vnode_locate } from '../../client/vnode';
5+
import { AsyncComputedSignalImpl } from '../../reactive-primitives/impl/async-computed-signal-impl';
6+
import { ComputedSignalImpl } from '../../reactive-primitives/impl/computed-signal-impl';
7+
import { SerializerSignalImpl } from '../../reactive-primitives/impl/serializer-signal-impl';
8+
import { SignalImpl } from '../../reactive-primitives/impl/signal-impl';
9+
import { getOrCreateStore } from '../../reactive-primitives/impl/store';
10+
import { WrappedSignalImpl } from '../../reactive-primitives/impl/wrapped-signal-impl';
11+
import { SubscriptionData, type NodePropData } from '../../reactive-primitives/subscription-data';
12+
import { StoreFlags } from '../../reactive-primitives/types';
13+
import { createResourceReturn } from '../../use/use-resource';
14+
import { Task } from '../../use/use-task';
15+
import { componentQrl } from '../component.public';
16+
import { qError, QError } from '../error/error';
17+
import { JSXNodeImpl, createPropsProxy } from '../jsx/jsx-runtime';
18+
import type { DeserializeContainer } from '../types';
19+
import { _UNINITIALIZED } from '../utils/constants';
20+
21+
export const allocate = (container: DeserializeContainer, typeId: number, value: unknown): any => {
22+
if (typeId === TypeIds.Plain) {
23+
return value;
24+
}
25+
switch (typeId) {
26+
case TypeIds.RootRef:
27+
return container.$getObjectById$(value as number);
28+
case TypeIds.ForwardRef:
29+
if (!container.$forwardRefs$) {
30+
throw qError(QError.serializeErrorCannotAllocate, ['forward ref']);
31+
}
32+
const rootRef = container.$forwardRefs$[value as number];
33+
if (rootRef === -1) {
34+
return _UNINITIALIZED;
35+
} else {
36+
return container.$getObjectById$(rootRef);
37+
}
38+
case TypeIds.ForwardRefs:
39+
return value;
40+
case TypeIds.Constant:
41+
return _constants[value as Constants];
42+
case TypeIds.Array:
43+
return Array((value as any[]).length / 2);
44+
case TypeIds.Object:
45+
return {};
46+
case TypeIds.QRL:
47+
case TypeIds.PreloadQRL:
48+
const qrl =
49+
typeof value === 'number'
50+
? // root reference
51+
container.$getObjectById$(value)
52+
: value;
53+
return parseQRL(qrl as string);
54+
case TypeIds.Task:
55+
return new Task(-1, -1, null!, null!, null!, null);
56+
case TypeIds.Resource: {
57+
const res = createResourceReturn(
58+
container as any,
59+
// we don't care about the timeout value
60+
undefined,
61+
undefined
62+
);
63+
res.loading = false;
64+
return res;
65+
}
66+
case TypeIds.URL:
67+
return new URL(value as string);
68+
case TypeIds.Date:
69+
return new Date(value as number);
70+
case TypeIds.Regex:
71+
const idx = (value as string).lastIndexOf('/');
72+
return new RegExp((value as string).slice(1, idx), (value as string).slice(idx + 1));
73+
case TypeIds.Error:
74+
return new Error();
75+
case TypeIds.Component:
76+
return componentQrl(null!);
77+
case TypeIds.Signal:
78+
return new SignalImpl(container as any, 0);
79+
case TypeIds.WrappedSignal:
80+
return new WrappedSignalImpl(container as any, null!, null!, null!);
81+
case TypeIds.ComputedSignal:
82+
return new ComputedSignalImpl(container as any, null!);
83+
case TypeIds.AsyncComputedSignal:
84+
return new AsyncComputedSignalImpl(container as any, null!);
85+
case TypeIds.SerializerSignal:
86+
return new SerializerSignalImpl(container as any, null!);
87+
case TypeIds.Store:
88+
/**
89+
* We have a problem here: In theory, both the store and the target need to be present at
90+
* allocate time before inflation can happen. However, that makes the code really complex.
91+
* Instead, we deserialize the target here, which will already allocate and inflate this store
92+
* if there is a cycle (because the original allocation for the store didn't complete yet).
93+
* Because we have a map of target -> store, we will reuse the same store instance after
94+
* target deserialization. So in that case, we will be running inflation twice on the same
95+
* store, but that is not a problem, very little overhead and the code is way simpler.
96+
*/
97+
const storeValue = deserializeData(
98+
container,
99+
(value as any[])[0] as TypeIds,
100+
(value as any[])[1]
101+
);
102+
(value as any[])[0] = TypeIds.Plain;
103+
(value as any[])[1] = storeValue;
104+
return getOrCreateStore(storeValue, StoreFlags.NONE, container as DomContainer);
105+
case TypeIds.URLSearchParams:
106+
return new URLSearchParams(value as string);
107+
case TypeIds.FormData:
108+
return new FormData();
109+
case TypeIds.JSXNode:
110+
return new JSXNodeImpl(null!, null!, null!, null!, -1, null);
111+
case TypeIds.BigInt:
112+
return BigInt(value as string);
113+
case TypeIds.Set:
114+
return new Set();
115+
case TypeIds.Map:
116+
return new Map();
117+
case TypeIds.Promise:
118+
let resolve!: (value: any) => void;
119+
let reject!: (error: any) => void;
120+
const promise = new Promise((res, rej) => {
121+
resolve = res;
122+
reject = rej;
123+
});
124+
resolvers.set(promise, [resolve, reject]);
125+
// Don't leave unhandled promise rejections
126+
promise.catch(() => {});
127+
return promise;
128+
case TypeIds.Uint8Array:
129+
const encodedLength = (value as string).length;
130+
const blocks = encodedLength >>> 2;
131+
const rest = encodedLength & 3;
132+
const decodedLength = blocks * 3 + (rest ? rest - 1 : 0);
133+
return new Uint8Array(decodedLength);
134+
case TypeIds.PropsProxy:
135+
return createPropsProxy(null!, null);
136+
case TypeIds.VNode:
137+
return retrieveVNodeOrDocument(container, value);
138+
case TypeIds.RefVNode:
139+
const vNode = retrieveVNodeOrDocument(container, value);
140+
if (vnode_isVNode(vNode)) {
141+
/**
142+
* If we have a ref, we need to ensure the element is materialized.
143+
*
144+
* Example:
145+
*
146+
* ```
147+
* const Cmp = component$(() => {
148+
* const element = useSignal<HTMLDivElement>();
149+
*
150+
* useVisibleTask$(() => {
151+
* element.value!.innerHTML = 'I am the innerHTML content!';
152+
* });
153+
*
154+
* return (
155+
* <div ref={element} />
156+
* );
157+
* });
158+
* ```
159+
*
160+
* If we don't materialize early element with ref property, and change element innerHTML it
161+
* will be applied to a vnode tree during the lazy materialization, and it is wrong.
162+
*
163+
* Next if we rerender component it will remove applied innerHTML, because the system thinks
164+
* it is a part of the vnode tree.
165+
*/
166+
ensureMaterialized(vNode as ElementVNode);
167+
return vnode_getNode(vNode);
168+
} else {
169+
throw qError(QError.serializeErrorExpectedVNode, [typeof vNode]);
170+
}
171+
case TypeIds.SubscriptionData:
172+
return new SubscriptionData({} as NodePropData);
173+
default:
174+
throw qError(QError.serializeErrorCannotAllocate, [typeId]);
175+
}
176+
};
177+
export function retrieveVNodeOrDocument(
178+
container: DeserializeContainer,
179+
value: unknown | null
180+
): VNode | Document | undefined {
181+
return value
182+
? (container as any).rootVNode
183+
? vnode_locate((container as any).rootVNode, value as string)
184+
: undefined
185+
: container.element?.ownerDocument;
186+
}

0 commit comments

Comments
 (0)