diff --git a/packages/runtime-core/__tests__/rendererFragment.spec.ts b/packages/runtime-core/__tests__/rendererFragment.spec.ts index 9e1f87ae..93140f13 100644 --- a/packages/runtime-core/__tests__/rendererFragment.spec.ts +++ b/packages/runtime-core/__tests__/rendererFragment.spec.ts @@ -10,9 +10,13 @@ import { dumpOps, NodeOpTypes, serializeInner, - createTextVNode + createTextVNode, + createBlock, + openBlock, + createCommentVNode } from '@vue/runtime-test' import { PatchFlags } from '@vue/shared' +import { renderList } from '../src/helpers/renderList' describe('renderer: fragment', () => { it('should allow returning multiple component root nodes', () => { @@ -269,4 +273,46 @@ describe('renderer: fragment', () => { render(null, root) expect(serializeInner(root)).toBe(``) }) + + // #2080 + test('`template` keyed fragment w/ comment + hoisted node', () => { + const root = nodeOps.createElement('div') + const hoisted = h('span') + + const renderFn = (items: string[]) => { + return ( + openBlock(true), + createBlock( + Fragment, + null, + renderList(items, item => { + return ( + openBlock(), + createBlock( + Fragment, + { key: item }, + [ + createCommentVNode('comment'), + hoisted, + createVNode('div', null, item, PatchFlags.TEXT) + ], + PatchFlags.STABLE_FRAGMENT + ) + ) + }), + PatchFlags.KEYED_FRAGMENT + ) + ) + } + + render(renderFn(['one', 'two']), root) + expect(serializeInner(root)).toBe( + `
one
two
` + ) + + render(renderFn(['two', 'one']), root) + expect(serializeInner(root)).toBe( + `
two
one
` + ) + }) }) diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index 670cd41f..5246fcb1 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -1153,8 +1153,10 @@ function baseCreateRenderer( parentSuspense, isSVG ) - if (__DEV__ && parentComponent && parentComponent.type.__hmrId) { - traverseStaticChildren(n1, n2) + // #2080 if the stable fragment has a key, it's a