From: Anthony Fu Date: Thu, 16 May 2024 17:29:33 +0000 (+0200) Subject: perf(sfc): lazy initiatate hoisted vnodes X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e15802590479e775c84071a9b7d037a9316cf94b;p=thirdparty%2Fvuejs%2Fcore.git perf(sfc): lazy initiatate hoisted vnodes --- diff --git a/packages/compiler-core/src/codegen.ts b/packages/compiler-core/src/codegen.ts index 987293d512..58f697c9a8 100644 --- a/packages/compiler-core/src/codegen.ts +++ b/packages/compiler-core/src/codegen.ts @@ -42,6 +42,7 @@ import { CREATE_STATIC, CREATE_TEXT, CREATE_VNODE, + HOIST_LAZY, OPEN_BLOCK, POP_SCOPE_ID, PUSH_SCOPE_ID, @@ -476,6 +477,7 @@ function genModulePreamble( if (genScopeId && ast.hoists.length) { ast.helpers.add(PUSH_SCOPE_ID) ast.helpers.add(POP_SCOPE_ID) + ast.helpers.add(HOIST_LAZY) } // generate import statements for helpers @@ -585,14 +587,15 @@ function genHoists(hoists: (JSChildNode | null)[], context: CodegenContext) { if (exp) { const needScopeIdWrapper = genScopeId && exp.type === NodeTypes.VNODE_CALL push( - `const _hoisted_${i + 1} = ${ - needScopeIdWrapper ? `${PURE_ANNOTATION} _withScopeId(() => ` : `` + `const _hoisted_${i + 1} = ${PURE_ANNOTATION} ${helper(HOIST_LAZY)}(() => (${ + needScopeIdWrapper ? `_withScopeId(() => ` : `` }`, ) genNode(exp, context) if (needScopeIdWrapper) { push(`)`) } + push('))') newline() } } diff --git a/packages/compiler-core/src/runtimeHelpers.ts b/packages/compiler-core/src/runtimeHelpers.ts index 47ab73e011..fe1e6a376c 100644 --- a/packages/compiler-core/src/runtimeHelpers.ts +++ b/packages/compiler-core/src/runtimeHelpers.ts @@ -9,6 +9,7 @@ export const CREATE_ELEMENT_BLOCK = Symbol(__DEV__ ? `createElementBlock` : ``) export const CREATE_VNODE = Symbol(__DEV__ ? `createVNode` : ``) export const CREATE_ELEMENT_VNODE = Symbol(__DEV__ ? `createElementVNode` : ``) export const CREATE_COMMENT = Symbol(__DEV__ ? `createCommentVNode` : ``) +export const HOIST_LAZY = Symbol(__DEV__ ? `hoistLazy` : ``) export const CREATE_TEXT = Symbol(__DEV__ ? `createTextVNode` : ``) export const CREATE_STATIC = Symbol(__DEV__ ? `createStaticVNode` : ``) export const RESOLVE_COMPONENT = Symbol(__DEV__ ? `resolveComponent` : ``) @@ -79,6 +80,7 @@ export const helperNameMap: Record = { [POP_SCOPE_ID]: `popScopeId`, [WITH_CTX]: `withCtx`, [UNREF]: `unref`, + [HOIST_LAZY]: `hoistLazy`, [IS_REF]: `isRef`, [WITH_MEMO]: `withMemo`, [IS_MEMO_SAME]: `isMemoSame`, diff --git a/packages/compiler-core/src/transform.ts b/packages/compiler-core/src/transform.ts index 69821f7f87..81b1626778 100644 --- a/packages/compiler-core/src/transform.ts +++ b/packages/compiler-core/src/transform.ts @@ -288,7 +288,7 @@ export function createTransformContext( if (isString(exp)) exp = createSimpleExpression(exp) context.hoists.push(exp) const identifier = createSimpleExpression( - `_hoisted_${context.hoists.length}`, + `_hoisted_${context.hoists.length}()`, false, exp.loc, ConstantTypes.CAN_HOIST, diff --git a/packages/compiler-core/src/transforms/hoistStatic.ts b/packages/compiler-core/src/transforms/hoistStatic.ts index 70a0468e51..ab3a5d6db0 100644 --- a/packages/compiler-core/src/transforms/hoistStatic.ts +++ b/packages/compiler-core/src/transforms/hoistStatic.ts @@ -21,6 +21,7 @@ import { PatchFlags, isArray, isString, isSymbol } from '@vue/shared' import { isSlotOutlet } from '../utils' import { GUARD_REACTIVE_PROPS, + HOIST_LAZY, NORMALIZE_CLASS, NORMALIZE_PROPS, NORMALIZE_STYLE, @@ -70,6 +71,7 @@ function walk( : getConstantType(child, context) if (constantType > ConstantTypes.NOT_CONSTANT) { if (constantType >= ConstantTypes.CAN_HOIST) { + context.helper(HOIST_LAZY) ;(child.codegenNode as VNodeCall).patchFlag = PatchFlags.HOISTED + (__DEV__ ? ` /* HOISTED */` : ``) child.codegenNode = context.hoist(child.codegenNode!) diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 94b2985040..be233178e3 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -97,7 +97,13 @@ export { getCurrentInstance } from './component' // For raw render function users export { h } from './h' // Advanced render function utilities -export { createVNode, cloneVNode, mergeProps, isVNode } from './vnode' +export { + createVNode, + cloneVNode, + mergeProps, + isVNode, + hoistLazy, +} from './vnode' // VNode types export { Fragment, Text, Comment, Static, type VNodeRef } from './vnode' // Built-in components diff --git a/packages/runtime-core/src/vnode.ts b/packages/runtime-core/src/vnode.ts index 0e2a4bafcc..24074ba821 100644 --- a/packages/runtime-core/src/vnode.ts +++ b/packages/runtime-core/src/vnode.ts @@ -875,3 +875,13 @@ export function invokeVNodeHook( prevVNode, ]) } + +export function hoistLazy(fn: () => T): () => T { + let cache: T | undefined + return (): T => { + if (!cache) { + cache = fn() + } + return cache + } +}