From: Evan You Date: Mon, 10 Feb 2025 09:37:24 +0000 (+0800) Subject: perf(vapor): v-for remove all fast path X-Git-Tag: v3.6.0-alpha.1~16^2~69 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=528705f667b4afebf3ea8dbbc674a4eed1415809;p=thirdparty%2Fvuejs%2Fcore.git perf(vapor): v-for remove all fast path --- diff --git a/packages/compiler-vapor/src/generators/for.ts b/packages/compiler-vapor/src/generators/for.ts index 12d21b3515..6f596499ff 100644 --- a/packages/compiler-vapor/src/generators/for.ts +++ b/packages/compiler-vapor/src/generators/for.ts @@ -16,8 +16,18 @@ export function genFor( context: CodegenContext, ): CodeFragment[] { const { helper } = context - const { source, value, key, index, render, keyProp, once, id, component } = - oper + const { + source, + value, + key, + index, + render, + keyProp, + once, + id, + component, + onlyChild, + } = oper let rawValue: string | null = null const rawKey = key && key.content @@ -80,6 +90,7 @@ export function genFor( genCallback(keyProp), component && 'true', once && 'true', + onlyChild && `true`, // todo: hydrationNode ), ] diff --git a/packages/compiler-vapor/src/ir/index.ts b/packages/compiler-vapor/src/ir/index.ts index cf45a60139..361cafc0c1 100644 --- a/packages/compiler-vapor/src/ir/index.ts +++ b/packages/compiler-vapor/src/ir/index.ts @@ -89,6 +89,7 @@ export interface ForIRNode extends BaseIRNode, IRFor { render: BlockIRNode once: boolean component: boolean + onlyChild: boolean } export interface SetPropIRNode extends BaseIRNode { diff --git a/packages/compiler-vapor/src/transforms/vFor.ts b/packages/compiler-vapor/src/transforms/vFor.ts index 7b47788223..83bda63067 100644 --- a/packages/compiler-vapor/src/transforms/vFor.ts +++ b/packages/compiler-vapor/src/transforms/vFor.ts @@ -57,6 +57,16 @@ export function processFor( return (): void => { exitBlock() + + const { parent } = context + + // if v-for is the only child of a parent element, it can go the fast path + // when the entire list is emptied + const isOnlyChild = + parent && + parent.block.node !== parent.node && + parent.node.children.length === 1 + context.registerOperation({ type: IRNodeTypes.FOR, id, @@ -68,6 +78,7 @@ export function processFor( render, once: context.inVOnce, component: isComponent, + onlyChild: !!isOnlyChild, }) } } diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index 1d6d719011..f8f0988704 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -70,6 +70,7 @@ export const createFor = ( */ isComponent = false, once?: boolean, + canUseFastRemove?: boolean, // hydrationNode?: Node, ): VaporFragment => { let isMounted = false @@ -105,9 +106,14 @@ export const createFor = ( mount(source, i) } } else if (!newLength) { - // fast path for clearing + // fast path for clearing all + const doRemove = !canUseFastRemove for (let i = 0; i < oldLength; i++) { - unmount(oldBlocks[i]) + unmount(oldBlocks[i], doRemove) + } + if (canUseFastRemove) { + parent!.textContent = '' + parent!.appendChild(parentAnchor) } } else if (!getKey) { // unkeyed fast path @@ -343,9 +349,9 @@ export const createFor = ( } } - const unmount = ({ nodes, scope }: ForBlock) => { + const unmount = ({ nodes, scope }: ForBlock, doRemove = true) => { scope && scope.stop() - removeBlock(nodes, parent!) + doRemove && removeBlock(nodes, parent!) } once ? renderList() : renderEffect(renderList)