refactor(compiler): refine codegen node types

This commit is contained in:
Evan You
2019-10-05 22:47:20 -04:00
parent bfecf2cdce
commit 82bd9eb1db
10 changed files with 636 additions and 288 deletions

View File

@@ -2,13 +2,13 @@ import {
RootNode,
NodeTypes,
TemplateChildNode,
CallExpression,
ElementNode,
ElementTypes
ElementTypes,
ElementCodegenNode,
ElementCodegenNodeWithDirective
} from '../ast'
import { TransformContext } from '../transform'
import { APPLY_DIRECTIVES } from '../runtimeHelpers'
import { PropsExpression } from './transformElement'
import { PatchFlags } from '@vue/shared'
export function hoistStatic(root: RootNode, context: TransformContext) {
@@ -29,7 +29,7 @@ function walk(
) {
if (isStaticNode(child, resultCache)) {
// whole tree is static
child.codegenNode = context.hoist(child.codegenNode!)
;(child as any).codegenNode = context.hoist(child.codegenNode!)
continue
} else {
// node may contain dynamic children, but its props may be eligible for
@@ -40,18 +40,13 @@ function walk(
flag === PatchFlags.NEED_PATCH ||
flag === PatchFlags.TEXT
) {
let codegenNode = child.codegenNode as CallExpression
let codegenNode = child.codegenNode!
if (codegenNode.callee === APPLY_DIRECTIVES) {
codegenNode = codegenNode.arguments[0] as CallExpression
codegenNode = codegenNode.arguments[0]
}
const props = codegenNode.arguments[1] as
| PropsExpression
| `null`
| undefined
const props = codegenNode.arguments[1]
if (props && props !== `null`) {
;(child.codegenNode as CallExpression).arguments[1] = context.hoist(
props
)
codegenNode.arguments[1] = context.hoist(props)
}
}
}
@@ -67,9 +62,11 @@ function walk(
}
function getPatchFlag(node: ElementNode): number | undefined {
let codegenNode = node.codegenNode as CallExpression
let codegenNode = node.codegenNode as
| ElementCodegenNode
| ElementCodegenNodeWithDirective
if (codegenNode.callee === APPLY_DIRECTIVES) {
codegenNode = codegenNode.arguments[0] as CallExpression
codegenNode = codegenNode.arguments[0]
}
const flag = codegenNode.arguments[3]
return flag ? parseInt(flag as string, 10) : undefined

View File

@@ -14,7 +14,8 @@ import {
ElementTypes,
createObjectExpression,
createObjectProperty,
CallExpression
ForCodegenNode,
PlainElementNode
} from '../ast'
import { createCompilerError, ErrorCodes } from '../errors'
import {
@@ -66,7 +67,7 @@ export const transformFor = createStructuralDirectiveTransform(
fragmentFlag +
(__DEV__ ? ` /* ${PatchFlagNames[fragmentFlag]} */` : ``)
])
])
]) as ForCodegenNode
context.replaceNode({
type: NodeTypes.FOR,
@@ -118,7 +119,7 @@ export const transformFor = createStructuralDirectiveTransform(
: null
if (slotOutlet) {
// <slot v-for="..."> or <template v-for="..."><slot/></template>
childBlock = slotOutlet.codegenNode as CallExpression
childBlock = slotOutlet.codegenNode!
if (isTemplate && keyProperty) {
// <template v-for="..." :key="..."><slot/></template>
// we need to inject the key to the renderSlot() call.
@@ -148,7 +149,7 @@ export const transformFor = createStructuralDirectiveTransform(
// Normal element v-for. Directly use the child's codegenNode
// arguments, but replace createVNode() with createBlock()
childBlock = createBlockExpression(
(node.codegenNode as CallExpression).arguments,
(node as PlainElementNode).codegenNode!.arguments,
context
)
}

View File

@@ -17,7 +17,15 @@ import {
CallExpression,
createSimpleExpression,
createObjectProperty,
createObjectExpression
createObjectExpression,
IfCodegenNode,
IfConditionalExpression,
BlockCodegenNode,
SlotOutletCodegenNode,
ElementCodegenNode,
ComponentCodegenNode,
ElementCodegenNodeWithDirective,
CompoenntCodegenNodeWithDirective
} from '../ast'
import { createCompilerError, ErrorCodes } from '../errors'
import { processExpression } from './transformExpression'
@@ -31,7 +39,6 @@ import {
RENDER_SLOT
} from '../runtimeHelpers'
import { injectProp } from '../utils'
import { PropsExpression } from './transformElement'
export const transformIf = createStructuralDirectiveTransform(
/^(if|else|else-if)$/,
@@ -57,7 +64,8 @@ export const transformIf = createStructuralDirectiveTransform(
const branch = createIfBranch(node, dir)
const codegenNode = createSequenceExpression([
createCallExpression(context.helper(OPEN_BLOCK))
])
]) as IfCodegenNode
context.replaceNode({
type: NodeTypes.IF,
loc: node.loc,
@@ -68,9 +76,11 @@ export const transformIf = createStructuralDirectiveTransform(
// Exit callback. Complete the codegenNode when all children have been
// transformed.
return () => {
codegenNode.expressions.push(
createCodegenNodeForBranch(branch, 0, context)
)
codegenNode.expressions.push(createCodegenNodeForBranch(
branch,
0,
context
) as IfConditionalExpression)
}
} else {
// locate the adjacent v-if
@@ -137,7 +147,7 @@ function createCodegenNodeForBranch(
branch: IfBranchNode,
index: number,
context: TransformContext
): ConditionalExpression | CallExpression {
): IfConditionalExpression | BlockCodegenNode {
if (branch.condition) {
return createConditionalExpression(
branch.condition,
@@ -145,9 +155,9 @@ function createCodegenNodeForBranch(
createCallExpression(context.helper(CREATE_BLOCK), [
context.helper(EMPTY)
])
)
) as IfConditionalExpression
} else {
return createChildrenCodegenNode(branch, index, context)
return createChildrenCodegenNode(branch, index, context) as BlockCodegenNode
}
}
@@ -173,23 +183,27 @@ function createChildrenCodegenNode(
]
if (children.length === 1 && child.type === NodeTypes.FOR) {
// optimize away nested fragments when child is a ForNode
const forBlockArgs = (child.codegenNode.expressions[1] as CallExpression)
.arguments
const forBlockArgs = child.codegenNode.expressions[1].arguments
// directly use the for block's children and patchFlag
blockArgs[2] = forBlockArgs[2]
blockArgs[3] = forBlockArgs[3]
}
return createCallExpression(helper(CREATE_BLOCK), blockArgs)
} else {
const childCodegen = (child as ElementNode).codegenNode as CallExpression
const childCodegen = (child as ElementNode).codegenNode as
| ElementCodegenNode
| ComponentCodegenNode
| ElementCodegenNodeWithDirective
| CompoenntCodegenNodeWithDirective
| SlotOutletCodegenNode
let vnodeCall = childCodegen
// Element with custom directives. Locate the actual createVNode() call.
if (vnodeCall.callee === APPLY_DIRECTIVES) {
vnodeCall = vnodeCall.arguments[0] as CallExpression
vnodeCall = vnodeCall.arguments[0]
}
// Change createVNode to createBlock.
if (vnodeCall.callee === CREATE_VNODE) {
vnodeCall.callee = helper(CREATE_BLOCK)
;(vnodeCall as any).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
@@ -197,10 +211,9 @@ function createChildrenCodegenNode(
// logic below works for it too.
const propsIndex = vnodeCall.callee === RENDER_SLOT ? 2 : 1
// inject branch key
const existingProps = vnodeCall.arguments[propsIndex] as
| PropsExpression
| undefined
| 'null'
const existingProps = vnodeCall.arguments[
propsIndex
] as ElementCodegenNode['arguments'][1]
vnodeCall.arguments[propsIndex] = injectProp(
existingProps,
keyProperty,