Răsfoiți Sursa

revert: "refactor: remove update function from compiler"

Bad for performance, so revert it temporarily

This reverts commit be65b98a3331ab956d5dcbf373718016e4b3ac75.
三咲智子 Kevin Deng 2 ani în urmă
părinte
comite
66cea4b325

+ 11 - 12
packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap

@@ -1,7 +1,7 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
 exports[`compiler: v-for > basic v-for 1`] = `
-"import { children as _children, on as _on, renderEffect as _renderEffect, setText as _setText, createFor as _createFor, template as _template } from 'vue/vapor';
+"import { children as _children, on as _on, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue/vapor';
 const t0 = _template("<div></div>")
 
 export function render(_ctx) {
@@ -9,33 +9,32 @@ export function render(_ctx) {
     const n2 = t0()
     const n3 = _children(n2, 0)
     _on(n3, "click", () => $event => (_ctx.remove(_block.s[0])))
-    _renderEffect(() => {
+    const _updateEffect = () => {
       const [item] = _block.s
       _setText(n3, item)
-    })
-    return n2
+    }
+    _renderEffect(_updateEffect)
+    return [n2, _updateEffect]
   }, (item) => (item.id))
   return [n1]
 }"
 `;
 
 exports[`compiler: v-for > multi effect 1`] = `
-"import { children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, createFor as _createFor, template as _template } from 'vue/vapor';
+"import { children as _children, setDynamicProp as _setDynamicProp, renderEffect as _renderEffect, createFor as _createFor, template as _template } from 'vue/vapor';
 const t0 = _template("<div></div>")
 
 export function render(_ctx) {
   const n1 = _createFor(() => (_ctx.items), (_block) => {
     const n2 = t0()
     const n3 = _children(n2, 0)
-    _renderEffect(() => {
+    const _updateEffect = () => {
       const [item, index] = _block.s
       _setDynamicProp(n3, "item", item)
-    })
-    _renderEffect(() => {
-      const [item, index] = _block.s
       _setDynamicProp(n3, "index", index)
-    })
-    return n2
+    }
+    _renderEffect(_updateEffect)
+    return [n2, _updateEffect]
   })
   return [n1]
 }"
@@ -48,7 +47,7 @@ const t0 = _template("<div>item</div>")
 export function render(_ctx) {
   const n1 = _createFor(() => (_ctx.items), (_block) => {
     const n2 = t0()
-    return n2
+    return [n2, () => {}]
   })
   return [n1]
 }"

+ 9 - 2
packages/compiler-vapor/src/generators/block.ts

@@ -21,13 +21,14 @@ export function genBlockFunction(
   oper: BlockFunctionIRNode,
   context: CodegenContext,
   args: CodeFragment[] = [],
+  returnValue?: () => CodeFragment[],
 ): CodeFragment[] {
   return [
     '(',
     ...args,
     ') => {',
     INDENT_START,
-    ...genBlockFunctionContent(oper, context),
+    ...genBlockFunctionContent(oper, context, returnValue),
     INDENT_END,
     NEWLINE,
     '}',
@@ -37,6 +38,7 @@ export function genBlockFunction(
 export function genBlockFunctionContent(
   ir: BlockFunctionIRNode | RootIRNode,
   context: CodegenContext,
+  returnValue?: () => CodeFragment[],
 ): CodeFragment[] {
   const [frag, push] = buildCodeFragment()
 
@@ -55,6 +57,7 @@ export function genBlockFunctionContent(
 
   push(...genOperations(ir.operation, context))
   push(...(context.genEffect || genEffects)(ir.effect, context))
+
   if (ir.returns) {
     push(
       NEWLINE,
@@ -62,7 +65,11 @@ export function genBlockFunctionContent(
       ...genMulti(['[', ']', ', '], ...ir.returns.map(n => `n${n}`)),
     )
   } else {
-    push(NEWLINE, `return n${ir.dynamic.id}`)
+    push(
+      NEWLINE,
+      'return ',
+      ...(returnValue ? returnValue() : [`n${ir.dynamic.id}`]),
+    )
   }
 
   return frag

+ 32 - 22
packages/compiler-vapor/src/generators/for.ts

@@ -3,7 +3,7 @@ import { genBlockFunction } from './block'
 import { genExpression } from './expression'
 import type { CodegenContext } from '../generate'
 import type { ForIRNode, IREffect } from '../ir'
-import { genOperation } from './operation'
+import { genOperations } from './operation'
 import {
   type CodeFragment,
   INDENT_END,
@@ -24,14 +24,19 @@ export function genFor(
   const rawKey = key && key.content
 
   const sourceExpr = ['() => (', ...genExpression(source, context), ')']
+  let updateFn = '_updateEffect'
   context.genEffect = genEffectInFor
 
   const idMap: Record<string, string> = {}
   if (rawValue) idMap[rawValue] = `_block.s[0]`
   if (rawKey) idMap[rawKey] = `_block.s[1]`
 
+  const blockRet = (): CodeFragment[] => [
+    `[n${render.dynamic.id!}, ${updateFn}]`,
+  ]
+
   const blockFn = context.withId(
-    () => genBlockFunction(render, context, ['_block']),
+    () => genBlockFunction(render, context, ['_block'], blockRet),
     idMap,
   )
 
@@ -63,16 +68,15 @@ export function genFor(
   ]
 
   function genEffectInFor(effects: IREffect[]): CodeFragment[] {
-    const [frag, push] = buildCodeFragment()
-
-    const idMap: Record<string, string | null> = {}
-    if (value) idMap[value.content] = null
-    if (key) idMap[key.content] = null
+    if (!effects.length) {
+      updateFn = '() => {}'
+      return []
+    }
 
-    let statement: CodeFragment[] = []
+    const [frag, push] = buildCodeFragment(INDENT_START)
+    // const [value, key] = _block.s
     if (rawValue || rawKey) {
-      // const [value, key] = _block.s
-      statement = [
+      push(
         NEWLINE,
         'const ',
         '[',
@@ -80,22 +84,28 @@ export function genFor(
         rawKey && ', ',
         rawKey && [rawKey, NewlineType.None, key.loc],
         '] = _block.s',
-      ]
+      )
     }
 
+    const idMap: Record<string, string | null> = {}
+    if (value) idMap[value.content] = null
+    if (key) idMap[key.content] = null
     context.withId(() => {
-      for (const { operations } of effects) {
-        push(
-          NEWLINE,
-          `${vaporHelper('renderEffect')}(() => {`,
-          INDENT_START,
-          ...statement,
-        )
-        operations.forEach(op => push(...genOperation(op, context)))
-        push(INDENT_END, NEWLINE, '})')
-      }
+      effects.forEach(effect =>
+        push(...genOperations(effect.operations, context)),
+      )
     }, idMap)
 
-    return frag
+    push(INDENT_END)
+
+    return [
+      NEWLINE,
+      `const ${updateFn} = () => {`,
+      ...frag,
+      NEWLINE,
+      '}',
+      NEWLINE,
+      `${vaporHelper('renderEffect')}(${updateFn})`,
+    ]
   }
 }

+ 4 - 3
packages/runtime-vapor/__tests__/for.spec.ts

@@ -24,11 +24,12 @@ describe('createFor', () => {
         () => sortedList.value,
         block => {
           const n3 = createTextNode()
-          renderEffect(() => {
+          const update = () => {
             const [item] = block.s
             setText(n3, item.name)
-          })
-          return [n3]
+          }
+          renderEffect(update)
+          return [n3, update]
         },
       )
       return [n1]

+ 4 - 3
packages/runtime-vapor/src/for.ts

@@ -15,7 +15,7 @@ interface ForBlock extends Fragment {
 /*! #__NO_SIDE_EFFECTS__ */
 export const createFor = (
   src: () => any[] | Record<string, string> | Set<any> | Map<any, any>,
-  renderItem: (block: ForBlock) => Block,
+  renderItem: (block: ForBlock) => [Block, () => void],
   getKey?: (item: any, index: number) => any,
   getMemo?: (item: any) => any[],
   hydrationNode?: Node,
@@ -46,8 +46,9 @@ export const createFor = (
       memo: getMemo && getMemo(item),
       [fragmentKey]: true,
     })
-    block.nodes = scope.run(() => renderItem(block))!
-    block.update = () => scope.effects.forEach(effect => effect.run())
+    const res = scope.run(() => renderItem(block))!
+    block.nodes = res[0]
+    block.update = res[1]
     if (getMemo) block.update()
     if (parent) insert(block.nodes, parent, anchor)
     return block