fix(compiler-core): avoid generating useless createVNode helper (#2938)

close #2739
This commit is contained in:
HcySunYang
2021-03-26 05:01:50 +08:00
committed by GitHub
parent 2451dd8ae6
commit 7715c49af9
17 changed files with 117 additions and 77 deletions

View File

@@ -35,7 +35,8 @@ import {
helperNameMap,
CREATE_BLOCK,
CREATE_COMMENT,
OPEN_BLOCK
OPEN_BLOCK,
CREATE_VNODE
} from './runtimeHelpers'
import { isVSlot } from './utils'
import { hoistStatic, isSingleElementRoot } from './transforms/hoistStatic'
@@ -85,7 +86,7 @@ export interface TransformContext
extends Required<Omit<TransformOptions, 'filename'>> {
selfName: string | null
root: RootNode
helpers: Set<symbol>
helpers: Map<symbol, number>
components: Set<string>
directives: Set<string>
hoists: (JSChildNode | null)[]
@@ -103,6 +104,7 @@ export interface TransformContext
childIndex: number
currentNode: RootNode | TemplateChildNode | null
helper<T extends symbol>(name: T): T
removeHelper<T extends symbol>(name: T): void
helperString(name: symbol): string
replaceNode(node: TemplateChildNode): void
removeNode(node?: TemplateChildNode): void
@@ -161,7 +163,7 @@ export function createTransformContext(
// state
root,
helpers: new Set(),
helpers: new Map(),
components: new Set(),
directives: new Set(),
hoists: [],
@@ -182,9 +184,21 @@ export function createTransformContext(
// methods
helper(name) {
context.helpers.add(name)
const count = context.helpers.get(name) || 0
context.helpers.set(name, count + 1)
return name
},
removeHelper(name) {
const count = context.helpers.get(name)
if (count) {
const currentCount = count - 1
if (!currentCount) {
context.helpers.delete(name)
} else {
context.helpers.set(name, currentCount)
}
}
},
helperString(name) {
return `_${helperNameMap[context.helper(name)]}`
},
@@ -292,7 +306,7 @@ export function transform(root: RootNode, options: TransformOptions) {
createRootCodegen(root, context)
}
// finalize meta information
root.helpers = [...context.helpers]
root.helpers = [...context.helpers.keys()]
root.components = [...context.components]
root.directives = [...context.directives]
root.imports = context.imports
@@ -302,7 +316,7 @@ export function transform(root: RootNode, options: TransformOptions) {
}
function createRootCodegen(root: RootNode, context: TransformContext) {
const { helper } = context
const { helper, removeHelper } = context
const { children } = root
if (children.length === 1) {
const child = children[0]
@@ -312,9 +326,12 @@ function createRootCodegen(root: RootNode, context: TransformContext) {
// SimpleExpressionNode
const codegenNode = child.codegenNode
if (codegenNode.type === NodeTypes.VNODE_CALL) {
codegenNode.isBlock = true
helper(OPEN_BLOCK)
helper(CREATE_BLOCK)
if (!codegenNode.isBlock) {
removeHelper(CREATE_VNODE)
codegenNode.isBlock = true
helper(OPEN_BLOCK)
helper(CREATE_BLOCK)
}
}
root.codegenNode = codegenNode
} else {

View File

@@ -14,7 +14,7 @@ import {
import { TransformContext } from '../transform'
import { PatchFlags, isString, isSymbol } from '@vue/shared'
import { isSlotOutlet } from '../utils'
import { CREATE_VNODE } from '../runtimeHelpers'
import { CREATE_BLOCK, CREATE_VNODE, OPEN_BLOCK } from '../runtimeHelpers'
export function hoistStatic(root: RootNode, context: TransformContext) {
walk(
@@ -212,6 +212,8 @@ export function getConstantType(
// static then they don't need to be blocks since there will be no
// nested updates.
if (codegenNode.isBlock) {
context.removeHelper(OPEN_BLOCK)
context.removeHelper(CREATE_BLOCK)
codegenNode.isBlock = false
context.helper(CREATE_VNODE)
}

View File

@@ -48,7 +48,7 @@ import { PatchFlags, PatchFlagNames } from '@vue/shared'
export const transformFor = createStructuralDirectiveTransform(
'for',
(node, dir, context) => {
const { helper } = context
const { helper, removeHelper } = context
return processFor(node, dir, context, forNode => {
// create the loop render function expression now, and add the
// iterator on exit after all children have been traversed
@@ -166,6 +166,16 @@ export const transformFor = createStructuralDirectiveTransform(
if (isTemplate && keyProperty) {
injectProp(childBlock, keyProperty, context)
}
if (childBlock.isBlock !== !isStableFragment) {
if (childBlock.isBlock) {
// switch from block to vnode
removeHelper(OPEN_BLOCK)
removeHelper(CREATE_BLOCK)
} else {
// switch from vnode to block
removeHelper(CREATE_VNODE)
}
}
childBlock.isBlock = !isStableFragment
if (childBlock.isBlock) {
helper(OPEN_BLOCK)

View File

@@ -31,7 +31,8 @@ import {
CREATE_BLOCK,
FRAGMENT,
CREATE_COMMENT,
OPEN_BLOCK
OPEN_BLOCK,
CREATE_VNODE
} from '../runtimeHelpers'
import { injectProp, findDir, findProp } from '../utils'
import { PatchFlags, PatchFlagNames } from '@vue/shared'
@@ -225,7 +226,7 @@ function createChildrenCodegenNode(
keyIndex: number,
context: TransformContext
): BlockCodegenNode {
const { helper } = context
const { helper, removeHelper } = context
const keyProperty = createObjectProperty(
`key`,
createSimpleExpression(
@@ -275,7 +276,8 @@ function createChildrenCodegenNode(
const vnodeCall = (firstChild as ElementNode)
.codegenNode as BlockCodegenNode
// Change createVNode to createBlock.
if (vnodeCall.type === NodeTypes.VNODE_CALL) {
if (vnodeCall.type === NodeTypes.VNODE_CALL && !vnodeCall.isBlock) {
removeHelper(CREATE_VNODE)
vnodeCall.isBlock = true
helper(OPEN_BLOCK)
helper(CREATE_BLOCK)