fix(compiler-core): force <svg> into blocks for correct runtime isSVG

state during patch
This commit is contained in:
Evan You 2020-01-20 14:48:19 -05:00
parent 0c42a6d8fa
commit f2ac28b31e
3 changed files with 48 additions and 7 deletions

View File

@ -16,7 +16,9 @@ import {
RESOLVE_DYNAMIC_COMPONENT, RESOLVE_DYNAMIC_COMPONENT,
SUSPENSE, SUSPENSE,
KEEP_ALIVE, KEEP_ALIVE,
BASE_TRANSITION BASE_TRANSITION,
OPEN_BLOCK,
CREATE_BLOCK
} from '../../src/runtimeHelpers' } from '../../src/runtimeHelpers'
import { import {
CallExpression, CallExpression,
@ -821,4 +823,25 @@ describe('compiler: element transform', () => {
]) ])
}) })
}) })
test('<svg> should be forced into blocks', () => {
const ast = parse(`<div><svg/></div>`)
transform(ast, {
nodeTransforms: [transformElement]
})
expect((ast as any).children[0].children[0].codegenNode).toMatchObject({
type: NodeTypes.JS_SEQUENCE_EXPRESSION,
expressions: [
{
type: NodeTypes.JS_CALL_EXPRESSION,
callee: OPEN_BLOCK
},
{
type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_BLOCK,
arguments: [`"svg"`]
}
]
})
})
}) })

View File

@ -118,6 +118,7 @@ export interface BaseElementNode extends Node {
| CallExpression | CallExpression
| SimpleExpressionNode | SimpleExpressionNode
| CacheExpression | CacheExpression
| SequenceExpression
| undefined | undefined
} }
@ -125,14 +126,18 @@ export interface PlainElementNode extends BaseElementNode {
tagType: ElementTypes.ELEMENT tagType: ElementTypes.ELEMENT
codegenNode: codegenNode:
| ElementCodegenNode | ElementCodegenNode
| undefined
| SimpleExpressionNode // when hoisted | SimpleExpressionNode // when hoisted
| CacheExpression // when cached by v-once | CacheExpression // when cached by v-once
| SequenceExpression // when turned into a block
| undefined
} }
export interface ComponentNode extends BaseElementNode { export interface ComponentNode extends BaseElementNode {
tagType: ElementTypes.COMPONENT tagType: ElementTypes.COMPONENT
codegenNode: ComponentCodegenNode | undefined | CacheExpression // when cached by v-once codegenNode:
| ComponentCodegenNode
| CacheExpression // when cached by v-once
| undefined
} }
export interface SlotOutletNode extends BaseElementNode { export interface SlotOutletNode extends BaseElementNode {

View File

@ -13,7 +13,8 @@ import {
createObjectProperty, createObjectProperty,
createSimpleExpression, createSimpleExpression,
createObjectExpression, createObjectExpression,
Property Property,
createSequenceExpression
} from '../ast' } from '../ast'
import { PatchFlags, PatchFlagNames, isSymbol } from '@vue/shared' import { PatchFlags, PatchFlagNames, isSymbol } from '@vue/shared'
import { createCompilerError, ErrorCodes } from '../errors' import { createCompilerError, ErrorCodes } from '../errors'
@ -26,7 +27,9 @@ import {
MERGE_PROPS, MERGE_PROPS,
TO_HANDLERS, TO_HANDLERS,
PORTAL, PORTAL,
KEEP_ALIVE KEEP_ALIVE,
OPEN_BLOCK,
CREATE_BLOCK
} from '../runtimeHelpers' } from '../runtimeHelpers'
import { import {
getInnerRange, getInnerRange,
@ -67,6 +70,9 @@ export const transformElement: NodeTransform = (node, context) => {
let runtimeDirectives: DirectiveNode[] | undefined let runtimeDirectives: DirectiveNode[] | undefined
let dynamicPropNames: string[] | undefined let dynamicPropNames: string[] | undefined
let dynamicComponent: string | CallExpression | undefined let dynamicComponent: string | CallExpression | undefined
// technically this is web specific but we are keeping it in core to avoid
// extra complexity
let isSVG = false
// handle dynamic component // handle dynamic component
const isProp = findProp(node, 'is') const isProp = findProp(node, 'is')
@ -105,6 +111,7 @@ export const transformElement: NodeTransform = (node, context) => {
} else { } else {
// plain element // plain element
nodeType = `"${node.tag}"` nodeType = `"${node.tag}"`
isSVG = node.tag === 'svg'
} }
const args: CallExpression['arguments'] = [nodeType] const args: CallExpression['arguments'] = [nodeType]
@ -190,8 +197,14 @@ export const transformElement: NodeTransform = (node, context) => {
} }
const { loc } = node const { loc } = node
const vnode = createCallExpression(context.helper(CREATE_VNODE), args, loc) const vnode = isSVG
? // <svg> must be forced into blocks so that block updates inside retain
// isSVG flag at runtime. (#639, #643)
createSequenceExpression([
createCallExpression(context.helper(OPEN_BLOCK)),
createCallExpression(context.helper(CREATE_BLOCK), args, loc)
])
: createCallExpression(context.helper(CREATE_VNODE), args, loc)
if (runtimeDirectives && runtimeDirectives.length) { if (runtimeDirectives && runtimeDirectives.length) {
node.codegenNode = createCallExpression( node.codegenNode = createCallExpression(
context.helper(WITH_DIRECTIVES), context.helper(WITH_DIRECTIVES),