Skip to content

Commit 6c11c4d

Browse files
committed
test: add test
1 parent 7e08418 commit 6c11c4d

File tree

2 files changed

+65
-7
lines changed

2 files changed

+65
-7
lines changed

packages/runtime-core/__tests__/hmr.spec.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,4 +1040,57 @@ describe('hot module replacement', () => {
10401040

10411041
expect(serializeInner(root)).toBe('<div>bar</div>')
10421042
})
1043+
1044+
// #14127
1045+
test('update cached text nodes', async () => {
1046+
const root = nodeOps.createElement('div')
1047+
const appId = 'test-cached-text-nodes'
1048+
const App: ComponentOptions = {
1049+
__hmrId: appId,
1050+
data() {
1051+
return {
1052+
count: 0,
1053+
}
1054+
},
1055+
render: compileToFunction(
1056+
`{{count}}
1057+
<button @click="count++">++</button>
1058+
static text`,
1059+
),
1060+
}
1061+
createRecord(appId, App)
1062+
render(h(App), root)
1063+
expect(serializeInner(root)).toBe(`0 <button>++</button> static text`)
1064+
1065+
// trigger count update
1066+
triggerEvent((root as any).children[2], 'click')
1067+
await nextTick()
1068+
expect(serializeInner(root)).toBe(`1 <button>++</button> static text`)
1069+
1070+
// trigger HMR update
1071+
rerender(
1072+
appId,
1073+
compileToFunction(
1074+
`{{count}}
1075+
<button @click="count++">++</button>
1076+
static text updated`,
1077+
),
1078+
)
1079+
expect(serializeInner(root)).toBe(
1080+
`1 <button>++</button> static text updated`,
1081+
)
1082+
1083+
// trigger HMR update again
1084+
rerender(
1085+
appId,
1086+
compileToFunction(
1087+
`{{count}}
1088+
<button @click="count++">++</button>
1089+
static text updated2`,
1090+
),
1091+
)
1092+
expect(serializeInner(root)).toBe(
1093+
`1 <button>++</button> static text updated2`,
1094+
)
1095+
})
10431096
})

packages/runtime-core/src/renderer.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -500,20 +500,22 @@ function baseCreateRenderer(
500500
} else {
501501
const el = (n2.el = n1.el!)
502502
if (n2.children !== n1.children) {
503-
// we don't inherit text node for cached text nodes in `traverseStaticChildren`
504-
// but it maybe changed during HMR updates, so we need to handle this case by
505-
// replacing the text node.
503+
// We don't inherit el for cached text nodes in `traverseStaticChildren`
504+
// to avoid retaining detached DOM nodes. However, the text node may be
505+
// changed during HMR. In this case we need to replace the old text node
506+
// with the new one.
506507
if (
507508
__DEV__ &&
508509
isHmrUpdating &&
509510
n2.patchFlag === PatchFlags.CACHED &&
510511
'__elIndex' in n1
511512
) {
513+
const childNodes = __TEST__
514+
? container.children
515+
: container.childNodes
512516
const newChild = hostCreateText(n2.children as string)
513517
const oldChild =
514-
container.childNodes[
515-
((n2 as any).__elIndex = (n1 as any).__elIndex)
516-
]
518+
childNodes[((n2 as any).__elIndex = (n1 as any).__elIndex)]
517519
hostInsert(newChild, container, oldChild)
518520
hostRemove(oldChild)
519521
} else {
@@ -2520,7 +2522,10 @@ export function traverseStaticChildren(
25202522
c2.el = c1.el
25212523
} else {
25222524
// cache the child index for HMR updates
2523-
;(c2 as any).__elIndex = i + (n1.type === Fragment ? 1 : 0)
2525+
;(c2 as any).__elIndex =
2526+
i +
2527+
// take fragment start anchor into account
2528+
(n1.type === Fragment ? 1 : 0)
25242529
}
25252530
}
25262531
// #2324 also inherit for comment nodes, but not placeholders (e.g. v-if which

0 commit comments

Comments
 (0)