fix(compiler): handle block nodes with custom directives + improve ast types

This commit is contained in:
Evan You
2019-10-08 10:50:00 -04:00
parent 1393ee52ca
commit 16da9ae89f
15 changed files with 200 additions and 157 deletions

View File

@@ -2,10 +2,8 @@ import {
RootNode,
NodeTypes,
TemplateChildNode,
ElementNode,
ElementTypes,
ElementCodegenNode,
ElementCodegenNodeWithDirective,
PlainElementNode,
ComponentNode,
TemplateNode
@@ -51,7 +49,7 @@ function walk(
) {
if (!doNotHoistNode && isStaticNode(child, resultCache)) {
// whole tree is static
;(child as any).codegenNode = context.hoist(child.codegenNode!)
child.codegenNode = context.hoist(child.codegenNode!)
continue
} else {
// node may contain dynamic children, but its props may be eligible for
@@ -62,7 +60,7 @@ function walk(
flag === PatchFlags.NEED_PATCH ||
flag === PatchFlags.TEXT
) {
let codegenNode = child.codegenNode!
let codegenNode = child.codegenNode as ElementCodegenNode
if (codegenNode.callee === APPLY_DIRECTIVES) {
codegenNode = codegenNode.arguments[0]
}
@@ -88,10 +86,8 @@ function walk(
}
}
function getPatchFlag(node: ElementNode): number | undefined {
let codegenNode = node.codegenNode as
| ElementCodegenNode
| ElementCodegenNodeWithDirective
function getPatchFlag(node: PlainElementNode): number | undefined {
let codegenNode = node.codegenNode as ElementCodegenNode
if (codegenNode.callee === APPLY_DIRECTIVES) {
codegenNode = codegenNode.arguments[0]
}

View File

@@ -15,7 +15,7 @@ import {
createObjectExpression,
createObjectProperty,
ForCodegenNode,
PlainElementNode
ElementCodegenNode
} from '../ast'
import { createCompilerError, ErrorCodes } from '../errors'
import {
@@ -30,11 +30,11 @@ import {
RENDER_LIST,
OPEN_BLOCK,
CREATE_BLOCK,
FRAGMENT
FRAGMENT,
APPLY_DIRECTIVES
} from '../runtimeHelpers'
import { processExpression } from './transformExpression'
import { PatchFlags, PatchFlagNames } from '@vue/shared'
import { PropsExpression } from './transformElement'
export const transformFor = createStructuralDirectiveTransform(
'for',
@@ -124,34 +124,29 @@ export const transformFor = createStructuralDirectiveTransform(
// <template v-for="..." :key="..."><slot/></template>
// we need to inject the key to the renderSlot() call.
// the props for renderSlot is passed as the 3rd argument.
const existingProps = childBlock.arguments[2] as
| PropsExpression
| undefined
| 'null'
childBlock.arguments[2] = injectProp(
existingProps,
keyProperty,
context
)
injectProp(childBlock, keyProperty, context)
}
} else if (isTemplate) {
// <template v-for="...">
// should generate a fragment block for each loop
childBlock = createBlockExpression(
[
createCallExpression(helper(CREATE_BLOCK), [
helper(FRAGMENT),
keyProperty ? createObjectExpression([keyProperty]) : `null`,
node.children
],
]),
context
)
} else {
// Normal element v-for. Directly use the child's codegenNode
// arguments, but replace createVNode() with createBlock()
childBlock = createBlockExpression(
(node as PlainElementNode).codegenNode!.arguments,
context
)
let codegenNode = node.codegenNode as ElementCodegenNode
if (codegenNode.callee === APPLY_DIRECTIVES) {
codegenNode.arguments[0].callee = helper(CREATE_BLOCK)
} else {
codegenNode.callee = helper(CREATE_BLOCK)
}
childBlock = createBlockExpression(codegenNode, context)
}
renderExp.arguments.push(

View File

@@ -23,9 +23,7 @@ import {
BlockCodegenNode,
SlotOutletCodegenNode,
ElementCodegenNode,
ComponentCodegenNode,
ElementCodegenNodeWithDirective,
CompoenntCodegenNodeWithDirective
ComponentCodegenNode
} from '../ast'
import { createCompilerError, ErrorCodes } from '../errors'
import { processExpression } from './transformExpression'
@@ -35,8 +33,7 @@ import {
EMPTY,
FRAGMENT,
APPLY_DIRECTIVES,
CREATE_VNODE,
RENDER_SLOT
CREATE_VNODE
} from '../runtimeHelpers'
import { injectProp } from '../utils'
@@ -196,8 +193,6 @@ function createChildrenCodegenNode(
const childCodegen = (child as ElementNode).codegenNode as
| ElementCodegenNode
| ComponentCodegenNode
| ElementCodegenNodeWithDirective
| CompoenntCodegenNodeWithDirective
| SlotOutletCodegenNode
let vnodeCall = childCodegen
// Element with custom directives. Locate the actual createVNode() call.
@@ -206,22 +201,10 @@ function createChildrenCodegenNode(
}
// Change createVNode to createBlock.
if (vnodeCall.callee === CREATE_VNODE) {
;(vnodeCall as any).callee = helper(CREATE_BLOCK)
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 === RENDER_SLOT ? 2 : 1
// inject branch key
const existingProps = vnodeCall.arguments[
propsIndex
] as ElementCodegenNode['arguments'][1]
vnodeCall.arguments[propsIndex] = injectProp(
existingProps,
keyProperty,
context
)
injectProp(vnodeCall, keyProperty, context)
return childCodegen
}
}