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

wip(compiler): adjust renderSlot() signature

Evan You 6 лет назад
Родитель
Сommit
05db2a9c6c

+ 1 - 2
packages/compiler-core/__tests__/transform.spec.ts

@@ -277,8 +277,7 @@ describe('compiler: transform', () => {
       expect(ast.codegenNode).toMatchObject({
         codegenNode: {
           type: NodeTypes.JS_CALL_EXPRESSION,
-          callee: `_${RENDER_SLOT}`,
-          arguments: ['$slots.default']
+          callee: `_${RENDER_SLOT}`
         }
       })
     })

+ 2 - 2
packages/compiler-core/__tests__/transforms/__snapshots__/vFor.spec.ts.snap

@@ -112,7 +112,7 @@ return function render() {
     const { renderList: _renderList, openBlock: _openBlock, createBlock: _createBlock, Fragment: _Fragment, renderSlot: _renderSlot } = _Vue
     
     return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (item) => {
-      return _renderSlot($slots.default)
+      return _renderSlot($slots, \\"default\\")
     }), 128 /* UNKEYED_FRAGMENT */))
   }
 }"
@@ -126,7 +126,7 @@ return function render() {
     const { renderList: _renderList, openBlock: _openBlock, createBlock: _createBlock, Fragment: _Fragment, renderSlot: _renderSlot } = _Vue
     
     return (_openBlock(), _createBlock(_Fragment, null, _renderList(items, (item) => {
-      return _renderSlot($slots.default)
+      return _renderSlot($slots, \\"default\\")
     }), 128 /* UNKEYED_FRAGMENT */))
   }
 }"

+ 15 - 1
packages/compiler-core/__tests__/transforms/__snapshots__/vIf.spec.ts.snap

@@ -40,7 +40,7 @@ return function render() {
     const { openBlock: _openBlock, renderSlot: _renderSlot, createBlock: _createBlock, Empty: _Empty } = _Vue
     
     return (_openBlock(), ok
-      ? _renderSlot($slots.default, { key: 0 })
+      ? _renderSlot($slots, \\"default\\", { key: 0 })
       : _createBlock(_Empty))
   }
 }"
@@ -91,3 +91,17 @@ return function render() {
   }
 }"
 `;
+
+exports[`compiler: v-if codegen v-if on <slot/> 1`] = `
+"const _Vue = Vue
+
+return function render() {
+  with (this) {
+    const { openBlock: _openBlock, renderSlot: _renderSlot, createBlock: _createBlock, Empty: _Empty } = _Vue
+    
+    return (_openBlock(), ok
+      ? _renderSlot($slots, \\"default\\", { key: 0 })
+      : _createBlock(_Empty))
+  }
+}"
+`;

+ 22 - 34
packages/compiler-core/__tests__/transforms/transformSlotOutlet.spec.ts

@@ -36,7 +36,7 @@ describe('compiler: transform <slot> outlets', () => {
     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
       type: NodeTypes.JS_CALL_EXPRESSION,
       callee: `_${RENDER_SLOT}`,
-      arguments: [`$slots.default`]
+      arguments: [`$slots`, `"default"`]
     })
   })
 
@@ -45,16 +45,7 @@ describe('compiler: transform <slot> outlets', () => {
     expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
       type: NodeTypes.JS_CALL_EXPRESSION,
       callee: `_${RENDER_SLOT}`,
-      arguments: [`$slots.foo`]
-    })
-  })
-
-  test('statically named slot outlet w/ name that needs quotes', () => {
-    const ast = parseWithSlots(`<slot name="foo-bar" />`)
-    expect((ast.children[0] as ElementNode).codegenNode).toMatchObject({
-      type: NodeTypes.JS_CALL_EXPRESSION,
-      callee: `_${RENDER_SLOT}`,
-      arguments: [`$slots["foo-bar"]`]
+      arguments: [`$slots`, `"foo"`]
     })
   })
 
@@ -64,17 +55,11 @@ describe('compiler: transform <slot> outlets', () => {
       type: NodeTypes.JS_CALL_EXPRESSION,
       callee: `_${RENDER_SLOT}`,
       arguments: [
+        `$slots`,
         {
-          type: NodeTypes.COMPOUND_EXPRESSION,
-          children: [
-            `$slots[`,
-            {
-              type: NodeTypes.SIMPLE_EXPRESSION,
-              content: `foo`,
-              isStatic: false
-            },
-            `]`
-          ]
+          type: NodeTypes.SIMPLE_EXPRESSION,
+          content: `foo`,
+          isStatic: false
         }
       ]
     })
@@ -88,10 +73,10 @@ describe('compiler: transform <slot> outlets', () => {
       type: NodeTypes.JS_CALL_EXPRESSION,
       callee: RENDER_SLOT,
       arguments: [
+        `_ctx.$slots`,
         {
           type: NodeTypes.COMPOUND_EXPRESSION,
           children: [
-            `_ctx.$slots[`,
             {
               type: NodeTypes.SIMPLE_EXPRESSION,
               content: `_ctx.foo`,
@@ -102,8 +87,7 @@ describe('compiler: transform <slot> outlets', () => {
               type: NodeTypes.SIMPLE_EXPRESSION,
               content: `_ctx.bar`,
               isStatic: false
-            },
-            `]`
+            }
           ]
         }
       ]
@@ -116,7 +100,8 @@ describe('compiler: transform <slot> outlets', () => {
       type: NodeTypes.JS_CALL_EXPRESSION,
       callee: `_${RENDER_SLOT}`,
       arguments: [
-        `$slots.default`,
+        `$slots`,
+        `"default"`,
         {
           type: NodeTypes.JS_OBJECT_EXPRESSION,
           properties: [
@@ -152,7 +137,8 @@ describe('compiler: transform <slot> outlets', () => {
       type: NodeTypes.JS_CALL_EXPRESSION,
       callee: `_${RENDER_SLOT}`,
       arguments: [
-        `$slots.foo`,
+        `$slots`,
+        `"foo"`,
         {
           type: NodeTypes.JS_OBJECT_EXPRESSION,
           // props should not include name
@@ -189,10 +175,8 @@ describe('compiler: transform <slot> outlets', () => {
       type: NodeTypes.JS_CALL_EXPRESSION,
       callee: `_${RENDER_SLOT}`,
       arguments: [
-        {
-          type: NodeTypes.COMPOUND_EXPRESSION,
-          children: [`$slots[`, { content: `foo` }, `]`]
-        },
+        `$slots`,
+        { content: `foo`, isStatic: false },
         {
           type: NodeTypes.JS_OBJECT_EXPRESSION,
           // props should not include name
@@ -229,7 +213,8 @@ describe('compiler: transform <slot> outlets', () => {
       type: NodeTypes.JS_CALL_EXPRESSION,
       callee: `_${RENDER_SLOT}`,
       arguments: [
-        `$slots.default`,
+        `$slots`,
+        `"default"`,
         `{}`,
         [
           {
@@ -247,7 +232,8 @@ describe('compiler: transform <slot> outlets', () => {
       type: NodeTypes.JS_CALL_EXPRESSION,
       callee: `_${RENDER_SLOT}`,
       arguments: [
-        `$slots.foo`,
+        `$slots`,
+        `"foo"`,
         `{}`,
         [
           {
@@ -265,7 +251,8 @@ describe('compiler: transform <slot> outlets', () => {
       type: NodeTypes.JS_CALL_EXPRESSION,
       callee: `_${RENDER_SLOT}`,
       arguments: [
-        `$slots.default`,
+        `$slots`,
+        `"default"`,
         {
           type: NodeTypes.JS_OBJECT_EXPRESSION,
           properties: [
@@ -297,7 +284,8 @@ describe('compiler: transform <slot> outlets', () => {
       type: NodeTypes.JS_CALL_EXPRESSION,
       callee: `_${RENDER_SLOT}`,
       arguments: [
-        `$slots.foo`,
+        `$slots`,
+        `"foo"`,
         {
           type: NodeTypes.JS_OBJECT_EXPRESSION,
           properties: [

+ 17 - 1
packages/compiler-core/__tests__/transforms/vIf.spec.ts

@@ -360,7 +360,23 @@ describe('compiler: v-if', () => {
       expect(branch1).toMatchObject({
         type: NodeTypes.JS_CALL_EXPRESSION,
         callee: `_${RENDER_SLOT}`,
-        arguments: ['$slots.default', createObjectMatcher({ key: `[0]` })]
+        arguments: ['$slots', '"default"', createObjectMatcher({ key: `[0]` })]
+      })
+      expect(generate(root).code).toMatchSnapshot()
+    })
+
+    test('v-if on <slot/>', () => {
+      const {
+        root,
+        node: { codegenNode }
+      } = parseWithIfTransform(`<slot v-if="ok"></slot>`)
+      // assertSharedCodegen(codegenNode)
+      const branch1 = (codegenNode.expressions[1] as ConditionalExpression)
+        .consequent as CallExpression
+      expect(branch1).toMatchObject({
+        type: NodeTypes.JS_CALL_EXPRESSION,
+        callee: `_${RENDER_SLOT}`,
+        arguments: ['$slots', '"default"', createObjectMatcher({ key: `[0]` })]
       })
       expect(generate(root).code).toMatchSnapshot()
     })

+ 7 - 18
packages/compiler-core/src/transforms/transfromSlotOutlet.ts

@@ -1,12 +1,11 @@
 import { NodeTransform } from '../transform'
 import {
   NodeTypes,
-  CompoundExpressionNode,
-  createCompoundExpression,
   CallExpression,
-  createCallExpression
+  createCallExpression,
+  ExpressionNode
 } from '../ast'
-import { isSimpleIdentifier, isSlotOutlet } from '../utils'
+import { isSlotOutlet } from '../utils'
 import { buildProps } from './transformElement'
 import { createCompilerError, ErrorCodes } from '../errors'
 import { RENDER_SLOT } from '../runtimeConstants'
@@ -15,7 +14,7 @@ export const transformSlotOutlet: NodeTransform = (node, context) => {
   if (isSlotOutlet(node)) {
     const { props, children, loc } = node
     const $slots = context.prefixIdentifiers ? `_ctx.$slots` : `$slots`
-    let slot: string | CompoundExpressionNode = $slots + `.default`
+    let slotName: string | ExpressionNode = `"default"`
 
     // check for <slot name="xxx" OR :name="xxx" />
     let nameIndex: number = -1
@@ -24,11 +23,7 @@ export const transformSlotOutlet: NodeTransform = (node, context) => {
       if (prop.type === NodeTypes.ATTRIBUTE) {
         if (prop.name === `name` && prop.value) {
           // static name="xxx"
-          const name = prop.value.content
-          const accessor = isSimpleIdentifier(name)
-            ? `.${name}`
-            : `[${JSON.stringify(name)}]`
-          slot = `${$slots}${accessor}`
+          slotName = JSON.stringify(prop.value.content)
           nameIndex = i
           break
         }
@@ -42,20 +37,14 @@ export const transformSlotOutlet: NodeTransform = (node, context) => {
           arg.content === `name`
         ) {
           // dynamic :name="xxx"
-          slot = createCompoundExpression([
-            $slots + `[`,
-            ...(exp.type === NodeTypes.SIMPLE_EXPRESSION
-              ? [exp]
-              : exp.children),
-            `]`
-          ])
+          slotName = exp
           nameIndex = i
           break
         }
       }
     }
 
-    const slotArgs: CallExpression['arguments'] = [slot]
+    const slotArgs: CallExpression['arguments'] = [$slots, slotName]
     const propsWithoutName =
       nameIndex > -1
         ? props.slice(0, nameIndex).concat(props.slice(nameIndex + 1))

+ 3 - 2
packages/compiler-core/src/transforms/vFor.ts

@@ -118,11 +118,12 @@ export const transformFor = createStructuralDirectiveTransform(
             if (isTemplate && keyProperty) {
               // <template v-for="..." :key="..."><slot/></template>
               // we need to inject the key to the renderSlot() call.
-              const existingProps = childBlock.arguments[1] as
+              // the props for renderSlot is passed as the 3rd argument.
+              const existingProps = childBlock.arguments[2] as
                 | PropsExpression
                 | undefined
                 | 'null'
-              childBlock.arguments[1] = injectProp(
+              childBlock.arguments[2] = injectProp(
                 existingProps,
                 keyProperty,
                 context

+ 13 - 6
packages/compiler-core/src/transforms/vIf.ts

@@ -27,7 +27,8 @@ import {
   EMPTY,
   FRAGMENT,
   APPLY_DIRECTIVES,
-  CREATE_VNODE
+  CREATE_VNODE,
+  RENDER_SLOT
 } from '../runtimeConstants'
 import { injectProp } from '../utils'
 import { PropsExpression } from './transformElement'
@@ -185,18 +186,24 @@ function createChildrenCodegenNode(
       vnodeCall = vnodeCall.arguments[0] as CallExpression
     }
     // Change createVNode to createBlock.
-    // It's possible to have renderSlot() here as well - which already produces
-    // a block, so no need to change the callee. renderSlot() also accepts props
-    // as the 2nd argument, so the key injection logic below works for it too.
     if (vnodeCall.callee.includes(CREATE_VNODE)) {
       vnodeCall.callee = helper(CREATE_BLOCK)
     }
+    // It's possible to have renderSlot() here as well - which already produces
+    // a block, so no need to change the callee. However it accepts props at
+    // a different arg index so make sure to check for so that the key injection
+    // logic below works for it too.
+    const propsIndex = vnodeCall.callee.includes(RENDER_SLOT) ? 2 : 1
     // inject branch key
-    const existingProps = vnodeCall.arguments[1] as
+    const existingProps = vnodeCall.arguments[propsIndex] as
       | PropsExpression
       | undefined
       | 'null'
-    vnodeCall.arguments[1] = injectProp(existingProps, keyProperty, context)
+    vnodeCall.arguments[propsIndex] = injectProp(
+      existingProps,
+      keyProperty,
+      context
+    )
     return childCodegen
   }
 }

+ 3 - 1
packages/runtime-core/src/helpers/renderSlot.ts

@@ -8,12 +8,14 @@ import {
 } from '../vnode'
 
 export function renderSlot(
-  slot: Slot | undefined,
+  slots: Record<string, Slot>,
+  key: string,
   props: any = {},
   // this is not a user-facing function, so the fallback is always generated by
   // the compiler and gurunteed to be an array
   fallback?: VNodeChildren
 ): VNode {
+  const slot = slots[key]
   return (
     openBlock(),
     createBlock(