feat(compiler-core): support Suspense in templates

This commit is contained in:
Evan You 2019-10-16 17:40:00 -04:00
parent e97951dd2e
commit 4b2b29efa1
3 changed files with 123 additions and 117 deletions

View File

@ -50,7 +50,8 @@ export const enum ElementTypes {
COMPONENT,
SLOT,
TEMPLATE,
PORTAL
PORTAL,
SUSPENSE
}
export interface Node {
@ -101,6 +102,7 @@ export type ElementNode =
| SlotOutletNode
| TemplateNode
| PortalNode
| SuspenseNode
export interface BaseElementNode extends Node {
type: NodeTypes.ELEMENT
@ -141,6 +143,11 @@ export interface PortalNode extends BaseElementNode {
codegenNode: ElementCodegenNode | undefined
}
export interface SuspenseNode extends BaseElementNode {
tagType: ElementTypes.SUSPENSE
codegenNode: ElementCodegenNode | undefined
}
export interface TextNode extends Node {
type: NodeTypes.TEXT
content: string

View File

@ -445,6 +445,8 @@ function parseTag(
if (tag === 'slot') tagType = ElementTypes.SLOT
else if (tag === 'template') tagType = ElementTypes.TEMPLATE
else if (tag === 'portal' || tag === 'Portal') tagType = ElementTypes.PORTAL
else if (tag === 'suspense' || tag === 'Suspense')
tagType = ElementTypes.SUSPENSE
}
return {

View File

@ -24,7 +24,8 @@ import {
RESOLVE_COMPONENT,
MERGE_PROPS,
TO_HANDLERS,
PORTAL
PORTAL,
SUSPENSE
} from '../runtimeHelpers'
import { getInnerRange, isVSlot, toValidAssetId } from '../utils'
import { buildSlots } from './vSlot'
@ -36,20 +37,20 @@ const directiveImportMap = new WeakMap<DirectiveNode, symbol>()
// generate a JavaScript AST for this element's codegen
export const transformElement: NodeTransform = (node, context) => {
if (node.type === NodeTypes.ELEMENT) {
if (
node.tagType === ElementTypes.ELEMENT ||
node.tagType === ElementTypes.COMPONENT ||
node.tagType === ElementTypes.PORTAL ||
// <template> with v-if or v-for are ignored during traversal.
// <template> without v-slot should be treated as a normal element.
(node.tagType === ElementTypes.TEMPLATE && !node.props.some(isVSlot))
node.type !== NodeTypes.ELEMENT ||
// handled by transformSlotOutlet
node.tagType === ElementTypes.SLOT ||
// <template v-if/v-for> should have already been replaced
// <templte v-slot> is handled by buildSlots
(node.tagType === ElementTypes.TEMPLATE && node.props.some(isVSlot))
) {
return
}
// perform the work on exit, after all child expressions have been
// processed and merged.
return () => {
const isComponent = node.tagType === ElementTypes.COMPONENT
const isPortal = node.tagType === ElementTypes.PORTAL
let hasProps = node.props.length > 0
let patchFlag: number = 0
let runtimeDirectives: DirectiveNode[] | undefined
@ -63,8 +64,10 @@ export const transformElement: NodeTransform = (node, context) => {
const args: CallExpression['arguments'] = [
isComponent
? toValidAssetId(node.tag, `component`)
: isPortal
: node.tagType === ElementTypes.PORTAL
? context.helper(PORTAL)
: node.tagType === ElementTypes.SUSPENSE
? context.helper(SUSPENSE)
: `"${node.tag}"`
]
// props
@ -138,11 +141,7 @@ export const transformElement: NodeTransform = (node, context) => {
}
const { loc } = node
const vnode = createCallExpression(
context.helper(CREATE_VNODE),
args,
loc
)
const vnode = createCallExpression(context.helper(CREATE_VNODE), args, loc)
if (runtimeDirectives && runtimeDirectives.length) {
node.codegenNode = createCallExpression(
@ -161,8 +160,6 @@ export const transformElement: NodeTransform = (node, context) => {
}
}
}
}
}
export type PropsExpression = ObjectExpression | CallExpression | ExpressionNode