wip(srr): slot outlet

This commit is contained in:
Evan You
2020-02-05 21:04:40 -05:00
parent 7a63103a11
commit 9b3b6962df
14 changed files with 263 additions and 120 deletions

View File

@@ -147,11 +147,13 @@ export interface ComponentNode extends BaseElementNode {
| ComponentCodegenNode
| CacheExpression // when cached by v-once
| undefined
ssrCodegenNode?: CallExpression
}
export interface SlotOutletNode extends BaseElementNode {
tagType: ElementTypes.SLOT
codegenNode: SlotOutletCodegenNode | undefined | CacheExpression // when cached by v-once
ssrCodegenNode?: CallExpression
}
export interface TemplateNode extends BaseElementNode {

View File

@@ -35,14 +35,15 @@ export { transformBind } from './transforms/vBind'
// exported for compiler-ssr
export { MERGE_PROPS } from './runtimeHelpers'
export { processIfBranches } from './transforms/vIf'
export { processForNode, createForLoopParams } from './transforms/vFor'
export { processIf } from './transforms/vIf'
export { processFor, createForLoopParams } from './transforms/vFor'
export {
transformExpression,
processExpression
} from './transforms/transformExpression'
export { trackVForSlotScopes, trackSlotScopes } from './transforms/vSlot'
export { buildProps } from './transforms/transformElement'
export { processSlotOutlet } from './transforms/transformSlotOutlet'
// utility, but need to rewrite typing to avoid dts relying on @vue/shared
import { generateCodeFrame as _genCodeFrame } from '@vue/shared'

View File

@@ -1,78 +1,32 @@
import { NodeTransform } from '../transform'
import { NodeTransform, TransformContext } from '../transform'
import {
NodeTypes,
CallExpression,
createCallExpression,
ExpressionNode
ExpressionNode,
SlotOutletNode
} from '../ast'
import { isSlotOutlet } from '../utils'
import { buildProps } from './transformElement'
import { isSlotOutlet, findProp } from '../utils'
import { buildProps, PropsExpression } from './transformElement'
import { createCompilerError, ErrorCodes } from '../errors'
import { RENDER_SLOT } from '../runtimeHelpers'
export const transformSlotOutlet: NodeTransform = (node, context) => {
if (isSlotOutlet(node)) {
const { props, children, loc } = node
const $slots = context.prefixIdentifiers ? `_ctx.$slots` : `$slots`
let slotName: string | ExpressionNode = `"default"`
const { children, loc } = node
const { slotName, slotProps } = processSlotOutlet(node, context)
// check for <slot name="xxx" OR :name="xxx" />
let nameIndex: number = -1
for (let i = 0; i < props.length; i++) {
const prop = props[i]
if (prop.type === NodeTypes.ATTRIBUTE) {
if (prop.name === `name` && prop.value) {
// static name="xxx"
slotName = JSON.stringify(prop.value.content)
nameIndex = i
break
}
} else if (prop.name === `bind`) {
const { arg, exp } = prop
if (
arg &&
exp &&
arg.type === NodeTypes.SIMPLE_EXPRESSION &&
arg.isStatic &&
arg.content === `name`
) {
// dynamic :name="xxx"
slotName = exp
nameIndex = i
break
}
}
}
const slotArgs: CallExpression['arguments'] = [
context.prefixIdentifiers ? `_ctx.$slots` : `$slots`,
slotName
]
const slotArgs: CallExpression['arguments'] = [$slots, slotName]
const propsWithoutName =
nameIndex > -1
? props.slice(0, nameIndex).concat(props.slice(nameIndex + 1))
: props
let hasProps = propsWithoutName.length > 0
if (hasProps) {
const { props: propsExpression, directives } = buildProps(
node,
context,
propsWithoutName
)
if (directives.length) {
context.onError(
createCompilerError(
ErrorCodes.X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET,
directives[0].loc
)
)
}
if (propsExpression) {
slotArgs.push(propsExpression)
} else {
hasProps = false
}
if (slotProps) {
slotArgs.push(slotProps)
}
if (children.length) {
if (!hasProps) {
if (!slotProps) {
slotArgs.push(`{}`)
}
slotArgs.push(children)
@@ -85,3 +39,49 @@ export const transformSlotOutlet: NodeTransform = (node, context) => {
)
}
}
interface SlotOutletProcessResult {
slotName: string | ExpressionNode
slotProps: PropsExpression | undefined
}
export function processSlotOutlet(
node: SlotOutletNode,
context: TransformContext
): SlotOutletProcessResult {
let slotName: string | ExpressionNode = `"default"`
let slotProps: PropsExpression | undefined = undefined
// check for <slot name="xxx" OR :name="xxx" />
const name = findProp(node, 'name')
if (name) {
if (name.type === NodeTypes.ATTRIBUTE && name.value) {
// static name
slotName = JSON.stringify(name.value.content)
} else if (name.type === NodeTypes.DIRECTIVE && name.exp) {
// dynamic name
slotName = name.exp
}
}
const propsWithoutName = name
? node.props.filter(p => p !== name)
: node.props
if (propsWithoutName.length > 0) {
const { props, directives } = buildProps(node, context, propsWithoutName)
slotProps = props
if (directives.length) {
context.onError(
createCompilerError(
ErrorCodes.X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET,
directives[0].loc
)
)
}
}
return {
slotName,
slotProps
}
}

View File

@@ -46,7 +46,7 @@ export const transformFor = createStructuralDirectiveTransform(
'for',
(node, dir, context) => {
const { helper } = context
return processForNode(node, dir, context, forNode => {
return processFor(node, dir, context, forNode => {
// create the loop render function expression now, and add the
// iterator on exit after all children have been traversed
const renderExp = createCallExpression(helper(RENDER_LIST), [
@@ -138,7 +138,7 @@ export const transformFor = createStructuralDirectiveTransform(
)
// target-agnostic transform used for both Client and SSR
export function processForNode(
export function processFor(
node: ElementNode,
dir: DirectiveNode,
context: TransformContext,

View File

@@ -41,7 +41,7 @@ import { injectProp } from '../utils'
export const transformIf = createStructuralDirectiveTransform(
/^(if|else|else-if)$/,
(node, dir, context) => {
return processIfBranches(node, dir, context, (ifNode, branch, isRoot) => {
return processIf(node, dir, context, (ifNode, branch, isRoot) => {
// Exit callback. Complete the codegenNode when all children have been
// transformed.
return () => {
@@ -72,7 +72,7 @@ export const transformIf = createStructuralDirectiveTransform(
)
// target-agnostic transform used for both Client and SSR
export function processIfBranches(
export function processIf(
node: ElementNode,
dir: DirectiveNode,
context: TransformContext,