fix(compiler): do not hoist element with dynamic key (#187)
This commit is contained in:
parent
f11dadc1d2
commit
80f5cb2700
@ -1,6 +1,23 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`compiler: hositStatic transform hoist nested static tree 1`] = `
|
||||
exports[`compiler: hoistStatic transform hoist element with static key 1`] = `
|
||||
"const _Vue = Vue
|
||||
const _createVNode = Vue.createVNode
|
||||
|
||||
const _hoisted_1 = _createVNode(\\"div\\", { key: \\"foo\\" })
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||
|
||||
return (_openBlock(), _createBlock(\\"div\\", null, [
|
||||
_hoisted_1
|
||||
]))
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: hoistStatic transform hoist nested static tree 1`] = `
|
||||
"const _Vue = Vue
|
||||
const _createVNode = Vue.createVNode
|
||||
|
||||
@ -20,7 +37,7 @@ return function render() {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: hositStatic transform hoist siblings with common non-hoistable parent 1`] = `
|
||||
exports[`compiler: hoistStatic transform hoist siblings with common non-hoistable parent 1`] = `
|
||||
"const _Vue = Vue
|
||||
const _createVNode = Vue.createVNode
|
||||
|
||||
@ -39,7 +56,7 @@ return function render() {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: hositStatic transform hoist simple element 1`] = `
|
||||
exports[`compiler: hoistStatic transform hoist simple element 1`] = `
|
||||
"const _Vue = Vue
|
||||
const _createVNode = Vue.createVNode
|
||||
|
||||
@ -56,7 +73,7 @@ return function render() {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: hositStatic transform hoist static props for elements with directives 1`] = `
|
||||
exports[`compiler: hoistStatic transform hoist static props for elements with directives 1`] = `
|
||||
"const _Vue = Vue
|
||||
const _createVNode = Vue.createVNode
|
||||
|
||||
@ -77,7 +94,7 @@ return function render() {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: hositStatic transform hoist static props for elements with dynamic text children 1`] = `
|
||||
exports[`compiler: hoistStatic transform hoist static props for elements with dynamic text children 1`] = `
|
||||
"const _Vue = Vue
|
||||
const _createVNode = Vue.createVNode
|
||||
|
||||
@ -94,7 +111,7 @@ return function render() {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: hositStatic transform hoist static props for elements with unhoistable children 1`] = `
|
||||
exports[`compiler: hoistStatic transform hoist static props for elements with unhoistable children 1`] = `
|
||||
"const _Vue = Vue
|
||||
const _createVNode = Vue.createVNode
|
||||
|
||||
@ -115,7 +132,7 @@ return function render() {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: hositStatic transform should NOT hoist components 1`] = `
|
||||
exports[`compiler: hoistStatic transform should NOT hoist components 1`] = `
|
||||
"const _Vue = Vue
|
||||
|
||||
return function render() {
|
||||
@ -131,7 +148,21 @@ return function render() {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: hositStatic transform should NOT hoist element with dynamic props 1`] = `
|
||||
exports[`compiler: hoistStatic transform should NOT hoist element with dynamic key 1`] = `
|
||||
"const _Vue = Vue
|
||||
|
||||
return function render() {
|
||||
with (this) {
|
||||
const { createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue
|
||||
|
||||
return (_openBlock(), _createBlock(\\"div\\", null, [
|
||||
_createVNode(\\"div\\", { key: foo })
|
||||
]))
|
||||
}
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: hoistStatic transform should NOT hoist element with dynamic props 1`] = `
|
||||
"const _Vue = Vue
|
||||
|
||||
return function render() {
|
||||
@ -145,7 +176,7 @@ return function render() {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: hositStatic transform should NOT hoist root node 1`] = `
|
||||
exports[`compiler: hoistStatic transform should NOT hoist root node 1`] = `
|
||||
"const _Vue = Vue
|
||||
|
||||
return function render() {
|
||||
@ -157,7 +188,7 @@ return function render() {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: hositStatic transform should hoist v-for children if static 1`] = `
|
||||
exports[`compiler: hoistStatic transform should hoist v-for children if static 1`] = `
|
||||
"const _Vue = Vue
|
||||
const _createVNode = Vue.createVNode
|
||||
|
||||
@ -179,7 +210,7 @@ return function render() {
|
||||
}"
|
||||
`;
|
||||
|
||||
exports[`compiler: hositStatic transform should hoist v-if props/children if static 1`] = `
|
||||
exports[`compiler: hoistStatic transform should hoist v-if props/children if static 1`] = `
|
||||
"const _Vue = Vue
|
||||
const _createVNode = Vue.createVNode
|
||||
|
||||
|
@ -42,7 +42,7 @@ function transformWithHoist(template: string) {
|
||||
}
|
||||
}
|
||||
|
||||
describe('compiler: hositStatic transform', () => {
|
||||
describe('compiler: hoistStatic transform', () => {
|
||||
test('should NOT hoist root node', () => {
|
||||
// if the whole tree is static, the root still needs to be a block
|
||||
// so that it's patched in optimized mode to skip children
|
||||
@ -187,6 +187,52 @@ describe('compiler: hositStatic transform', () => {
|
||||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('hoist element with static key', () => {
|
||||
const { root, args } = transformWithHoist(`<div><div key="foo"/></div>`)
|
||||
expect(root.hoists.length).toBe(1)
|
||||
expect(root.hoists).toMatchObject([
|
||||
{
|
||||
type: NodeTypes.JS_CALL_EXPRESSION,
|
||||
callee: CREATE_VNODE,
|
||||
arguments: [`"div"`, createObjectMatcher({ key: 'foo' })]
|
||||
}
|
||||
])
|
||||
expect(args).toMatchObject([
|
||||
`"div"`,
|
||||
`null`,
|
||||
[
|
||||
{
|
||||
type: NodeTypes.ELEMENT,
|
||||
codegenNode: {
|
||||
type: NodeTypes.SIMPLE_EXPRESSION,
|
||||
content: `_hoisted_1`
|
||||
}
|
||||
}
|
||||
]
|
||||
])
|
||||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('should NOT hoist element with dynamic key', () => {
|
||||
const { root, args } = transformWithHoist(`<div><div :key="foo"/></div>`)
|
||||
expect(root.hoists.length).toBe(0)
|
||||
expect(args[2]).toMatchObject([
|
||||
{
|
||||
type: NodeTypes.ELEMENT,
|
||||
codegenNode: {
|
||||
callee: CREATE_VNODE,
|
||||
arguments: [
|
||||
`"div"`,
|
||||
createObjectMatcher({
|
||||
key: `[foo]`
|
||||
})
|
||||
]
|
||||
}
|
||||
}
|
||||
])
|
||||
expect(generate(root).code).toMatchSnapshot()
|
||||
})
|
||||
|
||||
test('hoist static props for elements with directives', () => {
|
||||
const { root, args } = transformWithHoist(
|
||||
`<div><div id="foo" v-foo/></div>`
|
||||
|
@ -6,12 +6,18 @@ import {
|
||||
ElementCodegenNode,
|
||||
PlainElementNode,
|
||||
ComponentNode,
|
||||
TemplateNode
|
||||
TemplateNode,
|
||||
ElementNode
|
||||
} from '../ast'
|
||||
import { TransformContext } from '../transform'
|
||||
import { APPLY_DIRECTIVES } from '../runtimeHelpers'
|
||||
import { PatchFlags } from '@vue/shared'
|
||||
import { isSlotOutlet } from '../utils'
|
||||
import { isSlotOutlet, findProp } from '../utils'
|
||||
|
||||
function hasDynamicKey(node: ElementNode) {
|
||||
const keyProp = findProp(node, 'key')
|
||||
return keyProp && keyProp.type === NodeTypes.DIRECTIVE
|
||||
}
|
||||
|
||||
export function hoistStatic(root: RootNode, context: TransformContext) {
|
||||
walk(
|
||||
@ -47,7 +53,11 @@ function walk(
|
||||
child.type === NodeTypes.ELEMENT &&
|
||||
child.tagType === ElementTypes.ELEMENT
|
||||
) {
|
||||
if (!doNotHoistNode && isStaticNode(child, resultCache)) {
|
||||
if (
|
||||
!doNotHoistNode &&
|
||||
isStaticNode(child, resultCache) &&
|
||||
!hasDynamicKey(child)
|
||||
) {
|
||||
// whole tree is static
|
||||
child.codegenNode = context.hoist(child.codegenNode!)
|
||||
continue
|
||||
@ -56,9 +66,10 @@ function walk(
|
||||
// hoisting.
|
||||
const flag = getPatchFlag(child)
|
||||
if (
|
||||
!flag ||
|
||||
(!flag ||
|
||||
flag === PatchFlags.NEED_PATCH ||
|
||||
flag === PatchFlags.TEXT
|
||||
flag === PatchFlags.TEXT) &&
|
||||
!hasDynamicKey(child)
|
||||
) {
|
||||
let codegenNode = child.codegenNode as ElementCodegenNode
|
||||
if (codegenNode.callee === APPLY_DIRECTIVES) {
|
||||
|
Loading…
Reference in New Issue
Block a user