Browse Source

fix(compiler-vapor): emit dynamic component handlers directly (#14826)

edison 4 weeks ago
parent
commit
87013357e2

+ 15 - 3
packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap

@@ -329,7 +329,7 @@ exports[`compiler: element transform > component dynamic event with once modifie
 export function render(_ctx) {
 export function render(_ctx) {
   const _component_Foo = _resolveComponent("Foo")
   const _component_Foo = _resolveComponent("Foo")
   const n0 = _createComponentWithFallback(_component_Foo, { $: [
   const n0 = _createComponentWithFallback(_component_Foo, { $: [
-    () => ({ [_toHandlerKey(_ctx.foo) + "Once"]: () => _ctx.bar })
+    () => ({ [_toHandlerKey(_ctx.foo) + "Once"]: _ctx.bar })
   ] }, null, true)
   ] }, null, true)
   return n0
   return n0
 }"
 }"
@@ -381,8 +381,20 @@ exports[`compiler: element transform > component with dynamic event arguments 1`
 export function render(_ctx) {
 export function render(_ctx) {
   const _component_Foo = _resolveComponent("Foo")
   const _component_Foo = _resolveComponent("Foo")
   const n0 = _createComponentWithFallback(_component_Foo, { $: [
   const n0 = _createComponentWithFallback(_component_Foo, { $: [
-    () => ({ [_toHandlerKey(_ctx.foo-_ctx.bar)]: () => _ctx.bar }),
-    () => ({ [_toHandlerKey(_ctx.baz)]: () => _ctx.qux })
+    () => ({ [_toHandlerKey(_ctx.foo-_ctx.bar)]: _ctx.bar }),
+    () => ({ [_toHandlerKey(_ctx.baz)]: _ctx.qux })
+  ] }, null, true)
+  return n0
+}"
+`;
+
+exports[`compiler: element transform > component with dynamic event arguments and inline statement 1`] = `
+"import { resolveComponent as _resolveComponent, toHandlerKey as _toHandlerKey, createComponentWithFallback as _createComponentWithFallback } from 'vue';
+
+export function render(_ctx) {
+  const _component_Foo = _resolveComponent("Foo")
+  const n0 = _createComponentWithFallback(_component_Foo, { $: [
+    () => ({ [_toHandlerKey(_ctx.event)]: $event => (_ctx.bar($event)) })
   ] }, null, true)
   ] }, null, true)
   return n0
   return n0
 }"
 }"

+ 5 - 5
packages/compiler-vapor/__tests__/transforms/__snapshots__/vModel.spec.ts.snap

@@ -79,13 +79,13 @@ export function render(_ctx) {
   const n0 = _createComponentWithFallback(_component_Comp, { $: [
   const n0 = _createComponentWithFallback(_component_Comp, { $: [
     () => ({
     () => ({
       [_ctx.foo]: _ctx.foo,
       [_ctx.foo]: _ctx.foo,
-      ["onUpdate:" + _ctx.foo]: () => _value => (_ctx.foo = _value),
-      [_ctx.foo + "Modifiers"]: () => ({ trim: true })
+      ["onUpdate:" + _ctx.foo]: _value => (_ctx.foo = _value),
+      [_ctx.foo + "Modifiers"]: { trim: true }
     }),
     }),
     () => ({
     () => ({
       [_ctx.bar]: _ctx.bar,
       [_ctx.bar]: _ctx.bar,
-      ["onUpdate:" + _ctx.bar]: () => _value => (_ctx.bar = _value),
-      [_ctx.bar + "Modifiers"]: () => ({ number: true })
+      ["onUpdate:" + _ctx.bar]: _value => (_ctx.bar = _value),
+      [_ctx.bar + "Modifiers"]: { number: true }
     })
     })
   ] }, null, true)
   ] }, null, true)
   return n0
   return n0
@@ -100,7 +100,7 @@ export function render(_ctx) {
   const n0 = _createComponentWithFallback(_component_Comp, { $: [
   const n0 = _createComponentWithFallback(_component_Comp, { $: [
     () => ({
     () => ({
       [_ctx.arg]: _ctx.foo,
       [_ctx.arg]: _ctx.foo,
-      ["onUpdate:" + _ctx.arg]: () => _value => (_ctx.foo = _value)
+      ["onUpdate:" + _ctx.arg]: _value => (_ctx.foo = _value)
     })
     })
   ] }, null, true)
   ] }, null, true)
   return n0
   return n0

+ 24 - 0
packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts

@@ -1096,6 +1096,8 @@ describe('compiler: element transform', () => {
       `<Foo @[foo-bar]="bar" @[baz]="qux" />`,
       `<Foo @[foo-bar]="bar" @[baz]="qux" />`,
     )
     )
     expect(code).toMatchSnapshot()
     expect(code).toMatchSnapshot()
+    expect(code).contains('[_toHandlerKey(_ctx.foo-_ctx.bar)]: _ctx.bar')
+    expect(code).contains('[_toHandlerKey(_ctx.baz)]: _ctx.qux')
     expect(ir.block.dynamic.children[0].operation).toMatchObject({
     expect(ir.block.dynamic.children[0].operation).toMatchObject({
       type: IRNodeTypes.CREATE_COMPONENT_NODE,
       type: IRNodeTypes.CREATE_COMPONENT_NODE,
       tag: 'Foo',
       tag: 'Foo',
@@ -1116,6 +1118,28 @@ describe('compiler: element transform', () => {
     })
     })
   })
   })
 
 
+  test('component with dynamic event arguments and inline statement', () => {
+    const { code, ir } = compileWithElementTransform(
+      `<Foo @[event]="bar($event)" />`,
+    )
+    expect(code).toMatchSnapshot()
+    expect(code).contains(
+      '[_toHandlerKey(_ctx.event)]: $event => (_ctx.bar($event))',
+    )
+    expect(ir.block.dynamic.children[0].operation).toMatchObject({
+      type: IRNodeTypes.CREATE_COMPONENT_NODE,
+      tag: 'Foo',
+      props: [
+        {
+          kind: IRDynamicPropsKind.ATTRIBUTE,
+          key: { content: 'event' },
+          values: [{ content: 'bar($event)' }],
+          handler: true,
+        },
+      ],
+    })
+  })
+
   test('component event with once modifier', () => {
   test('component event with once modifier', () => {
     const { code } = compileWithElementTransform(`<Foo @foo.once="bar" />`)
     const { code } = compileWithElementTransform(`<Foo @foo.once="bar" />`)
     expect(code).toMatchSnapshot()
     expect(code).toMatchSnapshot()

+ 5 - 5
packages/compiler-vapor/__tests__/transforms/vModel.spec.ts

@@ -252,7 +252,7 @@ describe('compiler: vModel transform', () => {
       expect(code).contains(
       expect(code).contains(
         `() => ({
         `() => ({
       [_ctx.arg]: _ctx.foo,
       [_ctx.arg]: _ctx.foo,
-      ["onUpdate:" + _ctx.arg]: () => _value => (_ctx.foo = _value)
+      ["onUpdate:" + _ctx.arg]: _value => (_ctx.foo = _value)
     })`,
     })`,
       )
       )
       expect(ir.block.dynamic.children[0].operation).toMatchObject({
       expect(ir.block.dynamic.children[0].operation).toMatchObject({
@@ -350,13 +350,13 @@ describe('compiler: vModel transform', () => {
       )
       )
       expect(code).toMatchSnapshot()
       expect(code).toMatchSnapshot()
       expect(code).contain(
       expect(code).contain(
-        '["onUpdate:" + _ctx.foo]: () => _value => (_ctx.foo = _value)',
+        '["onUpdate:" + _ctx.foo]: _value => (_ctx.foo = _value)',
       )
       )
-      expect(code).contain(`[_ctx.foo + "Modifiers"]: () => ({ trim: true })`)
+      expect(code).contain(`[_ctx.foo + "Modifiers"]: { trim: true }`)
       expect(code).contain(
       expect(code).contain(
-        '["onUpdate:" + _ctx.bar]: () => _value => (_ctx.bar = _value)',
+        '["onUpdate:" + _ctx.bar]: _value => (_ctx.bar = _value)',
       )
       )
-      expect(code).contain(`[_ctx.bar + "Modifiers"]: () => ({ number: true })`)
+      expect(code).contain(`[_ctx.bar + "Modifiers"]: { number: true }`)
       expect(ir.block.dynamic.children[0].operation).toMatchObject({
       expect(ir.block.dynamic.children[0].operation).toMatchObject({
         type: IRNodeTypes.CREATE_COMPONENT_NODE,
         type: IRNodeTypes.CREATE_COMPONENT_NODE,
         tag: 'Comp',
         tag: 'Comp',

+ 13 - 5
packages/compiler-vapor/src/generators/component.ts

@@ -368,7 +368,7 @@ function genDynamicProps(
               ] as CodeFragment[])
               ] as CodeFragment[])
           entries.push([
           entries.push([
             ...updateKey,
             ...updateKey,
-            ': () => ',
+            ': ',
             ...genModelHandler(p.values[0], context),
             ...genModelHandler(p.values[0], context),
           ])
           ])
 
 
@@ -383,12 +383,15 @@ function genDynamicProps(
                   ' + "Modifiers"]',
                   ' + "Modifiers"]',
                 ] as CodeFragment[])
                 ] as CodeFragment[])
             const modifiersVal = genDirectiveModifiers(modelModifiers)
             const modifiersVal = genDirectiveModifiers(modelModifiers)
-            entries.push([...modifiersKey, `: () => ({ ${modifiersVal} })`])
+            entries.push([...modifiersKey, `: { ${modifiersVal} }`])
           }
           }
 
 
           expr = genMulti(DELIMITERS_OBJECT_NEWLINE, ...entries)
           expr = genMulti(DELIMITERS_OBJECT_NEWLINE, ...entries)
         } else {
         } else {
-          expr = genMulti(DELIMITERS_OBJECT, genProp(p, context))
+          expr = genMulti(
+            DELIMITERS_OBJECT,
+            genProp(p, context, false, false /* wrapHandler */),
+          )
         }
         }
       } else {
       } else {
         expr = genExpression(p.value, context)
         expr = genExpression(p.value, context)
@@ -402,7 +405,12 @@ function genDynamicProps(
   }
   }
 }
 }
 
 
-function genProp(prop: IRProp, context: CodegenContext, isStatic?: boolean) {
+function genProp(
+  prop: IRProp,
+  context: CodegenContext,
+  isStatic?: boolean,
+  wrapHandler = true,
+) {
   const values = genPropValue(prop.values, context)
   const values = genPropValue(prop.values, context)
   return [
   return [
     ...genPropKey(prop, context),
     ...genPropKey(prop, context),
@@ -413,7 +421,7 @@ function genProp(prop: IRProp, context: CodegenContext, isStatic?: boolean) {
           prop.values,
           prop.values,
           prop.handlerModifiers,
           prop.handlerModifiers,
           true /* asComponentProp */,
           true /* asComponentProp */,
-          true /* wrapInGetter */,
+          wrapHandler /* wrapInGetter */,
         )
         )
       : isStatic
       : isStatic
         ? ['() => (', ...values, ')']
         ? ['() => (', ...values, ')']

+ 51 - 0
packages/runtime-vapor/__tests__/componentEmits.spec.ts

@@ -451,6 +451,57 @@ describe('component: emit', () => {
     expect(handler).toHaveBeenCalledTimes(1)
     expect(handler).toHaveBeenCalledTimes(1)
   })
   })
 
 
+  test('should trigger once handler from dynamic source', () => {
+    const { render } = define({
+      setup(_, { emit }) {
+        emit('foo')
+        emit('foo')
+        return []
+      },
+    })
+
+    const handler = vi.fn()
+    render({
+      $: [
+        () => ({
+          onFooOnce: handler,
+        }),
+      ],
+    } as any)
+
+    expect(handler).toHaveBeenCalledTimes(1)
+  })
+
+  test('v-model modifiers should work from dynamic source', () => {
+    const { render } = define({
+      setup(_, { emit }) {
+        emit('update:modelValue', '1')
+        emit('update:foo', '  two  ')
+        return []
+      },
+    })
+
+    const fn1 = vi.fn()
+    const fn2 = vi.fn()
+    render({
+      $: [
+        () => ({
+          modelValue: null,
+          modelModifiers: { number: true },
+          ['onUpdate:modelValue']: fn1,
+          foo: null,
+          fooModifiers: { trim: true },
+          ['onUpdate:foo']: fn2,
+        }),
+      ],
+    } as any)
+
+    expect(fn1).toHaveBeenCalledTimes(1)
+    expect(fn1).toHaveBeenCalledWith(1)
+    expect(fn2).toHaveBeenCalledTimes(1)
+    expect(fn2).toHaveBeenCalledWith('two')
+  })
+
   test('should re-queue when child emit mutates parent state during update', async () => {
   test('should re-queue when child emit mutates parent state during update', async () => {
     const show = ref(false)
     const show = ref(false)
     const calls: string[] = []
     const calls: string[] = []