]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor: remove update function from compiler
author三咲智子 Kevin Deng <sxzz@sxzz.moe>
Fri, 2 Feb 2024 21:02:07 +0000 (05:02 +0800)
committer三咲智子 Kevin Deng <sxzz@sxzz.moe>
Fri, 2 Feb 2024 21:02:07 +0000 (05:02 +0800)
packages/compiler-vapor/__tests__/transforms/__snapshots__/vFor.spec.ts.snap
packages/compiler-vapor/__tests__/transforms/vFor.spec.ts
packages/compiler-vapor/src/generators/block.ts
packages/compiler-vapor/src/generators/for.ts
packages/compiler-vapor/src/generators/operation.ts
packages/runtime-vapor/src/for.ts

index ed3f04907305dcdb4db51707105aea41e03ebb88..f0eea1022fc955d2dbd61a3658c7ddba0c50b5a3 100644 (file)
@@ -1,7 +1,7 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
 exports[`compiler: v-for > basic v-for 1`] = `
-"import { template as _template, fragment as _fragment, children as _children, on as _on, setText as _setText, renderEffect as _renderEffect, createFor as _createFor, append as _append } from 'vue/vapor';
+"import { template as _template, fragment as _fragment, children as _children, on as _on, renderEffect as _renderEffect, setText as _setText, createFor as _createFor, append as _append } from 'vue/vapor';
 
 export function render(_ctx) {
   const t0 = _template("<div></div>")
@@ -11,19 +11,43 @@ export function render(_ctx) {
     const n2 = t0()
     const { 0: [n3],} = _children(n2)
     _on(n3, "click", $event => (_ctx.remove(_block.s[0])))
-    const _updateEffect = () => {
+    _renderEffect(() => {
       const [item] = _block.s
       _setText(n3, item)
-    }
-    _renderEffect(_updateEffect)
-    return [n2, _updateEffect]
+    })
+    return n2
   })
   _append(n0, n1)
   return n0
 }"
 `;
 
-exports[`compiler: v-for > basic v-for 2`] = `
+exports[`compiler: v-for > multi effect 1`] = `
+"import { template as _template, fragment as _fragment, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp, createFor as _createFor, append as _append } from 'vue/vapor';
+
+export function render(_ctx) {
+  const t0 = _template("<div></div>")
+  const t1 = _fragment()
+  const n0 = t1()
+  const n1 = _createFor(() => (_ctx.items), (_block) => {
+    const n2 = t0()
+    const { 0: [n3],} = _children(n2)
+    _renderEffect(() => {
+      const [item, index] = _block.s
+      _setDynamicProp(n3, "item", item)
+    })
+    _renderEffect(() => {
+      const [item, index] = _block.s
+      _setDynamicProp(n3, "index", index)
+    })
+    return n2
+  })
+  _append(n0, n1)
+  return n0
+}"
+`;
+
+exports[`compiler: v-for > w/o value 1`] = `
 "import { template as _template, fragment as _fragment, createFor as _createFor, append as _append } from 'vue/vapor';
 
 export function render(_ctx) {
@@ -32,7 +56,7 @@ export function render(_ctx) {
   const n0 = t1()
   const n1 = _createFor(() => (_ctx.items), (_block) => {
     const n2 = t0()
-    return [n2, () => {}]
+    return n2
   })
   _append(n0, n1)
   return n0
index bfa31ab53752ae8fbfc3a649ab92d12ea4f26773..d02737a39ccf4762722e8d74d3fb7e663a185a94 100644 (file)
@@ -4,6 +4,7 @@ import {
   IRNodeTypes,
   transformElement,
   transformInterpolation,
+  transformVBind,
   transformVFor,
   transformVOn,
 } from '../../src'
@@ -11,7 +12,10 @@ import { NodeTypes } from '@vue/compiler-dom'
 
 const compileWithVFor = makeCompile({
   nodeTransforms: [transformInterpolation, transformVFor, transformElement],
-  directiveTransforms: { on: transformVOn },
+  directiveTransforms: {
+    bind: transformVBind,
+    on: transformVOn,
+  },
 })
 
 describe('compiler: v-for', () => {
@@ -66,8 +70,22 @@ describe('compiler: v-for', () => {
     expect((ir.operation[0] as ForIRNode).render.effect).lengthOf(1)
   })
 
-  test('basic v-for', () => {
+  test('multi effect', () => {
+    const { code } = compileWithVFor(
+      `<div v-for="(item, index) of items" :item="item" :index="index" />`,
+    )
+    expect(code).matchSnapshot()
+  })
+
+  test('w/o value', () => {
     const { code } = compileWithVFor(`<div v-for=" of items">item</div>`)
     expect(code).matchSnapshot()
   })
+
+  test.todo('object de-structured value', () => {
+    const { code } = compileWithVFor(
+      '<span v-for="({ id, value }) in items">{{ id }}{{ value }}</span>',
+    )
+    expect(code).matchSnapshot()
+  })
 })
index ddae02f025467eec65f518c6be56fb0e257b96be..b42166a703903d4d02448cdcee1fd9c8fb6bb336 100644 (file)
@@ -21,14 +21,13 @@ export function genBlockFunction(
   oper: BlockFunctionIRNode,
   context: CodegenContext,
   args: CodeFragment[] = [],
-  returnValue?: () => CodeFragment[],
 ): CodeFragment[] {
   return [
     '(',
     ...args,
     ') => {',
     INDENT_START,
-    ...genBlockFunctionContent(oper, context, returnValue),
+    ...genBlockFunctionContent(oper, context),
     INDENT_END,
     NEWLINE,
     '}',
@@ -38,7 +37,6 @@ export function genBlockFunction(
 export function genBlockFunctionContent(
   ir: BlockFunctionIRNode | RootIRNode,
   context: CodegenContext,
-  returnValue?: () => CodeFragment[],
 ): CodeFragment[] {
   const { vaporHelper } = context
   const [frag, push] = buildCodeFragment(
@@ -63,13 +61,8 @@ export function genBlockFunctionContent(
   }
 
   push(...genOperations(ir.operation, context))
-  push(...genEffects(ir.effect, context))
-
-  push(
-    NEWLINE,
-    'return ',
-    ...(returnValue ? returnValue() : [`n${ir.dynamic.id}`]),
-  )
+  push(...(context.genEffect || genEffects)(ir.effect, context))
+  push(NEWLINE, `return n${ir.dynamic.id}`)
 
   return frag
 }
index 9640553e83958c57b76544e6e84227df0d0eef4d..c1446e7d9d98e7dac6aaa76dec6ad2a270885626 100644 (file)
@@ -9,7 +9,7 @@ import {
   buildCodeFragment,
 } from '../generate'
 import type { ForIRNode, IREffect } from '../ir'
-import { genOperations } from './operation'
+import { genOperation } from './operation'
 import { NewlineType } from '@vue/compiler-dom'
 
 export function genFor(
@@ -23,19 +23,14 @@ 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'], blockRet),
+    () => genBlockFunction(render, context, ['_block']),
     idMap,
   )
 
@@ -48,15 +43,16 @@ export function genFor(
   ]
 
   function genEffectInFor(effects: IREffect[]): CodeFragment[] {
-    if (!effects.length) {
-      updateFn = '() => {}'
-      return []
-    }
+    const [frag, push] = buildCodeFragment()
 
-    const [frag, push] = buildCodeFragment(INDENT_START)
-    // const [value, key] = _block.s
+    const idMap: Record<string, string | null> = {}
+    if (value) idMap[value.content] = null
+    if (key) idMap[key.content] = null
+
+    let statement: CodeFragment[] = []
     if (rawValue || rawKey) {
-      push(
+      // const [value, key] = _block.s
+      statement = [
         NEWLINE,
         'const ',
         '[',
@@ -64,28 +60,22 @@ 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(() => {
-      effects.forEach(effect =>
-        push(...genOperations(effect.operations, context)),
-      )
+      for (const { operations } of effects) {
+        push(
+          NEWLINE,
+          `${vaporHelper('renderEffect')}(() => {`,
+          INDENT_START,
+          ...statement,
+        )
+        operations.forEach(op => push(...genOperation(op, context)))
+        push(INDENT_END, NEWLINE, '})')
+      }
     }, idMap)
 
-    push(INDENT_END)
-
-    return [
-      NEWLINE,
-      `const ${updateFn} = () => {`,
-      ...frag,
-      NEWLINE,
-      '}',
-      NEWLINE,
-      `${vaporHelper('renderEffect')}(${updateFn})`,
-    ]
+    return frag
   }
 }
index d1d5575702f56cfbfc3e6a69797ed2ae896943c6..c672281ce79af11ba76abe05d4eefbc3534f34f7 100644 (file)
@@ -25,7 +25,7 @@ export function genOperations(opers: OperationNode[], context: CodegenContext) {
   return frag
 }
 
-function genOperation(
+export function genOperation(
   oper: OperationNode,
   context: CodegenContext,
 ): CodeFragment[] {
@@ -60,9 +60,6 @@ function genOperation(
 }
 
 export function genEffects(effects: IREffect[], context: CodegenContext) {
-  if (context.genEffect) {
-    return context.genEffect(effects)
-  }
   const [frag, push] = buildCodeFragment()
   for (const effect of effects) {
     push(...genEffect(effect, context))
@@ -70,7 +67,7 @@ export function genEffects(effects: IREffect[], context: CodegenContext) {
   return frag
 }
 
-function genEffect({ operations }: IREffect, context: CodegenContext) {
+export function genEffect({ operations }: IREffect, context: CodegenContext) {
   const { vaporHelper } = context
   const [frag, push] = buildCodeFragment(
     NEWLINE,
index ed68491ead9bdeb2464d542baf15a5a7ed1903ed..c486643c831f517b948f4e0f1562814ea5d6a720 100644 (file)
@@ -15,7 +15,7 @@ interface ForBlock extends Fragment {
 
 export const createFor = (
   src: () => any[] | Record<string, string> | Set<any> | Map<any, any>,
-  renderItem: (block: ForBlock) => [Block, () => void],
+  renderItem: (block: ForBlock) => Block,
   getKey: ((item: any, index: number) => any) | null,
   getMemo?: (item: any) => any[],
   hydrationNode?: Node,
@@ -47,9 +47,8 @@ export const createFor = (
       memo: getMemo && getMemo(item),
       [fragmentKey]: true,
     })
-    const res = scope.run(() => renderItem(block))!
-    block.nodes = res[0]
-    block.update = res[1]
+    block.nodes = scope.run(() => renderItem(block))!
+    block.update = () => scope.effects.forEach(effect => effect.run())
     if (getMemo) block.update()
     if (parent) insert(block.nodes, parent, anchor)
     return block