]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
perf(sfc): lazy initiatate hoisted vnodes
authorAnthony Fu <anthonyfu117@hotmail.com>
Thu, 16 May 2024 17:29:33 +0000 (19:29 +0200)
committerAnthony Fu <anthonyfu117@hotmail.com>
Thu, 16 May 2024 17:29:33 +0000 (19:29 +0200)
packages/compiler-core/src/codegen.ts
packages/compiler-core/src/runtimeHelpers.ts
packages/compiler-core/src/transform.ts
packages/compiler-core/src/transforms/hoistStatic.ts
packages/runtime-core/src/index.ts
packages/runtime-core/src/vnode.ts

index 987293d512497ed455480f2d418ac7cd9d1bfc7f..58f697c9a8958095b9a0af26213b7ddc2b2c3570 100644 (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()
     }
   }
index 47ab73e011a1243ae074b2fe557805ef67b70aec..fe1e6a376c46ab78be3a5e4f22123bf880bc1241 100644 (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`,
index 69821f7f879f30263cc6e216b26cf50aa27c290b..81b1626778f70bd40e271d17a1c8a6f2fd8d1e65 100644 (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,
index 70a0468e5196893ff059d75ab028eda5fc6ba545..ab3a5d6db0ba65c8383a36b6b99bc486f708752f 100644 (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!)
index 94b2985040acfeadf07ce890e0de470b2d5f5d3d..be233178e345d6c6c33e83b9d99b8116d5801d51 100644 (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
index 0e2a4bafcc5ae6d69cc7978a58dc10f30b69c15c..24074ba82177db476e2e04da6a7088b7a58a5033 100644 (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
+  }
+}