Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ebea034

Browse files
committed
fix(hmr): avoid infinite recursion when reloading hmr components (#6930)
1 parent b0b74a1 commit ebea034

File tree

2 files changed

+56
-2
lines changed

2 files changed

+56
-2
lines changed

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

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import {
88
serializeInner,
99
triggerEvent,
1010
TestElement,
11-
nextTick
11+
nextTick,
12+
ref
1213
} from '@vue/runtime-test'
1314
import * as runtimeTest from '@vue/runtime-test'
1415
import { registerRuntimeCompiler, createApp } from '@vue/runtime-test'
@@ -194,6 +195,53 @@ describe('hot module replacement', () => {
194195
expect(mountSpy).toHaveBeenCalledTimes(1)
195196
})
196197

198+
// #6930
199+
test('reload: avoid infinite recursion', async () => {
200+
const root = nodeOps.createElement('div')
201+
const childId = 'test-child-6930'
202+
const unmountSpy = jest.fn()
203+
const mountSpy = jest.fn()
204+
205+
const Child: ComponentOptions = {
206+
__hmrId: childId,
207+
data() {
208+
return { count: 0 }
209+
},
210+
expose: ['count'],
211+
unmounted: unmountSpy,
212+
render: compileToFunction(`<div @click="count++">{{ count }}</div>`)
213+
}
214+
createRecord(childId, Child)
215+
216+
const Parent: ComponentOptions = {
217+
setup() {
218+
const com = ref()
219+
const changeRef = (value: any) => {
220+
com.value = value
221+
}
222+
223+
return () => [h(Child, { ref: changeRef }), com.value?.count]
224+
}
225+
}
226+
227+
render(h(Parent), root)
228+
await nextTick()
229+
expect(serializeInner(root)).toBe(`<div>0</div>0`)
230+
231+
reload(childId, {
232+
__hmrId: childId,
233+
data() {
234+
return { count: 1 }
235+
},
236+
mounted: mountSpy,
237+
render: compileToFunction(`<div @click="count++">{{ count }}</div>`)
238+
})
239+
await nextTick()
240+
expect(serializeInner(root)).toBe(`<div>1</div>1`)
241+
expect(unmountSpy).toHaveBeenCalledTimes(1)
242+
expect(mountSpy).toHaveBeenCalledTimes(1)
243+
})
244+
197245
// #1156 - static nodes should retain DOM element reference across updates
198246
// when HMR is active
199247
test('static el reference', async () => {

‎packages/runtime-core/src/hmr.ts‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,13 @@ function reload(id: string, newComp: HMRComponent) {
135135
// 4. Force the parent instance to re-render. This will cause all updated
136136
// components to be unmounted and re-mounted. Queue the update so that we
137137
// don't end up forcing the same parent to re-render multiple times.
138-
queueJob(instance.parent.update)
138+
queueJob(() => {
139+
if (instance.parent) {
140+
instance.parent.update()
141+
// #6930 avoid infinite recursion
142+
hmrDirtyComponents.delete(oldComp)
143+
}
144+
})
139145
// instance is the inner component of an async custom element
140146
// invoke to reset styles
141147
if (

0 commit comments

Comments
 (0)