Explorar o código

fix(compiler-vapor): preserve :is prop on normal components (#14491)

edison hai 1 mes
pai
achega
c763388867

+ 20 - 0
packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap

@@ -409,6 +409,16 @@ export function render(_ctx) {
 }"
 `;
 
+exports[`compiler: element transform > dynamic component > component keeps both :is and is props 1`] = `
+"import { createComponent as _createComponent } from 'vue';
+
+export function render(_ctx, $props, $emit, $attrs, $slots) {
+  const n0 = _createComponent(_ctx.Comp, { is: () => ("Parent") })
+  const n1 = _createComponent(_ctx.Comp, { is: () => ("Parent") })
+  return [n0, n1]
+}"
+`;
+
 exports[`compiler: element transform > dynamic component > dynamic binding 1`] = `
 "import { createDynamicComponent as _createDynamicComponent } from 'vue';
 
@@ -427,6 +437,16 @@ export function render(_ctx) {
 }"
 `;
 
+exports[`compiler: element transform > dynamic component > normal component with dynamic :is prop 1`] = `
+"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
+
+export function render(_ctx) {
+  const _component_custom_input = _resolveComponent("custom-input")
+  const n0 = _createComponentWithFallback(_component_custom_input, { is: () => ("foo") }, null, true)
+  return n0
+}"
+`;
+
 exports[`compiler: element transform > dynamic component > normal component with is prop 1`] = `
 "import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
 

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

@@ -573,6 +573,45 @@ describe('compiler: element transform', () => {
         props: [[{ key: { content: 'is' }, values: [{ content: 'foo' }] }]],
       })
     })
+
+    test('normal component with dynamic :is prop', () => {
+      const { code, ir, helpers } = compileWithElementTransform(
+        `<custom-input :is="'foo'" />`,
+        {
+          isNativeTag: () => false,
+        },
+      )
+      expect(code).toMatchSnapshot()
+      expect(helpers).toContain('resolveComponent')
+      expect(helpers).not.toContain('resolveDynamicComponent')
+      expect(code).toContain(
+        '_createComponentWithFallback(_component_custom_input, { is: () => ("foo") }, null, true)',
+      )
+      expect(ir.block.dynamic.children[0].operation).toMatchObject({
+        type: IRNodeTypes.CREATE_COMPONENT_NODE,
+        tag: 'custom-input',
+        asset: true,
+        root: true,
+        props: [[{ key: { content: 'is' } }]],
+      })
+    })
+
+    test('component keeps both :is and is props', () => {
+      const { code } = compileWithElementTransform(
+        `<Comp :is="'Parent'" /><Comp is="Parent" />`,
+        {
+          bindingMetadata: {
+            Comp: BindingTypes.SETUP_CONST,
+          },
+        },
+      )
+      expect(code).toMatchSnapshot()
+      expect(
+        code.match(
+          /_createComponent\(_ctx\.Comp, \{ is: \(\) => \("Parent"\) \}\)/g,
+        )?.length,
+      ).toBe(2)
+    })
   })
 
   test('checkbox with static indeterminate', () => {

+ 6 - 7
packages/compiler-vapor/src/transforms/transformElement.ts

@@ -477,14 +477,13 @@ export function buildProps(
       }
     }
 
-    // exclude `is` prop for <component>
+    // exclude `is` prop only for <component>
     if (
-      (isDynamicComponent &&
-        prop.type === NodeTypes.ATTRIBUTE &&
-        prop.name === 'is') ||
-      (prop.type === NodeTypes.DIRECTIVE &&
-        prop.name === 'bind' &&
-        isStaticArgOf(prop.arg, 'is'))
+      isDynamicComponent &&
+      ((prop.type === NodeTypes.ATTRIBUTE && prop.name === 'is') ||
+        (prop.type === NodeTypes.DIRECTIVE &&
+          prop.name === 'bind' &&
+          isStaticArgOf(prop.arg, 'is')))
     ) {
       continue
     }