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