]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor(vapor): use bitwise flags for v-for runtime optimizations
authorEvan You <evan@vuejs.org>
Wed, 12 Feb 2025 07:28:10 +0000 (15:28 +0800)
committerEvan You <evan@vuejs.org>
Wed, 12 Feb 2025 07:40:09 +0000 (15:40 +0800)
packages/compiler-vapor/__tests__/transforms/__snapshots__/transformTemplateRef.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/__snapshots__/vOnce.spec.ts.snap
packages/compiler-vapor/src/generators/for.ts
packages/runtime-vapor/src/apiCreateFor.ts
packages/shared/src/vaporFlags.ts [new file with mode: 0644]

index 15da71ff4f320a1f4c60d4a15a91239f07f05df5..f2eade4bcdf4e275f5a0b839ae9d762de1bb54a7 100644 (file)
@@ -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
 }"
 `;
index d7e763e849cb7a02dc70c019e094e3fd8c385387..02235ddd99baeba7852f2c6b6dde78704055a212 100644 (file)
@@ -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
   })
index 94fd139589bbbfd146ee3a548152511e8fc42c53..9cbe1bd0d348d93d82bc6ab6fdbdf84798931d60 100644 (file)
@@ -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
 }"
 `;
index 6f596499ff103d58fc74441d44befc9ebbbb51db..fbb72c61d476eda757c7ea4179b4efcac95a6e8f 100644 (file)
@@ -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
     ),
   ]
index f8f0988704c76c4a9f4d2332092078084bd4a5ce..19653cd5daab80ec77ba3767435585ae20b9f5b3 100644 (file)
@@ -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<number | undefined>,
   ) => 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 (file)
index 0000000..2be48df
--- /dev/null
@@ -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,
+}