From 05db2a9c6c706c3a7eda1602ea5069dd54ac63c8 Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 3 Oct 2019 14:29:12 -0400 Subject: [PATCH] wip(compiler): adjust renderSlot() signature --- .../compiler-core/__tests__/transform.spec.ts | 3 +- .../__snapshots__/vFor.spec.ts.snap | 4 +- .../transforms/__snapshots__/vIf.spec.ts.snap | 16 +++++- .../transforms/transformSlotOutlet.spec.ts | 56 ++++++++----------- .../__tests__/transforms/vIf.spec.ts | 18 +++++- .../src/transforms/transfromSlotOutlet.ts | 25 +++------ packages/compiler-core/src/transforms/vFor.ts | 5 +- packages/compiler-core/src/transforms/vIf.ts | 19 +++++-- .../runtime-core/src/helpers/renderSlot.ts | 4 +- 9 files changed, 83 insertions(+), 67 deletions(-) diff --git a/packages/compiler-core/__tests__/transform.spec.ts b/packages/compiler-core/__tests__/transform.spec.ts index 44b88c93..e2d52fe4 100644 --- a/packages/compiler-core/__tests__/transform.spec.ts +++ b/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}` } }) }) diff --git a/packages/compiler-core/__tests__/transforms/__snapshots__/vFor.spec.ts.snap b/packages/compiler-core/__tests__/transforms/__snapshots__/vFor.spec.ts.snap index d40121be..02bbbcbb 100644 --- a/packages/compiler-core/__tests__/transforms/__snapshots__/vFor.spec.ts.snap +++ b/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 */)) } }" diff --git a/packages/compiler-core/__tests__/transforms/__snapshots__/vIf.spec.ts.snap b/packages/compiler-core/__tests__/transforms/__snapshots__/vIf.spec.ts.snap index 8fd74760..f2959952 100644 --- a/packages/compiler-core/__tests__/transforms/__snapshots__/vIf.spec.ts.snap +++ b/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 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)) + } +}" +`; diff --git a/packages/compiler-core/__tests__/transforms/transformSlotOutlet.spec.ts b/packages/compiler-core/__tests__/transforms/transformSlotOutlet.spec.ts index 5b16c27b..bad59c46 100644 --- a/packages/compiler-core/__tests__/transforms/transformSlotOutlet.spec.ts +++ b/packages/compiler-core/__tests__/transforms/transformSlotOutlet.spec.ts @@ -36,7 +36,7 @@ describe('compiler: transform 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 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(``) - 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 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 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 outlets', () => { type: NodeTypes.SIMPLE_EXPRESSION, content: `_ctx.bar`, isStatic: false - }, - `]` + } ] } ] @@ -116,7 +100,8 @@ describe('compiler: transform 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 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 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 outlets', () => { type: NodeTypes.JS_CALL_EXPRESSION, callee: `_${RENDER_SLOT}`, arguments: [ - `$slots.default`, + `$slots`, + `"default"`, `{}`, [ { @@ -247,7 +232,8 @@ describe('compiler: transform outlets', () => { type: NodeTypes.JS_CALL_EXPRESSION, callee: `_${RENDER_SLOT}`, arguments: [ - `$slots.foo`, + `$slots`, + `"foo"`, `{}`, [ { @@ -265,7 +251,8 @@ describe('compiler: transform 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 outlets', () => { type: NodeTypes.JS_CALL_EXPRESSION, callee: `_${RENDER_SLOT}`, arguments: [ - `$slots.foo`, + `$slots`, + `"foo"`, { type: NodeTypes.JS_OBJECT_EXPRESSION, properties: [ diff --git a/packages/compiler-core/__tests__/transforms/vIf.spec.ts b/packages/compiler-core/__tests__/transforms/vIf.spec.ts index 930313c3..c9d8c551 100644 --- a/packages/compiler-core/__tests__/transforms/vIf.spec.ts +++ b/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 ', () => { + const { + root, + node: { codegenNode } + } = parseWithIfTransform(``) + // 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() }) diff --git a/packages/compiler-core/src/transforms/transfromSlotOutlet.ts b/packages/compiler-core/src/transforms/transfromSlotOutlet.ts index 3ed95a4e..f897aa8c 100644 --- a/packages/compiler-core/src/transforms/transfromSlotOutlet.ts +++ b/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 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)) diff --git a/packages/compiler-core/src/transforms/vFor.ts b/packages/compiler-core/src/transforms/vFor.ts index 6ae47d3e..c54e9578 100644 --- a/packages/compiler-core/src/transforms/vFor.ts +++ b/packages/compiler-core/src/transforms/vFor.ts @@ -118,11 +118,12 @@ export const transformFor = createStructuralDirectiveTransform( if (isTemplate && keyProperty) { // // 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 diff --git a/packages/compiler-core/src/transforms/vIf.ts b/packages/compiler-core/src/transforms/vIf.ts index 9dd27e1f..47eda281 100644 --- a/packages/compiler-core/src/transforms/vIf.ts +++ b/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 } } diff --git a/packages/runtime-core/src/helpers/renderSlot.ts b/packages/runtime-core/src/helpers/renderSlot.ts index 5e14df25..c5a84aad 100644 --- a/packages/runtime-core/src/helpers/renderSlot.ts +++ b/packages/runtime-core/src/helpers/renderSlot.ts @@ -8,12 +8,14 @@ import { } from '../vnode' export function renderSlot( - slot: Slot | undefined, + slots: Record, + 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(