@@ -20,6 +20,7 @@ const DEFAULT_LOADER = require.resolve('../lib/loader.js') + '?force';
2020const DEFAULT_TEMPLATE = DEFAULT_LOADER + '!' + require . resolve ( '../default_index.ejs' ) ;
2121
2222jest . setTimeout ( 30000 ) ;
23+
2324process . on ( 'unhandledRejection' , r => console . log ( r ) ) ;
2425
2526describe ( 'HtmlWebpackPluginHMR' , ( ) => {
@@ -85,4 +86,140 @@ describe('HtmlWebpackPluginHMR', () => {
8586 } )
8687 . then ( ( ) => compiler . stopWatching ( ) ) ;
8788 } ) ;
89+
90+ it ( 'should re-emit favicon and assets from a loader if watch is active' , ( ) => {
91+ const template = path . join ( __dirname , './fixtures/html-template-with-image.html' ) ;
92+ const config = {
93+ mode : 'development' ,
94+ entry : path . join ( __dirname , 'fixtures/index.js' ) ,
95+ output : {
96+ assetModuleFilename : '[name][ext]' ,
97+ path : OUTPUT_DIR
98+ } ,
99+ module : {
100+ rules : [
101+ {
102+ test : / \. h t m l $ / ,
103+ loader : 'html-loader'
104+ }
105+ ]
106+ } ,
107+ plugins : [
108+ new HtmlWebpackPlugin ( {
109+ favicon : path . join ( __dirname , './fixtures/favicon.ico' ) ,
110+ template
111+ } )
112+ ]
113+ } ;
114+
115+ const templateContent = fs . readFileSync ( template , 'utf-8' ) ;
116+ const compiler = new WebpackRecompilationSimulator ( webpack ( config ) ) ;
117+ const jsFileTempPath = compiler . addTestFile ( path . join ( __dirname , 'fixtures/index.js' ) ) ;
118+ const expected = [ 'logo.png' , 'main.js' , 'favicon.ico' , 'index.html' ] ;
119+
120+ return compiler . startWatching ( )
121+ // Change the template file and compile again
122+ . then ( ( stats ) => {
123+ expect ( expected . every ( val => Object . keys ( stats . compilation . assets ) . includes ( val ) ) ) . toBe ( true ) ;
124+ expect ( stats . compilation . errors ) . toEqual ( [ ] ) ;
125+ expect ( stats . compilation . warnings ) . toEqual ( [ ] ) ;
126+
127+ fs . writeFileSync ( jsFileTempPath , 'module.exports = function calc(a, b){ return a - b };' ) ;
128+
129+ return compiler . waitForWatchRunComplete ( ) ;
130+ } )
131+ . then ( stats => {
132+ expect ( expected . every ( val => Object . keys ( stats . compilation . assets ) . includes ( val ) ) ) . toBe ( true ) ;
133+ expect ( stats . compilation . errors ) . toEqual ( [ ] ) ;
134+ expect ( stats . compilation . warnings ) . toEqual ( [ ] ) ;
135+
136+ fs . writeFileSync ( template , templateContent . replace ( / S o m e u n i q u e t e x t / , 'Some other unique text' ) ) ;
137+
138+ return compiler . waitForWatchRunComplete ( ) ;
139+ } )
140+ . then ( ( stats ) => {
141+ expect ( expected . every ( val => Object . keys ( stats . compilation . assets ) . includes ( val ) ) ) . toBe ( true ) ;
142+ expect ( stats . compilation . errors ) . toEqual ( [ ] ) ;
143+ expect ( stats . compilation . warnings ) . toEqual ( [ ] ) ;
144+
145+ fs . writeFileSync ( template , templateContent ) ;
146+ } )
147+ . then ( ( ) => compiler . stopWatching ( ) ) ;
148+ } ) ;
149+
150+ it ( 'should re-emit favicon and assets from a loader if watch is active and clean enabled' , ( ) => {
151+ const expected = [ 'logo.png' , 'main.js' , 'favicon.ico' , 'index.html' ] ;
152+
153+ class MyPlugin {
154+ apply ( compiler ) {
155+ compiler . hooks . thisCompilation . tap ( { name : this . constructor . name } , ( compilation ) => {
156+ return compilation . hooks . processAssets . tap (
157+ { name : this . constructor . name , stage : webpack . Compilation . PROCESS_ASSETS_STAGE_ANALYSE } ,
158+ ( assets ) => {
159+ expect ( expected . every ( val => Object . keys ( assets ) . includes ( val ) ) ) . toBe ( true ) ;
160+ }
161+ ) ;
162+ } ) ;
163+ }
164+ }
165+
166+ const template = path . join ( __dirname , './fixtures/html-template-with-image.html' ) ;
167+ const config = {
168+ mode : 'development' ,
169+ entry : path . join ( __dirname , 'fixtures/index.js' ) ,
170+ output : {
171+ clean : true ,
172+ assetModuleFilename : '[name][ext]' ,
173+ path : OUTPUT_DIR
174+ } ,
175+ module : {
176+ rules : [
177+ {
178+ test : / \. h t m l $ / ,
179+ loader : 'html-loader'
180+ }
181+ ]
182+ } ,
183+ plugins : [
184+ new HtmlWebpackPlugin ( {
185+ favicon : path . join ( __dirname , './fixtures/favicon.ico' ) ,
186+ template
187+ } ) ,
188+ new MyPlugin ( )
189+ ]
190+ } ;
191+
192+ const templateContent = fs . readFileSync ( template , 'utf-8' ) ;
193+ const compiler = new WebpackRecompilationSimulator ( webpack ( config ) ) ;
194+ const jsFileTempPath = compiler . addTestFile ( path . join ( __dirname , 'fixtures/index.js' ) ) ;
195+
196+ return compiler . startWatching ( )
197+ // Change the template file and compile again
198+ . then ( ( stats ) => {
199+ expect ( expected . every ( val => Object . keys ( stats . compilation . assets ) . includes ( val ) ) ) . toBe ( true ) ;
200+ expect ( stats . compilation . errors ) . toEqual ( [ ] ) ;
201+ expect ( stats . compilation . warnings ) . toEqual ( [ ] ) ;
202+
203+ fs . writeFileSync ( jsFileTempPath , 'module.exports = function calc(a, b){ return a - b };' ) ;
204+
205+ return compiler . waitForWatchRunComplete ( ) ;
206+ } )
207+ . then ( stats => {
208+ expect ( expected . every ( val => Object . keys ( stats . compilation . assets ) . includes ( val ) ) ) . toBe ( true ) ;
209+ expect ( stats . compilation . errors ) . toEqual ( [ ] ) ;
210+ expect ( stats . compilation . warnings ) . toEqual ( [ ] ) ;
211+
212+ fs . writeFileSync ( template , templateContent . replace ( / S o m e u n i q u e t e x t / , 'Some other unique text' ) ) ;
213+
214+ return compiler . waitForWatchRunComplete ( ) ;
215+ } )
216+ . then ( ( stats ) => {
217+ expect ( expected . every ( val => Object . keys ( stats . compilation . assets ) . includes ( val ) ) ) . toBe ( true ) ;
218+ expect ( stats . compilation . errors ) . toEqual ( [ ] ) ;
219+ expect ( stats . compilation . warnings ) . toEqual ( [ ] ) ;
220+
221+ fs . writeFileSync ( template , templateContent ) ;
222+ } )
223+ . then ( ( ) => compiler . stopWatching ( ) ) ;
224+ } ) ;
88225} ) ;
0 commit comments