Skip to content

Commit 3b8361a

Browse files
committed
perf: small improvements for element and component render
1 parent 4d3d02a commit 3b8361a

File tree

6 files changed

+37
-42
lines changed

6 files changed

+37
-42
lines changed

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,6 @@ export class DomContainer extends _SharedContainer implements IClientContainer {
277277
if (typeof value == 'string') {
278278
const projection = this.vNodeLocate(value);
279279
props[i + 1] = projection;
280-
projection.getSlotParent();
281280
}
282281
}
283282
}

packages/qwik/src/core/client/vnode-diff.ts

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ import {
5151
vnode_getDomParentVNode,
5252
vnode_getElementName,
5353
vnode_getFirstChild,
54-
vnode_getNode,
5554
vnode_getProjectionParentComponent,
5655
vnode_getProps,
5756
vnode_getText,
@@ -453,7 +452,7 @@ export const vnode_diff = (
453452
}
454453

455454
function expectSlot() {
456-
const vHost = vnode_getProjectionParentComponent(vParent, container.rootVNode);
455+
const vHost = vnode_getProjectionParentComponent(vParent);
457456

458457
const slotNameKey = getSlotNameKey(vHost);
459458
// console.log('expectSlot', JSON.stringify(slotNameKey));
@@ -668,15 +667,16 @@ export const vnode_diff = (
668667
}
669668
const key = jsx.key;
670669
if (key) {
671-
element.setAttribute(ELEMENT_KEY, key);
672670
(vNewNode as ElementVNode).setProp(ELEMENT_KEY, key);
673671
}
674672

675673
// append class attribute if styleScopedId exists and there is no class attribute
676-
const classAttributeExists =
677-
hasClassAttr(jsx.varProps) || (jsx.constProps && hasClassAttr(jsx.constProps));
678-
if (!classAttributeExists && scopedStyleIdPrefix) {
679-
element.setAttribute('class', scopedStyleIdPrefix);
674+
if (scopedStyleIdPrefix) {
675+
const classAttributeExists =
676+
hasClassAttr(jsx.varProps) || (jsx.constProps && hasClassAttr(jsx.constProps));
677+
if (!classAttributeExists) {
678+
element.setAttribute('class', scopedStyleIdPrefix);
679+
}
680680
}
681681

682682
vnode_insertBefore(journal, vParent as ElementVNode, vNewNode as ElementVNode, vCurrent);
@@ -693,7 +693,7 @@ export const vnode_diff = (
693693

694694
const element = container.document.createElementNS(elementNamespace, elementName);
695695
vNewNode = vnode_newElement(element, elementName);
696-
(vNewNode as ElementVNode).flags |= elementNamespaceFlag;
696+
vNewNode.flags |= elementNamespaceFlag;
697697
return element;
698698
}
699699

@@ -702,7 +702,6 @@ export const vnode_diff = (
702702
vCurrent && vnode_isElementVNode(vCurrent) && elementName === vnode_getElementName(vCurrent);
703703
const jsxKey: string | null = jsx.key;
704704
let needsQDispatchEventPatch = false;
705-
const currentFile = getFileLocationFromJsx(jsx.dev);
706705
if (!isSameElementName || jsxKey !== getKey(vCurrent)) {
707706
// So we have a key and it does not match the current node.
708707
// We need to do a forward search to find it.
@@ -735,22 +734,23 @@ export const vnode_diff = (
735734
}
736735
const vNode = (vNewNode || vCurrent) as ElementVNode;
737736

738-
const element = (vNode as ElementVNode).element as QElement;
737+
const element = vNode.element as QElement;
739738
if (!element.vNode) {
740739
element.vNode = vNode;
741740
}
742741

743742
needsQDispatchEventPatch =
744-
setBulkProps(vNode, jsxAttrs, currentFile) || needsQDispatchEventPatch;
743+
setBulkProps(vNode, jsxAttrs, (isDev && getFileLocationFromJsx(jsx.dev)) || null) ||
744+
needsQDispatchEventPatch;
745745
if (needsQDispatchEventPatch) {
746746
// Event handler needs to be patched onto the element.
747747
if (!element.qDispatchEvent) {
748748
element.qDispatchEvent = (event: Event, scope: QwikLoaderEventScope) => {
749749
const eventName = event.type;
750750
const eventProp = ':' + scope.substring(1) + ':' + eventName;
751751
const qrls = [
752-
(vNode as ElementVNode).getProp<QRL>(eventProp, null),
753-
(vNode as ElementVNode).getProp<QRL>(HANDLER_PREFIX + eventProp, null),
752+
vNode.getProp<QRL>(eventProp, null),
753+
vNode.getProp<QRL>(HANDLER_PREFIX + eventProp, null),
754754
];
755755
let returnValue = false;
756756
qrls.flat(2).forEach((qrl) => {
@@ -778,7 +778,7 @@ export const vnode_diff = (
778778
function setBulkProps(
779779
vnode: ElementVNode,
780780
srcAttrs: ClientAttrs,
781-
currentFile?: string | null
781+
currentFile: string | null
782782
): boolean {
783783
vnode_ensureElementInflated(vnode);
784784
const dstAttrs = vnode_getProps(vnode) as ClientAttrs;
@@ -792,12 +792,12 @@ export const vnode_diff = (
792792

793793
const record = (key: string, value: any) => {
794794
if (key.startsWith(':')) {
795-
(vnode as ElementVNode).setProp(key, value);
795+
vnode.setProp(key, value);
796796
return;
797797
}
798798

799799
if (key === 'ref') {
800-
const element = vnode_getNode(vnode) as Element;
800+
const element = vnode.element;
801801
if (isSignal(value)) {
802802
value.value = element;
803803
return;
@@ -815,7 +815,7 @@ export const vnode_diff = (
815815
value = trackSignalAndAssignHost(value, vnode, key, container, NON_CONST_SUBSCRIPTION_DATA);
816816
}
817817

818-
(vnode as ElementVNode).setAttr(
818+
vnode.setAttr(
819819
key,
820820
value !== null ? serializeAttribute(key, value, scopedStyleIdPrefix) : null,
821821
journal
@@ -1059,8 +1059,12 @@ export const vnode_diff = (
10591059
ELEMENT_PROPS,
10601060
container.$getObjectById$
10611061
);
1062-
const propsAreDifferent = propsDiffer(jsxProps, vNodeProps);
1063-
shouldRender = shouldRender || propsAreDifferent;
1062+
let propsAreDifferent = false;
1063+
if (!shouldRender) {
1064+
propsAreDifferent = propsDiffer(jsxProps, vNodeProps);
1065+
shouldRender = shouldRender || propsAreDifferent;
1066+
}
1067+
10641068
if (shouldRender) {
10651069
if (propsAreDifferent) {
10661070
if (vNodeProps) {

packages/qwik/src/core/client/vnode-impl.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,26 +7,26 @@ import {
77
type VNodeJournal,
88
} from './vnode';
99
import type { ChoreArray } from './chore-array';
10+
import { _EFFECT_BACK_REF } from '../reactive-primitives/types';
11+
import { BackRef } from '../reactive-primitives/cleanup';
1012

1113
/** @internal */
12-
export abstract class VNode {
13-
props: (string | null | boolean)[] | null = null;
14+
export abstract class VNode extends BackRef {
15+
props: unknown[] | null = null;
1416
slotParent: VNode | null = null;
1517
// scheduled chores for this vnode
1618
chores: ChoreArray | null = null;
1719
// blocked chores for this vnode
1820
blockedChores: ChoreArray | null = null;
1921

20-
getSlotParent(): VNode | null {
21-
return this.slotParent;
22-
}
23-
2422
constructor(
2523
public flags: VNodeFlags,
2624
public parent: ElementVNode | VirtualVNode | null,
2725
public previousSibling: VNode | null | undefined,
2826
public nextSibling: VNode | null | undefined
29-
) {}
27+
) {
28+
super();
29+
}
3030

3131
getProp<T>(key: string, getObject: ((id: string) => any) | null): T | null {
3232
const type = this.flags;

packages/qwik/src/core/client/vnode.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1968,17 +1968,14 @@ const isElement = (node: any): node is Element =>
19681968
* @param rootVNode
19691969
* @returns
19701970
*/
1971-
export const vnode_getProjectionParentComponent = (
1972-
vHost: VNode,
1973-
rootVNode: ElementVNode
1974-
): VirtualVNode | null => {
1971+
export const vnode_getProjectionParentComponent = (vHost: VNode): VirtualVNode | null => {
19751972
let projectionDepth = 1;
19761973
while (projectionDepth--) {
19771974
while (
19781975
vHost &&
19791976
(vnode_isVirtualVNode(vHost) ? vHost.getProp(OnRenderProp, null) === null : true)
19801977
) {
1981-
const qSlotParent = vHost.getSlotParent();
1978+
const qSlotParent = vHost.slotParent;
19821979
const vProjectionParent = vnode_isVirtualVNode(vHost) && qSlotParent;
19831980
if (vProjectionParent) {
19841981
// We found a projection, so we need to go up one more level.

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1839,8 +1839,10 @@ export class _VirtualVNode extends _VNode {
18391839
// @public (undocumented)
18401840
export type VisibleTaskStrategy = 'intersection-observer' | 'document-ready' | 'document-idle';
18411841

1842+
// Warning: (ae-forgotten-export) The symbol "BackRef" needs to be exported by the entry point index.d.ts
1843+
//
18421844
// @internal (undocumented)
1843-
export abstract class _VNode {
1845+
export abstract class _VNode extends BackRef {
18441846
constructor(flags: _VNodeFlags, parent: _ElementVNode | _VirtualVNode | null, previousSibling: _VNode | null | undefined, nextSibling: _VNode | null | undefined);
18451847
// (undocumented)
18461848
blockedChores: ChoreArray | null;
@@ -1855,15 +1857,13 @@ export abstract class _VNode {
18551857
// (undocumented)
18561858
getProp<T>(key: string, getObject: ((id: string) => any) | null): T | null;
18571859
// (undocumented)
1858-
getSlotParent(): _VNode | null;
1859-
// (undocumented)
18601860
nextSibling: _VNode | null | undefined;
18611861
// (undocumented)
18621862
parent: _ElementVNode | _VirtualVNode | null;
18631863
// (undocumented)
18641864
previousSibling: _VNode | null | undefined;
18651865
// (undocumented)
1866-
props: (string | null | boolean)[] | null;
1866+
props: unknown[] | null;
18671867
// (undocumented)
18681868
setAttr(key: string, value: string | null | boolean, journal: VNodeJournal | null): void;
18691869
// (undocumented)

packages/qwik/src/core/shared/utils/scoped-styles.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,7 @@ export const styleContent = (styleId: string): string => {
66
};
77

88
export function hasClassAttr(props: Props): boolean {
9-
for (const key in props) {
10-
if (Object.prototype.hasOwnProperty.call(props, key) && isClassAttr(key)) {
11-
return true;
12-
}
13-
}
14-
return false;
9+
return 'class' in props || 'className' in props;
1510
}
1611

1712
export function isClassAttr(key: string): boolean {

0 commit comments

Comments
 (0)