wip(compiler-ssr): v-if
This commit is contained in:
@@ -5,7 +5,7 @@ exports[`compiler: integration tests function mode 1`] = `
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { toDisplayString: _toDisplayString, openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, createCommentVNode: _createCommentVNode, Fragment: _Fragment, renderList: _renderList, createTextVNode: _createTextVNode } = _Vue
|
||||
const { toDisplayString: _toDisplayString, createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock, createCommentVNode: _createCommentVNode, Fragment: _Fragment, renderList: _renderList, createTextVNode: _createTextVNode } = _Vue
|
||||
|
||||
return (_openBlock(), _createBlock(\\"div\\", {
|
||||
id: \\"foo\\",
|
||||
@@ -26,7 +26,7 @@ return function render() {
|
||||
`;
|
||||
|
||||
exports[`compiler: integration tests function mode w/ prefixIdentifiers: true 1`] = `
|
||||
"const { toDisplayString, openBlock, createVNode, createBlock, createCommentVNode, Fragment, renderList, createTextVNode } = Vue
|
||||
"const { toDisplayString, createVNode, openBlock, createBlock, createCommentVNode, Fragment, renderList, createTextVNode } = Vue
|
||||
|
||||
return function render() {
|
||||
const _ctx = this
|
||||
@@ -48,7 +48,7 @@ return function render() {
|
||||
`;
|
||||
|
||||
exports[`compiler: integration tests module mode 1`] = `
|
||||
"import { toDisplayString, openBlock, createVNode, createBlock, createCommentVNode, Fragment, renderList, createTextVNode } from \\"vue\\"
|
||||
"import { toDisplayString, createVNode, openBlock, createBlock, createCommentVNode, Fragment, renderList, createTextVNode } from \\"vue\\"
|
||||
|
||||
export function render() {
|
||||
const _ctx = this
|
||||
|
||||
@@ -380,7 +380,7 @@ const _hoisted_2 = _createVNode(\\"span\\")
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
|
||||
const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
|
||||
|
||||
return (_openBlock(), _createBlock(\\"div\\", null, [
|
||||
(_openBlock(), ok
|
||||
|
||||
@@ -155,7 +155,7 @@ exports[`compiler: v-for codegen v-if + v-for 1`] = `
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { openBlock: _openBlock, renderList: _renderList, createBlock: _createBlock, Fragment: _Fragment, createVNode: _createVNode, createCommentVNode: _createCommentVNode } = _Vue
|
||||
const { renderList: _renderList, openBlock: _openBlock, createBlock: _createBlock, Fragment: _Fragment, createVNode: _createVNode, createCommentVNode: _createCommentVNode } = _Vue
|
||||
|
||||
return (_openBlock(), ok
|
||||
? _createBlock(_Fragment, { key: 0 }, _renderList(list, (i) => {
|
||||
|
||||
@@ -5,7 +5,7 @@ exports[`compiler: v-if codegen basic v-if 1`] = `
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
|
||||
const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
|
||||
|
||||
return (_openBlock(), ok
|
||||
? _createBlock(\\"div\\", { key: 0 })
|
||||
@@ -19,7 +19,7 @@ exports[`compiler: v-if codegen template v-if 1`] = `
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { openBlock: _openBlock, createVNode: _createVNode, Fragment: _Fragment, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
|
||||
const { createVNode: _createVNode, openBlock: _openBlock, Fragment: _Fragment, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
|
||||
|
||||
return (_openBlock(), ok
|
||||
? _createBlock(_Fragment, { key: 0 }, [
|
||||
@@ -37,7 +37,7 @@ exports[`compiler: v-if codegen template v-if w/ single <slot/> child 1`] = `
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { openBlock: _openBlock, renderSlot: _renderSlot, createCommentVNode: _createCommentVNode } = _Vue
|
||||
const { renderSlot: _renderSlot, openBlock: _openBlock, createCommentVNode: _createCommentVNode } = _Vue
|
||||
|
||||
return (_openBlock(), ok
|
||||
? _renderSlot($slots, \\"default\\", { key: 0 })
|
||||
@@ -51,7 +51,7 @@ exports[`compiler: v-if codegen v-if + v-else 1`] = `
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
|
||||
const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
|
||||
|
||||
return (_openBlock(), ok
|
||||
? _createBlock(\\"div\\", { key: 0 })
|
||||
@@ -65,7 +65,7 @@ exports[`compiler: v-if codegen v-if + v-else-if + v-else 1`] = `
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, createCommentVNode: _createCommentVNode, Fragment: _Fragment } = _Vue
|
||||
const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock, createCommentVNode: _createCommentVNode, Fragment: _Fragment } = _Vue
|
||||
|
||||
return (_openBlock(), ok
|
||||
? _createBlock(\\"div\\", { key: 0 })
|
||||
@@ -81,7 +81,7 @@ exports[`compiler: v-if codegen v-if + v-else-if 1`] = `
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
|
||||
const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
|
||||
|
||||
return (_openBlock(), ok
|
||||
? _createBlock(\\"div\\", { key: 0 })
|
||||
@@ -97,7 +97,7 @@ exports[`compiler: v-if codegen v-if on <slot/> 1`] = `
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { openBlock: _openBlock, renderSlot: _renderSlot, createCommentVNode: _createCommentVNode } = _Vue
|
||||
const { renderSlot: _renderSlot, openBlock: _openBlock, createCommentVNode: _createCommentVNode } = _Vue
|
||||
|
||||
return (_openBlock(), ok
|
||||
? _renderSlot($slots, \\"default\\", { key: 0 })
|
||||
@@ -111,7 +111,7 @@ exports[`compiler: v-if codegen v-if with key 1`] = `
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { openBlock: _openBlock, createVNode: _createVNode, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
|
||||
const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock, createCommentVNode: _createCommentVNode } = _Vue
|
||||
|
||||
return (_openBlock(), ok
|
||||
? _createBlock(\\"div\\", { key: \\"some-key\\" })
|
||||
|
||||
@@ -12,7 +12,8 @@ import {
|
||||
SimpleExpressionNode,
|
||||
SequenceExpression,
|
||||
ConditionalExpression,
|
||||
CallExpression
|
||||
CallExpression,
|
||||
IfCodegenNode
|
||||
} from '../../src/ast'
|
||||
import { ErrorCodes } from '../../src/errors'
|
||||
import { CompilerOptions, generate } from '../../src'
|
||||
@@ -43,7 +44,7 @@ function parseWithIfTransform(
|
||||
}
|
||||
return {
|
||||
root: ast,
|
||||
node: ast.children[returnIndex] as IfNode
|
||||
node: ast.children[returnIndex] as IfNode & { codegenNode: IfCodegenNode }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ export interface RootNode extends Node {
|
||||
hoists: JSChildNode[]
|
||||
imports: ImportItem[]
|
||||
cached: number
|
||||
codegenNode: TemplateChildNode | JSChildNode | BlockStatement | undefined
|
||||
codegenNode?: TemplateChildNode | JSChildNode | BlockStatement | undefined
|
||||
}
|
||||
|
||||
export type ElementNode =
|
||||
@@ -213,7 +213,7 @@ export interface CompoundExpressionNode extends Node {
|
||||
export interface IfNode extends Node {
|
||||
type: NodeTypes.IF
|
||||
branches: IfBranchNode[]
|
||||
codegenNode: IfCodegenNode
|
||||
codegenNode?: IfCodegenNode
|
||||
}
|
||||
|
||||
export interface IfBranchNode extends Node {
|
||||
@@ -229,7 +229,7 @@ export interface ForNode extends Node {
|
||||
keyAlias: ExpressionNode | undefined
|
||||
objectIndexAlias: ExpressionNode | undefined
|
||||
children: TemplateChildNode[]
|
||||
codegenNode: ForCodegenNode
|
||||
codegenNode?: ForCodegenNode
|
||||
}
|
||||
|
||||
export interface TextCallNode extends Node {
|
||||
|
||||
@@ -32,7 +32,11 @@ export { transformModel } from './transforms/vModel'
|
||||
export { transformOn } from './transforms/vOn'
|
||||
|
||||
// exported for compiler-ssr
|
||||
export { transformExpression } from './transforms/transformExpression'
|
||||
export { processIfBranches } from './transforms/vIf'
|
||||
export {
|
||||
transformExpression,
|
||||
processExpression
|
||||
} from './transforms/transformExpression'
|
||||
export { trackVForSlotScopes, trackSlotScopes } from './transforms/vSlot'
|
||||
export { buildProps } from './transforms/transformElement'
|
||||
|
||||
|
||||
@@ -23,7 +23,8 @@ import {
|
||||
BlockCodegenNode,
|
||||
SlotOutletCodegenNode,
|
||||
ElementCodegenNode,
|
||||
ComponentCodegenNode
|
||||
ComponentCodegenNode,
|
||||
IfNode
|
||||
} from '../ast'
|
||||
import { createCompilerError, ErrorCodes } from '../errors'
|
||||
import { processExpression } from './transformExpression'
|
||||
@@ -40,73 +41,18 @@ import { injectProp } from '../utils'
|
||||
export const transformIf = createStructuralDirectiveTransform(
|
||||
/^(if|else|else-if)$/,
|
||||
(node, dir, context) => {
|
||||
if (
|
||||
dir.name !== 'else' &&
|
||||
(!dir.exp || !(dir.exp as SimpleExpressionNode).content.trim())
|
||||
) {
|
||||
const loc = dir.exp ? dir.exp.loc : node.loc
|
||||
context.onError(
|
||||
createCompilerError(ErrorCodes.X_V_IF_NO_EXPRESSION, dir.loc)
|
||||
)
|
||||
dir.exp = createSimpleExpression(`true`, false, loc)
|
||||
}
|
||||
|
||||
if (!__BROWSER__ && context.prefixIdentifiers && dir.exp) {
|
||||
// dir.exp can only be simple expression because vIf transform is applied
|
||||
// before expression transform.
|
||||
dir.exp = processExpression(dir.exp as SimpleExpressionNode, context)
|
||||
}
|
||||
|
||||
if (dir.name === 'if') {
|
||||
const branch = createIfBranch(node, dir)
|
||||
const codegenNode = createSequenceExpression([
|
||||
createCallExpression(context.helper(OPEN_BLOCK))
|
||||
]) as IfCodegenNode
|
||||
|
||||
context.replaceNode({
|
||||
type: NodeTypes.IF,
|
||||
loc: node.loc,
|
||||
branches: [branch],
|
||||
codegenNode
|
||||
})
|
||||
|
||||
return processIfBranches(node, dir, context, (ifNode, branch, isRoot) => {
|
||||
// Exit callback. Complete the codegenNode when all children have been
|
||||
// transformed.
|
||||
return () => {
|
||||
codegenNode.expressions.push(createCodegenNodeForBranch(
|
||||
branch,
|
||||
0,
|
||||
context
|
||||
) as IfConditionalExpression)
|
||||
}
|
||||
} else {
|
||||
// locate the adjacent v-if
|
||||
const siblings = context.parent!.children
|
||||
const comments = []
|
||||
let i = siblings.indexOf(node)
|
||||
while (i-- >= -1) {
|
||||
const sibling = siblings[i]
|
||||
if (__DEV__ && sibling && sibling.type === NodeTypes.COMMENT) {
|
||||
context.removeNode(sibling)
|
||||
comments.unshift(sibling)
|
||||
continue
|
||||
}
|
||||
if (sibling && sibling.type === NodeTypes.IF) {
|
||||
// move the node to the if node's branches
|
||||
context.removeNode()
|
||||
const branch = createIfBranch(node, dir)
|
||||
if (__DEV__ && comments.length) {
|
||||
branch.children = [...comments, ...branch.children]
|
||||
}
|
||||
sibling.branches.push(branch)
|
||||
// since the branch was removed, it will not be traversed.
|
||||
// make sure to traverse here.
|
||||
traverseChildren(branch, context)
|
||||
// make sure to reset currentNode after traversal to indicate this
|
||||
// node has been removed.
|
||||
context.currentNode = null
|
||||
if (isRoot) {
|
||||
ifNode.codegenNode = createSequenceExpression([
|
||||
createCallExpression(context.helper(OPEN_BLOCK)),
|
||||
createCodegenNodeForBranch(branch, 0, context)
|
||||
]) as IfCodegenNode
|
||||
} else {
|
||||
// attach this branch's codegen node to the v-if root.
|
||||
let parentCondition = sibling.codegenNode
|
||||
let parentCondition = ifNode.codegenNode!
|
||||
.expressions[1] as ConditionalExpression
|
||||
while (
|
||||
parentCondition.alternate.type ===
|
||||
@@ -116,20 +62,92 @@ export const transformIf = createStructuralDirectiveTransform(
|
||||
}
|
||||
parentCondition.alternate = createCodegenNodeForBranch(
|
||||
branch,
|
||||
sibling.branches.length - 1,
|
||||
ifNode.branches.length - 1,
|
||||
context
|
||||
)
|
||||
} else {
|
||||
context.onError(
|
||||
createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, node.loc)
|
||||
)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
export const processIfBranches = (
|
||||
node: ElementNode,
|
||||
dir: DirectiveNode,
|
||||
context: TransformContext,
|
||||
processCodegen?: (
|
||||
node: IfNode,
|
||||
branch: IfBranchNode,
|
||||
isRoot: boolean
|
||||
) => (() => void) | void
|
||||
) => {
|
||||
if (
|
||||
dir.name !== 'else' &&
|
||||
(!dir.exp || !(dir.exp as SimpleExpressionNode).content.trim())
|
||||
) {
|
||||
const loc = dir.exp ? dir.exp.loc : node.loc
|
||||
context.onError(
|
||||
createCompilerError(ErrorCodes.X_V_IF_NO_EXPRESSION, dir.loc)
|
||||
)
|
||||
dir.exp = createSimpleExpression(`true`, false, loc)
|
||||
}
|
||||
|
||||
if (!__BROWSER__ && context.prefixIdentifiers && dir.exp) {
|
||||
// dir.exp can only be simple expression because vIf transform is applied
|
||||
// before expression transform.
|
||||
dir.exp = processExpression(dir.exp as SimpleExpressionNode, context)
|
||||
}
|
||||
|
||||
if (dir.name === 'if') {
|
||||
const branch = createIfBranch(node, dir)
|
||||
const ifNode: IfNode = {
|
||||
type: NodeTypes.IF,
|
||||
loc: node.loc,
|
||||
branches: [branch]
|
||||
}
|
||||
context.replaceNode(ifNode)
|
||||
if (processCodegen) {
|
||||
return processCodegen(ifNode, branch, true)
|
||||
}
|
||||
} else {
|
||||
// locate the adjacent v-if
|
||||
const siblings = context.parent!.children
|
||||
const comments = []
|
||||
let i = siblings.indexOf(node)
|
||||
while (i-- >= -1) {
|
||||
const sibling = siblings[i]
|
||||
if (__DEV__ && sibling && sibling.type === NodeTypes.COMMENT) {
|
||||
context.removeNode(sibling)
|
||||
comments.unshift(sibling)
|
||||
continue
|
||||
}
|
||||
if (sibling && sibling.type === NodeTypes.IF) {
|
||||
// move the node to the if node's branches
|
||||
context.removeNode()
|
||||
const branch = createIfBranch(node, dir)
|
||||
if (__DEV__ && comments.length) {
|
||||
branch.children = [...comments, ...branch.children]
|
||||
}
|
||||
sibling.branches.push(branch)
|
||||
const onExit = processCodegen && processCodegen(sibling, branch, false)
|
||||
// since the branch was removed, it will not be traversed.
|
||||
// make sure to traverse here.
|
||||
traverseChildren(branch, context)
|
||||
// call on exit
|
||||
if (onExit) onExit()
|
||||
// make sure to reset currentNode after traversal to indicate this
|
||||
// node has been removed.
|
||||
context.currentNode = null
|
||||
} else {
|
||||
context.onError(
|
||||
createCompilerError(ErrorCodes.X_V_ELSE_NO_ADJACENT_IF, node.loc)
|
||||
)
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createIfBranch(node: ElementNode, dir: DirectiveNode): IfBranchNode {
|
||||
return {
|
||||
type: NodeTypes.IF_BRANCH,
|
||||
@@ -171,25 +189,25 @@ function createChildrenCodegenNode(
|
||||
createSimpleExpression(index + '', false)
|
||||
)
|
||||
const { children } = branch
|
||||
const child = children[0]
|
||||
const firstChild = children[0]
|
||||
const needFragmentWrapper =
|
||||
children.length !== 1 || child.type !== NodeTypes.ELEMENT
|
||||
children.length !== 1 || firstChild.type !== NodeTypes.ELEMENT
|
||||
if (needFragmentWrapper) {
|
||||
const blockArgs: CallExpression['arguments'] = [
|
||||
helper(FRAGMENT),
|
||||
createObjectExpression([keyProperty]),
|
||||
children
|
||||
]
|
||||
if (children.length === 1 && child.type === NodeTypes.FOR) {
|
||||
if (children.length === 1 && firstChild.type === NodeTypes.FOR) {
|
||||
// optimize away nested fragments when child is a ForNode
|
||||
const forBlockArgs = child.codegenNode.expressions[1].arguments
|
||||
const forBlockArgs = firstChild.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
|
||||
const childCodegen = (firstChild as ElementNode).codegenNode as
|
||||
| ElementCodegenNode
|
||||
| ComponentCodegenNode
|
||||
| SlotOutletCodegenNode
|
||||
|
||||
Reference in New Issue
Block a user