Просмотр исходного кода

fix(compiler-vapor): normalize default dynamic slot names in transform (#14619)

Jack 1 месяц назад
Родитель
Сommit
c615e0586c

+ 43 - 0
packages/compiler-vapor/__tests__/transforms/__snapshots__/vSlot.spec.ts.snap

@@ -1,5 +1,48 @@
 // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
 
+exports[`compiler: transform slot > default slot with v-for directive 1`] = `
+"import { resolveComponent as _resolveComponent, toDisplayString as _toDisplayString, setText as _setText, renderEffect as _renderEffect, createForSlots as _createForSlots, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
+const t0 = _template(" ")
+
+export function render(_ctx) {
+  const _component_Comp = _resolveComponent("Comp")
+  const n2 = _createComponentWithFallback(_component_Comp, null, {
+    $: [
+      () => (_createForSlots(_ctx.list, (item) => ({
+        name: "default",
+        fn: () => {
+          const n0 = t0()
+          _renderEffect(() => _setText(n0, _toDisplayString(item)))
+          return n0
+        }
+      })))
+    ]
+  }, true)
+  return n2
+}"
+`;
+
+exports[`compiler: transform slot > default slot with v-if directive 1`] = `
+"import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback } from 'vue';
+
+export function render(_ctx) {
+  const _component_Comp = _resolveComponent("Comp")
+  const n1 = _createComponentWithFallback(_component_Comp, null, {
+    $: [
+      () => (_ctx.show
+        ? {
+          name: "default",
+          fn: () => {
+            return null
+          }
+        }
+        : void 0)
+    ]
+  }, true)
+  return n1
+}"
+`;
+
 exports[`compiler: transform slot > dynamic slots name 1`] = `
 "import { resolveComponent as _resolveComponent, createComponentWithFallback as _createComponentWithFallback, template as _template } from 'vue';
 const t0 = _template("foo")

+ 59 - 0
packages/compiler-vapor/__tests__/transforms/vSlot.spec.ts

@@ -63,6 +63,65 @@ describe('compiler: transform slot', () => {
     })
   })
 
+  test('default slot with v-if directive', () => {
+    const { ir, code } = compileWithSlots(
+      `<Comp><template # v-if="show"></template></Comp>`,
+    )
+    expect(code).toMatchSnapshot()
+
+    expect(ir.block.dynamic.children[0].operation).toMatchObject({
+      type: IRNodeTypes.CREATE_COMPONENT_NODE,
+      id: 1,
+      tag: 'Comp',
+      props: [[]],
+      slots: [
+        {
+          slotType: IRSlotType.CONDITIONAL,
+        },
+      ],
+    })
+    expect(ir.block.returns).toEqual([1])
+    expect(ir.block.dynamic).toMatchObject({
+      children: [{ id: 1 }],
+    })
+    expect(code).contains(`name: "default",`)
+  })
+
+  test('default slot with v-for directive', () => {
+    const { ir, code } = compileWithSlots(
+      `<Comp><template # v-for="item in list">{{ item }}</template></Comp>`,
+    )
+    expect(code).toMatchSnapshot()
+
+    expect(ir.block.dynamic.children[0].operation).toMatchObject({
+      type: IRNodeTypes.CREATE_COMPONENT_NODE,
+      id: 2,
+      tag: 'Comp',
+      props: [[]],
+      slots: [
+        {
+          slotType: IRSlotType.LOOP,
+          name: {
+            type: NodeTypes.SIMPLE_EXPRESSION,
+            content: 'default',
+            isStatic: true,
+          },
+          fn: { type: IRNodeTypes.BLOCK },
+          loop: {
+            source: { content: 'list' },
+            value: { content: 'item' },
+            index: undefined,
+          },
+        },
+      ],
+    })
+    expect(ir.block.returns).toEqual([2])
+    expect(ir.block.dynamic).toMatchObject({
+      children: [{ id: 2 }],
+    })
+    expect(code).contains(`name: "default",`)
+  })
+
   test('on-component default slot', () => {
     const { ir, code } = compileWithSlots(
       `<Comp v-slot="{ foo }">{{ foo + bar }}</Comp>`,

+ 7 - 2
packages/compiler-vapor/src/transforms/vSlot.ts

@@ -6,6 +6,7 @@ import {
   type SimpleExpressionNode,
   type TemplateChildNode,
   createCompilerError,
+  createSimpleExpression,
   isTemplateNode,
 } from '@vue/compiler-dom'
 import type { NodeTransform, TransformContext } from '../transform'
@@ -134,7 +135,9 @@ function transformTemplateSlot(
 ) {
   context.dynamic.flags |= DynamicFlag.NON_TEMPLATE
 
-  const arg = dir.arg && resolveExpression(dir.arg)
+  const resolvedArg = dir.arg && resolveExpression(dir.arg)
+  let arg = resolvedArg
+  if (!arg) arg = createSimpleExpression('default', true)
   const vFor = findDir(node, 'for')
   const vIf = findDir(node, 'if')
   const vElse = findDir(node, /^else(-if)?$/, true /* allowEmpty */)
@@ -142,7 +145,9 @@ function transformTemplateSlot(
   const [block, onExit] = createSlotBlock(node, dir, context)
 
   if (!vFor && !vIf && !vElse) {
-    const slotName = arg ? arg.isStatic && arg.content : 'default'
+    const slotName = resolvedArg
+      ? resolvedArg.isStatic && resolvedArg.content
+      : 'default'
     if (slotName && hasStaticSlot(slots, slotName)) {
       context.options.onError(
         createCompilerError(ErrorCodes.X_V_SLOT_DUPLICATE_SLOT_NAMES, dir.loc),