// 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
}"
`;
-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
}"
`;
-exports[`compiler: hositStatic transform hoist simple element 1`] = `
+exports[`compiler: hoistStatic transform hoist simple element 1`] = `
"const _Vue = Vue
const _createVNode = Vue.createVNode
}"
`;
-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
}"
`;
-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
}"
`;
-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
}"
`;
-exports[`compiler: hositStatic transform should NOT hoist components 1`] = `
+exports[`compiler: hoistStatic transform should NOT hoist components 1`] = `
"const _Vue = Vue
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() {
}"
`;
-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() {
}"
`;
-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
}"
`;
-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
}
}
-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
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>`
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(
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
// hoisting.
const flag = getPatchFlag(child)
if (
- !flag ||
- flag === PatchFlags.NEED_PATCH ||
- flag === PatchFlags.TEXT
+ (!flag ||
+ flag === PatchFlags.NEED_PATCH ||
+ flag === PatchFlags.TEXT) &&
+ !hasDynamicKey(child)
) {
let codegenNode = child.codegenNode as ElementCodegenNode
if (codegenNode.callee === APPLY_DIRECTIVES) {