1
+ "use strict" ;
2
+
3
+ /* eslint-env browser */
4
+
5
+ /*
6
+ eslint-disable
7
+ no-console,
8
+ func-names
9
+ */
10
+ var normalizeUrl = require ( 'normalize-url' ) ;
11
+
12
+ var srcByModuleId = Object . create ( null ) ;
13
+ var noDocument = typeof document === 'undefined' ;
14
+ var forEach = Array . prototype . forEach ;
15
+
16
+ function debounce ( fn , time ) {
17
+ var timeout = 0 ;
18
+ return function ( ) {
19
+ var self = this ; // eslint-disable-next-line prefer-rest-params
20
+
21
+ var args = arguments ;
22
+
23
+ var functionCall = function functionCall ( ) {
24
+ return fn . apply ( self , args ) ;
25
+ } ;
26
+
27
+ clearTimeout ( timeout ) ;
28
+ timeout = setTimeout ( functionCall , time ) ;
29
+ } ;
30
+ }
31
+
32
+ function noop ( ) { }
33
+
34
+ function getCurrentScriptUrl ( moduleId ) {
35
+ var src = srcByModuleId [ moduleId ] ;
36
+
37
+ if ( ! src ) {
38
+ if ( document . currentScript ) {
39
+ src = document . currentScript . src ;
40
+ } else {
41
+ var scripts = document . getElementsByTagName ( 'script' ) ;
42
+ var lastScriptTag = scripts [ scripts . length - 1 ] ;
43
+
44
+ if ( lastScriptTag ) {
45
+ src = lastScriptTag . src ;
46
+ }
47
+ }
48
+
49
+ srcByModuleId [ moduleId ] = src ;
50
+ }
51
+
52
+ return function ( fileMap ) {
53
+ if ( ! src ) {
54
+ return null ;
55
+ }
56
+
57
+ var splitResult = src . split ( / ( [ ^ \\ / ] + ) \. j s $ / ) ;
58
+ var filename = splitResult && splitResult [ 1 ] ;
59
+
60
+ if ( ! filename ) {
61
+ return [ src . replace ( '.js' , '.css' ) ] ;
62
+ }
63
+
64
+ if ( ! fileMap ) {
65
+ return [ src . replace ( '.js' , '.css' ) ] ;
66
+ }
67
+
68
+ return fileMap . split ( ',' ) . map ( function ( mapRule ) {
69
+ var reg = new RegExp ( "" . concat ( filename , "\\.js$" ) , 'g' ) ;
70
+ return normalizeUrl ( src . replace ( reg , "" . concat ( mapRule . replace ( / { f i l e N a m e } / g, filename ) , ".css" ) ) , {
71
+ stripWWW : false
72
+ } ) ;
73
+ } ) ;
74
+ } ;
75
+ }
76
+
77
+ function updateCss ( el , url ) {
78
+ if ( ! url ) {
79
+ if ( ! el . href ) {
80
+ return ;
81
+ } // eslint-disable-next-line
82
+
83
+
84
+ url = el . href . split ( '?' ) [ 0 ] ;
85
+ }
86
+
87
+ if ( ! isUrlRequest ( url ) ) {
88
+ return ;
89
+ }
90
+
91
+ if ( el . isLoaded === false ) {
92
+ // We seem to be about to replace a css link that hasn't loaded yet.
93
+ // We're probably changing the same file more than once.
94
+ return ;
95
+ }
96
+
97
+ if ( ! url || ! ( url . indexOf ( '.css' ) > - 1 ) ) {
98
+ return ;
99
+ } // eslint-disable-next-line no-param-reassign
100
+
101
+
102
+ el . visited = true ;
103
+ var newEl = el . cloneNode ( ) ;
104
+ newEl . isLoaded = false ;
105
+ newEl . addEventListener ( 'load' , function ( ) {
106
+ newEl . isLoaded = true ;
107
+ el . parentNode . removeChild ( el ) ;
108
+ } ) ;
109
+ newEl . addEventListener ( 'error' , function ( ) {
110
+ newEl . isLoaded = true ;
111
+ el . parentNode . removeChild ( el ) ;
112
+ } ) ;
113
+ newEl . href = "" . concat ( url , "?" ) . concat ( Date . now ( ) ) ;
114
+
115
+ if ( el . nextSibling ) {
116
+ el . parentNode . insertBefore ( newEl , el . nextSibling ) ;
117
+ } else {
118
+ el . parentNode . appendChild ( newEl ) ;
119
+ }
120
+ }
121
+
122
+ function getReloadUrl ( href , src ) {
123
+ var ret ; // eslint-disable-next-line no-param-reassign
124
+
125
+ href = normalizeUrl ( href , {
126
+ stripWWW : false
127
+ } ) ; // eslint-disable-next-line array-callback-return
128
+
129
+ src . some ( function ( url ) {
130
+ if ( href . indexOf ( src ) > - 1 ) {
131
+ ret = url ;
132
+ }
133
+ } ) ;
134
+ return ret ;
135
+ }
136
+
137
+ function reloadStyle ( src ) {
138
+ var elements = document . querySelectorAll ( 'link' ) ;
139
+ var loaded = false ;
140
+ forEach . call ( elements , function ( el ) {
141
+ if ( ! el . href ) {
142
+ return ;
143
+ }
144
+
145
+ var url = getReloadUrl ( el . href , src ) ;
146
+
147
+ if ( ! isUrlRequest ( url ) ) {
148
+ return ;
149
+ }
150
+
151
+ if ( el . visited === true ) {
152
+ return ;
153
+ }
154
+
155
+ if ( url ) {
156
+ updateCss ( el , url ) ;
157
+ loaded = true ;
158
+ }
159
+ } ) ;
160
+ return loaded ;
161
+ }
162
+
163
+ function reloadAll ( ) {
164
+ var elements = document . querySelectorAll ( 'link' ) ;
165
+ forEach . call ( elements , function ( el ) {
166
+ if ( el . visited === true ) {
167
+ return ;
168
+ }
169
+
170
+ updateCss ( el ) ;
171
+ } ) ;
172
+ }
173
+
174
+ function isUrlRequest ( url ) {
175
+ // An URL is not an request if
176
+ // It is not http or https
177
+ if ( ! / ^ h t t p s ? : / i. test ( url ) ) {
178
+ return false ;
179
+ }
180
+
181
+ return true ;
182
+ }
183
+
184
+ module . exports = function ( moduleId , options ) {
185
+ if ( noDocument ) {
186
+ console . log ( 'no window.document found, will not HMR CSS' ) ;
187
+ return noop ;
188
+ }
189
+
190
+ var getScriptSrc = getCurrentScriptUrl ( moduleId ) ;
191
+
192
+ function update ( ) {
193
+ var src = getScriptSrc ( options . filename ) ;
194
+ var reloaded = reloadStyle ( src ) ;
195
+
196
+ if ( options . locals ) {
197
+ console . log ( '[HMR] Detected local css modules. Reload all css' ) ;
198
+ reloadAll ( ) ;
199
+ return ;
200
+ }
201
+
202
+ if ( reloaded && ! options . reloadAll ) {
203
+ console . log ( '[HMR] css reload %s' , src . join ( ' ' ) ) ;
204
+ } else {
205
+ console . log ( '[HMR] Reload all css' ) ;
206
+ reloadAll ( ) ;
207
+ }
208
+ }
209
+
210
+ return debounce ( update , 50 ) ;
211
+ } ;
0 commit comments