feat(compiler): mark hoisted trees with patchFlag

This commit is contained in:
Evan You 2020-02-12 13:31:29 -05:00
parent d866d389f3
commit 175f8aae8d
6 changed files with 25 additions and 17 deletions

View File

@ -5,8 +5,8 @@ exports[`scopeId compiler support should push scopeId for hoisted nodes 1`] = `
const _withId = _withScopeId(\\"test\\") const _withId = _withScopeId(\\"test\\")
_pushScopeId(\\"test\\") _pushScopeId(\\"test\\")
const _hoisted_1 = _createVNode(\\"div\\", null, \\"hello\\") const _hoisted_1 = _createVNode(\\"div\\", null, \\"hello\\", -1)
const _hoisted_2 = _createVNode(\\"div\\", null, \\"world\\") const _hoisted_2 = _createVNode(\\"div\\", null, \\"world\\", -1)
_popScopeId() _popScopeId()
export const render = _withId(function render(_ctx, _cache) { export const render = _withId(function render(_ctx, _cache) {

View File

@ -81,8 +81,8 @@ describe('scopeId compiler support', () => {
expect(code).toMatch( expect(code).toMatch(
[ [
`_pushScopeId("test")`, `_pushScopeId("test")`,
`const _hoisted_1 = _createVNode("div", null, "hello")`, `const _hoisted_1 = _createVNode("div", null, "hello", -1)`,
`const _hoisted_2 = _createVNode("div", null, "world")`, `const _hoisted_2 = _createVNode("div", null, "world", -1)`,
`_popScopeId()` `_popScopeId()`
].join('\n') ].join('\n')
) )

View File

@ -4,7 +4,7 @@ exports[`compiler: hoistStatic transform hoist element with static key 1`] = `
"const _Vue = Vue "const _Vue = Vue
const { createVNode: _createVNode } = _Vue const { createVNode: _createVNode } = _Vue
const _hoisted_1 = _createVNode(\\"div\\", { key: \\"foo\\" }) const _hoisted_1 = _createVNode(\\"div\\", { key: \\"foo\\" }, null, -1)
return function render(_ctx, _cache) { return function render(_ctx, _cache) {
with (this) { with (this) {
@ -24,7 +24,7 @@ const { createVNode: _createVNode } = _Vue
const _hoisted_1 = _createVNode(\\"p\\", null, [ const _hoisted_1 = _createVNode(\\"p\\", null, [
_createVNode(\\"span\\"), _createVNode(\\"span\\"),
_createVNode(\\"span\\") _createVNode(\\"span\\")
]) ], -1)
return function render(_ctx, _cache) { return function render(_ctx, _cache) {
with (this) { with (this) {
@ -43,7 +43,7 @@ const { createVNode: _createVNode, createCommentVNode: _createCommentVNode } = _
const _hoisted_1 = _createVNode(\\"div\\", null, [ const _hoisted_1 = _createVNode(\\"div\\", null, [
_createCommentVNode(\\"comment\\") _createCommentVNode(\\"comment\\")
]) ], -1)
return function render(_ctx, _cache) { return function render(_ctx, _cache) {
with (this) { with (this) {
@ -60,8 +60,8 @@ exports[`compiler: hoistStatic transform hoist siblings with common non-hoistabl
"const _Vue = Vue "const _Vue = Vue
const { createVNode: _createVNode } = _Vue const { createVNode: _createVNode } = _Vue
const _hoisted_1 = _createVNode(\\"span\\") const _hoisted_1 = _createVNode(\\"span\\", null, null, -1)
const _hoisted_2 = _createVNode(\\"div\\") const _hoisted_2 = _createVNode(\\"div\\", null, null, -1)
return function render(_ctx, _cache) { return function render(_ctx, _cache) {
with (this) { with (this) {
@ -79,7 +79,7 @@ exports[`compiler: hoistStatic transform hoist simple element 1`] = `
"const _Vue = Vue "const _Vue = Vue
const { createVNode: _createVNode } = _Vue const { createVNode: _createVNode } = _Vue
const _hoisted_1 = _createVNode(\\"span\\", { class: \\"inline\\" }, \\"hello\\") const _hoisted_1 = _createVNode(\\"span\\", { class: \\"inline\\" }, \\"hello\\", -1)
return function render(_ctx, _cache) { return function render(_ctx, _cache) {
with (this) { with (this) {
@ -172,7 +172,7 @@ exports[`compiler: hoistStatic transform prefixIdentifiers hoist nested static t
"const _Vue = Vue "const _Vue = Vue
const { createVNode: _createVNode } = _Vue const { createVNode: _createVNode } = _Vue
const _hoisted_1 = _createVNode(\\"span\\", null, \\"foo \\" + _toDisplayString(1) + \\" \\" + _toDisplayString(true)) const _hoisted_1 = _createVNode(\\"span\\", null, \\"foo \\" + _toDisplayString(1) + \\" \\" + _toDisplayString(true), -1)
return function render(_ctx, _cache) { return function render(_ctx, _cache) {
with (this) { with (this) {
@ -189,7 +189,7 @@ exports[`compiler: hoistStatic transform prefixIdentifiers hoist nested static t
"const _Vue = Vue "const _Vue = Vue
const { createVNode: _createVNode } = _Vue const { createVNode: _createVNode } = _Vue
const _hoisted_1 = _createVNode(\\"span\\", { foo: 0 }, _toDisplayString(1)) const _hoisted_1 = _createVNode(\\"span\\", { foo: 0 }, _toDisplayString(1), -1)
return function render(_ctx, _cache) { return function render(_ctx, _cache) {
with (this) { with (this) {
@ -346,7 +346,7 @@ exports[`compiler: hoistStatic transform should hoist v-for children if static 1
const { createVNode: _createVNode } = _Vue const { createVNode: _createVNode } = _Vue
const _hoisted_1 = { id: \\"foo\\" } const _hoisted_1 = { id: \\"foo\\" }
const _hoisted_2 = _createVNode(\\"span\\") const _hoisted_2 = _createVNode(\\"span\\", null, null, -1)
return function render(_ctx, _cache) { return function render(_ctx, _cache) {
with (this) { with (this) {
@ -371,7 +371,7 @@ const _hoisted_1 = {
key: 0, key: 0,
id: \\"foo\\" id: \\"foo\\"
} }
const _hoisted_2 = _createVNode(\\"span\\") const _hoisted_2 = _createVNode(\\"span\\", null, null, -1)
return function render(_ctx, _cache) { return function render(_ctx, _cache) {
with (this) { with (this) {

View File

@ -52,6 +52,7 @@ function walk(
) { ) {
if (!doNotHoistNode && isStaticNode(child, resultCache)) { if (!doNotHoistNode && isStaticNode(child, resultCache)) {
// whole tree is static // whole tree is static
;(child.codegenNode as VNodeCall).patchFlag = PatchFlags.HOISTED + ``
const hoisted = context.transformHoist const hoisted = context.transformHoist
? context.transformHoist(child, context) ? context.transformHoist(child, context)
: child.codegenNode! : child.codegenNode!

View File

@ -411,8 +411,12 @@ export function createRenderer<
optimized: boolean optimized: boolean
) { ) {
let el: HostElement let el: HostElement
const { type, props, shapeFlag, transition, scopeId } = vnode const { type, props, shapeFlag, transition, scopeId, patchFlag } = vnode
if (vnode.el != null && hostCloneNode !== undefined) { if (
vnode.el !== null &&
hostCloneNode !== undefined &&
patchFlag === PatchFlags.HOISTED
) {
// If a vnode has non-null el, it means it's being reused. // If a vnode has non-null el, it means it's being reused.
// Only static vnodes can be reused, so its mounted DOM nodes should be // Only static vnodes can be reused, so its mounted DOM nodes should be
// exactly the same, and we can simply do a clone here. // exactly the same, and we can simply do a clone here.

View File

@ -61,11 +61,14 @@ export const enum PatchFlags {
// Components with this flag are always force updated. // Components with this flag are always force updated.
DYNAMIC_SLOTS = 1 << 9, DYNAMIC_SLOTS = 1 << 9,
// A special flag that indicates a hoisted, static vnode.
HOISTED = -1,
// A special flag that indicates that the diffing algorithm should bail out // A special flag that indicates that the diffing algorithm should bail out
// of optimized mode. This is only on block fragments created by renderSlot() // of optimized mode. This is only on block fragments created by renderSlot()
// when encountering non-compiler generated slots (i.e. manually written // when encountering non-compiler generated slots (i.e. manually written
// render functions, which should always be fully diffed) // render functions, which should always be fully diffed)
BAIL = -1 BAIL = -2
} }
// runtime object for public consumption // runtime object for public consumption