From: Evan You Date: Wed, 12 Feb 2025 07:28:10 +0000 (+0800) Subject: refactor(vapor): use bitwise flags for v-for runtime optimizations X-Git-Tag: v3.6.0-alpha.1~16^2~64 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=242cc15fa6245ff97936f9c03fe8f0e9d176e97b;p=thirdparty%2Fvuejs%2Fcore.git refactor(vapor): use bitwise flags for v-for runtime optimizations --- diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformTemplateRef.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformTemplateRef.spec.ts.snap index 15da71ff4f..f2eade4bcd 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformTemplateRef.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/transformTemplateRef.spec.ts.snap @@ -23,7 +23,7 @@ export function render(_ctx) { const n2 = t0() _setTemplateRef(n2, "foo", void 0, true) return n2 - }, null, null, true) + }, null, 4) return n0 }" `; diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap index d7e763e849..02235ddd99 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap @@ -77,7 +77,7 @@ export function render(_ctx) { const x4 = _child(n4) _renderEffect(() => _setText(x4, _toDisplayString(_for_item1.value+_for_item0.value))) return n4 - }, null, null, null, true) + }, null, 1) _insert(n2, n5) return n5 }) diff --git a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap index 94fd139589..9cbe1bd0d3 100644 --- a/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap @@ -68,7 +68,7 @@ export function render(_ctx) { const n0 = _createFor(() => (_ctx.list), (_for_item0) => { const n2 = t0() return n2 - }, null, null, true) + }, null, 4) return n0 }" `; diff --git a/packages/compiler-vapor/src/generators/for.ts b/packages/compiler-vapor/src/generators/for.ts index 6f596499ff..fbb72c61d4 100644 --- a/packages/compiler-vapor/src/generators/for.ts +++ b/packages/compiler-vapor/src/generators/for.ts @@ -10,6 +10,7 @@ import type { ForIRNode } from '../ir' import { type CodeFragment, NEWLINE, genCall, genMulti } from './utils' import type { Identifier } from '@babel/types' import { parseExpression } from '@babel/parser' +import { VaporVForFlags } from '../../../shared/src/vaporFlags' export function genFor( oper: ForIRNode, @@ -80,6 +81,17 @@ export function genFor( const blockFn = context.withId(() => genBlock(render, context, args), idMap) exitScope() + let flags = 0 + if (onlyChild) { + flags |= VaporVForFlags.FAST_REMOVE + } + if (component) { + flags |= VaporVForFlags.IS_COMPONENT + } + if (once) { + flags |= VaporVForFlags.ONCE + } + return [ NEWLINE, `const n${id} = `, @@ -88,9 +100,7 @@ export function genFor( sourceExpr, blockFn, genCallback(keyProp), - component && 'true', - once && 'true', - onlyChild && `true`, + flags ? String(flags) : undefined, // todo: hydrationNode ), ] diff --git a/packages/runtime-vapor/src/apiCreateFor.ts b/packages/runtime-vapor/src/apiCreateFor.ts index f8f0988704..19653cd5da 100644 --- a/packages/runtime-vapor/src/apiCreateFor.ts +++ b/packages/runtime-vapor/src/apiCreateFor.ts @@ -21,6 +21,7 @@ import { warn } from '@vue/runtime-dom' import { currentInstance, isVaporComponent } from './component' import type { DynamicSlot } from './componentSlots' import { renderEffect } from './renderEffect' +import { VaporVForFlags } from '../../shared/src/vaporFlags' class ForBlock extends VaporFragment { scope: EffectScope | undefined @@ -64,13 +65,7 @@ export const createFor = ( index: ShallowRef, ) => Block, getKey?: (item: any, key: any, index?: number) => any, - /** - * Whether this v-for is used directly on a component. If true, we can avoid - * creating an extra fragment / scope for each block - */ - isComponent = false, - once?: boolean, - canUseFastRemove?: boolean, + flags = 0, // hydrationNode?: Node, ): VaporFragment => { let isMounted = false @@ -80,6 +75,8 @@ export const createFor = ( const parentAnchor = __DEV__ ? createComment('for') : createTextNode() const frag = new VaporFragment(oldBlocks) const instance = currentInstance! + const canUseFastRemove = flags & VaporVForFlags.FAST_REMOVE + const isComponent = flags & VaporVForFlags.IS_COMPONENT if (__DEV__ && !instance) { warn('createFor() can only be used inside setup()') @@ -354,7 +351,11 @@ export const createFor = ( doRemove && removeBlock(nodes, parent!) } - once ? renderList() : renderEffect(renderList) + if (flags & VaporVForFlags.ONCE) { + renderList() + } else { + renderEffect(renderList) + } return frag } diff --git a/packages/shared/src/vaporFlags.ts b/packages/shared/src/vaporFlags.ts new file mode 100644 index 0000000000..2be48df4d9 --- /dev/null +++ b/packages/shared/src/vaporFlags.ts @@ -0,0 +1,20 @@ +/** + * Flags to optimize vapor `createFor` runtime behavior, shared between the + * compiler and the runtime + */ +export enum VaporVForFlags { + /** + * v-for is the only child of a parent container, so it can take the fast + * path with textContent = '' when the whole list is emptied + */ + FAST_REMOVE = 1, + /** + * v-for used on component - we can skip creating child scopes for each block + * because the component itself already has a scope. + */ + IS_COMPONENT = 1 << 1, + /** + * v-for inside v-ince + */ + ONCE = 1 << 2, +}