wip(compiler): codegen node w/ block optimization for v-for
This commit is contained in:
@@ -7,11 +7,20 @@ import {
|
||||
ExpressionNode,
|
||||
createSimpleExpression,
|
||||
SourceLocation,
|
||||
SimpleExpressionNode
|
||||
SimpleExpressionNode,
|
||||
createSequenceExpression,
|
||||
createCallExpression,
|
||||
createFunctionExpression,
|
||||
ElementTypes
|
||||
} from '../ast'
|
||||
import { createCompilerError, ErrorCodes } from '../errors'
|
||||
import { getInnerRange } from '../utils'
|
||||
import { RENDER_LIST } from '../runtimeConstants'
|
||||
import {
|
||||
RENDER_LIST,
|
||||
OPEN_BLOCK,
|
||||
CREATE_BLOCK,
|
||||
FRAGMENT
|
||||
} from '../runtimeConstants'
|
||||
import { processExpression } from './transformExpression'
|
||||
|
||||
export const transformFor = createStructuralDirectiveTransform(
|
||||
@@ -26,9 +35,14 @@ export const transformFor = createStructuralDirectiveTransform(
|
||||
)
|
||||
|
||||
if (parseResult) {
|
||||
context.helper(RENDER_LIST)
|
||||
const { helper, addIdentifiers, removeIdentifiers } = context
|
||||
const { source, value, key, index } = parseResult
|
||||
|
||||
const codegenNode = createSequenceExpression([
|
||||
createCallExpression(helper(OPEN_BLOCK))
|
||||
// to be filled in on exit after children traverse
|
||||
])
|
||||
|
||||
context.replaceNode({
|
||||
type: NodeTypes.FOR,
|
||||
loc: dir.loc,
|
||||
@@ -36,19 +50,52 @@ export const transformFor = createStructuralDirectiveTransform(
|
||||
valueAlias: value,
|
||||
keyAlias: key,
|
||||
objectIndexAlias: index,
|
||||
children: [node]
|
||||
children: [node],
|
||||
codegenNode
|
||||
})
|
||||
|
||||
if (!__BROWSER__) {
|
||||
// scope management
|
||||
const { addIdentifiers, removeIdentifiers } = context
|
||||
|
||||
// inject identifiers to context
|
||||
value && addIdentifiers(value)
|
||||
key && addIdentifiers(key)
|
||||
index && addIdentifiers(index)
|
||||
}
|
||||
|
||||
return () => {
|
||||
return () => {
|
||||
const params: ExpressionNode[] = []
|
||||
if (value) {
|
||||
params.push(value)
|
||||
}
|
||||
if (key) {
|
||||
if (!value) {
|
||||
params.push(createSimpleExpression(`_`, false))
|
||||
}
|
||||
params.push(key)
|
||||
}
|
||||
if (index) {
|
||||
if (!key) {
|
||||
params.push(createSimpleExpression(`__`, false))
|
||||
}
|
||||
params.push(index)
|
||||
}
|
||||
|
||||
codegenNode.expressions.push(
|
||||
createCallExpression(helper(CREATE_BLOCK), [
|
||||
helper(FRAGMENT),
|
||||
`null`,
|
||||
createCallExpression(helper(RENDER_LIST), [
|
||||
source,
|
||||
createFunctionExpression(
|
||||
params,
|
||||
node.tagType === ElementTypes.TEMPLATE ? node.children : node,
|
||||
true /* force newline to make it more readable */
|
||||
)
|
||||
])
|
||||
])
|
||||
)
|
||||
|
||||
if (!__BROWSER__) {
|
||||
value && removeIdentifiers(value)
|
||||
key && removeIdentifiers(key)
|
||||
index && removeIdentifiers(index)
|
||||
|
||||
@@ -20,7 +20,9 @@ import {
|
||||
ObjectExpression,
|
||||
createObjectProperty,
|
||||
Property,
|
||||
ExpressionNode
|
||||
ExpressionNode,
|
||||
TemplateChildNode,
|
||||
FunctionExpression
|
||||
} from '../ast'
|
||||
import { createCompilerError, ErrorCodes } from '../errors'
|
||||
import { processExpression } from './transformExpression'
|
||||
@@ -68,7 +70,7 @@ export const transformIf = createStructuralDirectiveTransform(
|
||||
// transformed.
|
||||
return () => {
|
||||
codegenNode.expressions.push(
|
||||
createCodegenNodeForBranch(node, branch, 0, context)
|
||||
createCodegenNodeForBranch(branch, 0, context)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@@ -105,7 +107,6 @@ export const transformIf = createStructuralDirectiveTransform(
|
||||
parentCondition = parentCondition.alternate
|
||||
} else {
|
||||
parentCondition.alternate = createCodegenNodeForBranch(
|
||||
node,
|
||||
branch,
|
||||
sibling.branches.length - 1,
|
||||
context
|
||||
@@ -139,7 +140,6 @@ function createIfBranch(node: ElementNode, dir: DirectiveNode): IfBranchNode {
|
||||
}
|
||||
|
||||
function createCodegenNodeForBranch(
|
||||
node: ElementNode,
|
||||
branch: IfBranchNode,
|
||||
index: number,
|
||||
context: TransformContext
|
||||
@@ -147,41 +147,50 @@ function createCodegenNodeForBranch(
|
||||
if (branch.condition) {
|
||||
return createConditionalExpression(
|
||||
branch.condition,
|
||||
createChildrenCodegenNode(node, branch, index, context),
|
||||
createChildrenCodegenNode(branch, index, context),
|
||||
createCallExpression(context.helper(CREATE_BLOCK), [
|
||||
context.helper(EMPTY)
|
||||
])
|
||||
)
|
||||
} else {
|
||||
return createChildrenCodegenNode(node, branch, index, context)
|
||||
return createChildrenCodegenNode(branch, index, context)
|
||||
}
|
||||
}
|
||||
|
||||
function createChildrenCodegenNode(
|
||||
node: ElementNode,
|
||||
branch: IfBranchNode,
|
||||
index: number,
|
||||
{ helper }: TransformContext
|
||||
): CallExpression {
|
||||
const isTemplate = node.tagType === ElementTypes.TEMPLATE
|
||||
const keyExp = `{ key: ${index} }`
|
||||
if (isTemplate) {
|
||||
const { children } = branch
|
||||
const child = children[0]
|
||||
const needFragmentWrapper =
|
||||
children.length > 1 || child.type !== NodeTypes.ELEMENT
|
||||
if (needFragmentWrapper) {
|
||||
let fragmentChildren: TemplateChildNode[] | FunctionExpression = children
|
||||
// optimize away nested fragments when child is a ForNode
|
||||
if (children.length === 1 && child.type === NodeTypes.FOR) {
|
||||
fragmentChildren = (child.codegenNode.expressions[1] as CallExpression)
|
||||
.arguments[2] as FunctionExpression
|
||||
}
|
||||
return createCallExpression(helper(CREATE_BLOCK), [
|
||||
helper(FRAGMENT),
|
||||
keyExp,
|
||||
branch.children
|
||||
fragmentChildren
|
||||
])
|
||||
} else {
|
||||
let childCodegen = node.codegenNode!
|
||||
if (childCodegen.callee.includes(APPLY_DIRECTIVES)) {
|
||||
childCodegen = childCodegen.arguments[0] as CallExpression
|
||||
const childCodegen = (child as ElementNode).codegenNode!
|
||||
let vnodeCall = childCodegen
|
||||
if (vnodeCall.callee.includes(APPLY_DIRECTIVES)) {
|
||||
vnodeCall = vnodeCall.arguments[0] as CallExpression
|
||||
}
|
||||
// change child to a block
|
||||
childCodegen.callee = helper(CREATE_BLOCK)
|
||||
vnodeCall.callee = helper(CREATE_BLOCK)
|
||||
// branch key
|
||||
const existingProps = childCodegen.arguments[1]
|
||||
const existingProps = vnodeCall.arguments[1]
|
||||
if (!existingProps || existingProps === `null`) {
|
||||
childCodegen.arguments[1] = keyExp
|
||||
vnodeCall.arguments[1] = keyExp
|
||||
} else {
|
||||
// inject branch key if not already have a key
|
||||
const props = existingProps as
|
||||
@@ -202,13 +211,13 @@ function createChildrenCodegenNode(
|
||||
props.properties.unshift(createKeyProperty(index))
|
||||
} else {
|
||||
// single v-bind with expression
|
||||
childCodegen.arguments[1] = createCallExpression(helper(MERGE_PROPS), [
|
||||
vnodeCall.arguments[1] = createCallExpression(helper(MERGE_PROPS), [
|
||||
keyExp,
|
||||
props
|
||||
])
|
||||
}
|
||||
}
|
||||
return node.codegenNode!
|
||||
return childCodegen
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@ function buildSlot(
|
||||
createFunctionExpression(
|
||||
slotProps,
|
||||
children,
|
||||
false,
|
||||
children.length ? children[0].loc : loc
|
||||
)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user