perf(sfc): lazy initiatate hoisted vnodes

This commit is contained in:
Anthony Fu 2024-05-16 19:29:33 +02:00
parent 6a8d548506
commit e158025904
6 changed files with 27 additions and 4 deletions

View File

@ -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()
}
}

View File

@ -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<symbol, string> = {
[POP_SCOPE_ID]: `popScopeId`,
[WITH_CTX]: `withCtx`,
[UNREF]: `unref`,
[HOIST_LAZY]: `hoistLazy`,
[IS_REF]: `isRef`,
[WITH_MEMO]: `withMemo`,
[IS_MEMO_SAME]: `isMemoSame`,

View File

@ -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,

View File

@ -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!)

View File

@ -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

View File

@ -875,3 +875,13 @@ export function invokeVNodeHook(
prevVNode,
])
}
export function hoistLazy<T>(fn: () => T): () => T {
let cache: T | undefined
return (): T => {
if (!cache) {
cache = fn()
}
return cache
}
}