9
9
} from './component'
10
10
import { queueJob , queuePostFlushCb } from './scheduler'
11
11
import { extend } from '@vue/shared'
12
- import { warn } from './warning'
13
12
14
13
export let isHmrUpdating = false
15
14
@@ -43,58 +42,46 @@ if (__DEV__) {
43
42
} as HMRRuntime
44
43
}
45
44
46
- type HMRRecord = {
47
- component : ComponentOptions
48
- instances : Set < ComponentInternalInstance >
49
- }
50
-
51
- const map : Map < string , HMRRecord > = new Map ( )
45
+ const map : Map < string , Set < ComponentInternalInstance > > = new Map ( )
52
46
53
47
export function registerHMR ( instance : ComponentInternalInstance ) {
54
48
const id = instance . type . __hmrId !
55
49
let record = map . get ( id )
56
50
if ( ! record ) {
57
- createRecord ( id , instance . type as ComponentOptions )
51
+ createRecord ( id )
58
52
record = map . get ( id ) !
59
53
}
60
- record . instances . add ( instance )
54
+ record . add ( instance )
61
55
}
62
56
63
57
export function unregisterHMR ( instance : ComponentInternalInstance ) {
64
- map . get ( instance . type . __hmrId ! ) ! . instances . delete ( instance )
58
+ map . get ( instance . type . __hmrId ! ) ! . delete ( instance )
65
59
}
66
60
67
- function createRecord (
68
- id : string ,
69
- component : ComponentOptions | ClassComponent
70
- ) : boolean {
71
- if ( ! component ) {
72
- warn (
73
- `HMR API usage is out of date.\n` +
74
- `Please upgrade vue-loader/vite/rollup-plugin-vue or other relevant ` +
75
- `dependency that handles Vue SFC compilation.`
76
- )
77
- component = { }
78
- }
61
+ function createRecord ( id : string ) : boolean {
79
62
if ( map . has ( id ) ) {
80
63
return false
81
64
}
82
- map . set ( id , {
83
- component : isClassComponent ( component ) ? component . __vccOpts : component ,
84
- instances : new Set ( )
85
- } )
65
+ map . set ( id , new Set ( ) )
86
66
return true
87
67
}
88
68
69
+ type HMRComponent = ComponentOptions | ClassComponent
70
+
71
+ function normalizeClassComponent ( component : HMRComponent ) : ComponentOptions {
72
+ return isClassComponent ( component ) ? component . __vccOpts : component
73
+ }
74
+
89
75
function rerender ( id : string , newRender ?: Function ) {
90
76
const record = map . get ( id )
91
- if ( ! record ) return
92
- if ( newRender ) record . component . render = newRender
93
- // Array.from creates a snapshot which avoids the set being mutated during
94
- // updates
95
- Array . from ( record . instances ) . forEach ( instance => {
77
+ if ( ! record ) {
78
+ return
79
+ }
80
+ // Create a snapshot which avoids the set being mutated during updates
81
+ ; [ ... record ] . forEach ( instance => {
96
82
if ( newRender ) {
97
83
instance . render = newRender as InternalRenderFunction
84
+ normalizeClassComponent ( instance . type as HMRComponent ) . render = newRender
98
85
}
99
86
instance . renderCache = [ ]
100
87
// this flag forces child components with slot content to update
@@ -104,40 +91,40 @@ function rerender(id: string, newRender?: Function) {
104
91
} )
105
92
}
106
93
107
- function reload ( id : string , newComp : ComponentOptions | ClassComponent ) {
94
+ function reload ( id : string , newComp : HMRComponent ) {
108
95
const record = map . get ( id )
109
96
if ( ! record ) return
110
- // Array.from creates a snapshot which avoids the set being mutated during
111
- // updates
112
- const { component, instances } = record
113
-
114
- if ( ! hmrDirtyComponents . has ( component ) ) {
115
- // 1. Update existing comp definition to match new one
116
- newComp = isClassComponent ( newComp ) ? newComp . __vccOpts : newComp
117
- extend ( component , newComp )
118
- for ( const key in component ) {
119
- if ( key !== '__file' && ! ( key in newComp ) ) {
120
- delete ( component as any ) [ key ]
97
+
98
+ newComp = normalizeClassComponent ( newComp )
99
+
100
+ // create a snapshot which avoids the set being mutated during updates
101
+ const instances = [ ...record ]
102
+
103
+ for ( const instance of instances ) {
104
+ const oldComp = normalizeClassComponent ( instance . type as HMRComponent )
105
+
106
+ if ( ! hmrDirtyComponents . has ( oldComp ) ) {
107
+ // 1. Update existing comp definition to match new one
108
+ extend ( oldComp , newComp )
109
+ for ( const key in oldComp ) {
110
+ if ( key !== '__file' && ! ( key in newComp ) ) {
111
+ delete ( oldComp as any ) [ key ]
112
+ }
121
113
}
114
+ // 2. mark definition dirty. This forces the renderer to replace the
115
+ // component on patch.
116
+ hmrDirtyComponents . add ( oldComp )
122
117
}
123
- // 2. Mark component dirty. This forces the renderer to replace the component
124
- // on patch.
125
- hmrDirtyComponents . add ( component )
126
- // 3. Make sure to unmark the component after the reload.
127
- queuePostFlushCb ( ( ) => {
128
- hmrDirtyComponents . delete ( component )
129
- } )
130
- }
131
118
132
- Array . from ( instances ) . forEach ( instance => {
133
- // invalidate options resolution cache
119
+ // 3. invalidate options resolution cache
134
120
instance . appContext . optionsCache . delete ( instance . type as any )
135
121
122
+ // 4. actually update
136
123
if ( instance . ceReload ) {
137
124
// custom element
138
- hmrDirtyComponents . add ( component )
125
+ hmrDirtyComponents . add ( oldComp )
139
126
instance . ceReload ( ( newComp as any ) . styles )
140
- hmrDirtyComponents . delete ( component )
127
+ hmrDirtyComponents . delete ( oldComp )
141
128
} else if ( instance . parent ) {
142
129
// 4. Force the parent instance to re-render. This will cause all updated
143
130
// components to be unmounted and re-mounted. Queue the update so that we
@@ -162,6 +149,15 @@ function reload(id: string, newComp: ComponentOptions | ClassComponent) {
162
149
'[HMR] Root or manually mounted instance modified. Full reload required.'
163
150
)
164
151
}
152
+ }
153
+
154
+ // 5. make sure to cleanup dirty hmr components after update
155
+ queuePostFlushCb ( ( ) => {
156
+ for ( const instance of instances ) {
157
+ hmrDirtyComponents . delete (
158
+ normalizeClassComponent ( instance . type as HMRComponent )
159
+ )
160
+ }
165
161
} )
166
162
}
167
163
0 commit comments