Skip to content

Commit 01b7e90

Browse files
committed
fix(hmr): handle cases where instances with same id having different definitions
1 parent 0c48558 commit 01b7e90

File tree

1 file changed

+25
-28
lines changed
  • packages/runtime-core/src

1 file changed

+25
-28
lines changed

packages/runtime-core/src/hmr.ts

+25-28
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,7 @@ if (__DEV__) {
3333
} as HMRRuntime
3434
}
3535

36-
interface HMRRecord {
37-
comp: ComponentOptions
38-
instances: Set<ComponentInternalInstance>
39-
}
36+
type HMRRecord = Set<ComponentInternalInstance>
4037

4138
const map: Map<string, HMRRecord> = new Map()
4239

@@ -47,21 +44,18 @@ export function registerHMR(instance: ComponentInternalInstance) {
4744
createRecord(id, instance.type as ComponentOptions)
4845
record = map.get(id)!
4946
}
50-
record.instances.add(instance)
47+
record.add(instance)
5148
}
5249

5350
export function unregisterHMR(instance: ComponentInternalInstance) {
54-
map.get(instance.type.__hmrId!)!.instances.delete(instance)
51+
map.get(instance.type.__hmrId!)!.delete(instance)
5552
}
5653

5754
function createRecord(id: string, comp: ComponentOptions): boolean {
5855
if (map.has(id)) {
5956
return false
6057
}
61-
map.set(id, {
62-
comp,
63-
instances: new Set()
64-
})
58+
map.set(id, new Set())
6559
return true
6660
}
6761

@@ -70,7 +64,7 @@ function rerender(id: string, newRender?: Function) {
7064
if (!record) return
7165
// Array.from creates a snapshot which avoids the set being mutated during
7266
// updates
73-
Array.from(record.instances).forEach(instance => {
67+
Array.from(record).forEach(instance => {
7468
if (newRender) {
7569
instance.render = newRender as InternalRenderFunction
7670
}
@@ -85,22 +79,29 @@ function rerender(id: string, newRender?: Function) {
8579
function reload(id: string, newComp: ComponentOptions) {
8680
const record = map.get(id)
8781
if (!record) return
88-
// 1. Update existing comp definition to match new one
89-
const comp = record.comp
90-
Object.assign(comp, newComp)
91-
for (const key in comp) {
92-
if (!(key in newComp)) {
93-
delete (comp as any)[key]
94-
}
95-
}
96-
// 2. Mark component dirty. This forces the renderer to replace the component
97-
// on patch.
98-
comp.__hmrUpdated = true
9982
// Array.from creates a snapshot which avoids the set being mutated during
10083
// updates
101-
Array.from(record.instances).forEach(instance => {
84+
Array.from(record).forEach(instance => {
85+
const comp = instance.type
86+
if (!comp.__hmrUpdated) {
87+
// 1. Update existing comp definition to match new one
88+
Object.assign(comp, newComp)
89+
for (const key in comp) {
90+
if (!(key in newComp)) {
91+
delete (comp as any)[key]
92+
}
93+
}
94+
// 2. Mark component dirty. This forces the renderer to replace the component
95+
// on patch.
96+
comp.__hmrUpdated = true
97+
// 3. Make sure to unmark the component after the reload.
98+
queuePostFlushCb(() => {
99+
comp.__hmrUpdated = false
100+
})
101+
}
102+
102103
if (instance.parent) {
103-
// 3. Force the parent instance to re-render. This will cause all updated
104+
// 4. Force the parent instance to re-render. This will cause all updated
104105
// components to be unmounted and re-mounted. Queue the update so that we
105106
// don't end up forcing the same parent to re-render multiple times.
106107
queueJob(instance.parent.update)
@@ -116,10 +117,6 @@ function reload(id: string, newComp: ComponentOptions) {
116117
)
117118
}
118119
})
119-
// 4. Make sure to unmark the component after the reload.
120-
queuePostFlushCb(() => {
121-
comp.__hmrUpdated = false
122-
})
123120
}
124121

125122
function tryWrap(fn: (id: string, arg: any) => any): Function {

0 commit comments

Comments
 (0)