@@ -188,164 +188,175 @@ function hookIntoCompiler (compiler, options, plugin) {
188
188
} ;
189
189
}
190
190
191
- compiler . hooks . emit . tapAsync ( 'HtmlWebpackPlugin' ,
191
+ compiler . hooks . thisCompilation . tap ( 'HtmlWebpackPlugin' ,
192
192
/**
193
- * Hook into the webpack emit phase
193
+ * Hook into the webpack compilation
194
194
* @param {WebpackCompilation } compilation
195
+ */
196
+ ( compilation ) => {
197
+ compilation . hooks . processAssets . tapAsync (
198
+ {
199
+ name : 'HtmlWebpackPlugin' ,
200
+ stage : webpack . Compilation . PROCESS_ASSETS_STAGE_ADDITIONS
201
+ } ,
202
+ /**
203
+ * Hook into the PROCESS_ASSETS_STAGE_ADDITIONS hook
204
+ * @param {WebpackCompilation } compilationAssets
195
205
* @param {(err?: Error) => void } callback
196
206
*/
197
- ( compilation , callback ) => {
198
- // Get all entry point names for this html file
199
- const entryNames = Array . from ( compilation . entrypoints . keys ( ) ) ;
200
- const filteredEntryNames = filterChunks ( entryNames , options . chunks , options . excludeChunks ) ;
201
- const sortedEntryNames = sortEntryChunks ( filteredEntryNames , options . chunksSortMode , compilation ) ;
202
-
203
- const templateResult = options . templateContent
204
- ? { mainCompilationHash : compilation . hash }
205
- : childCompilerPlugin . getCompilationEntryResult ( options . template ) ;
206
-
207
- if ( 'error' in templateResult ) {
208
- compilation . errors . push ( prettyError ( templateResult . error , compiler . context ) . toString ( ) ) ;
209
- }
207
+ ( compilationAssets , callback ) => {
208
+ // Get all entry point names for this html file
209
+ const entryNames = Array . from ( compilation . entrypoints . keys ( ) ) ;
210
+ const filteredEntryNames = filterChunks ( entryNames , options . chunks , options . excludeChunks ) ;
211
+ const sortedEntryNames = sortEntryChunks ( filteredEntryNames , options . chunksSortMode , compilation ) ;
210
212
211
- const compiledEntries = 'compiledEntry' in templateResult ? {
212
- hash : templateResult . compiledEntry . hash ,
213
- chunk : templateResult . compiledEntry . entry
214
- } : {
215
- hash : templateResult . mainCompilationHash
216
- } ;
213
+ const templateResult = options . templateContent
214
+ ? { mainCompilationHash : compilation . hash }
215
+ : childCompilerPlugin . getCompilationEntryResult ( options . template ) ;
217
216
218
- const childCompilationOutputName = compilation . getAssetPath ( options . filename , compiledEntries ) ;
219
-
220
- // If the child compilation was not executed during a previous main compile run
221
- // it is a cached result
222
- const isCompilationCached = templateResult . mainCompilationHash !== compilation . hash ;
217
+ if ( 'error' in templateResult ) {
218
+ compilation . errors . push ( prettyError ( templateResult . error , compiler . context ) . toString ( ) ) ;
219
+ }
223
220
224
- // Turn the entry point names into file paths
225
- const assets = htmlWebpackPluginAssets ( compilation , childCompilationOutputName , sortedEntryNames , options . publicPath ) ;
221
+ const compiledEntries = 'compiledEntry' in templateResult ? {
222
+ hash : templateResult . compiledEntry . hash ,
223
+ chunk : templateResult . compiledEntry . entry
224
+ } : {
225
+ hash : templateResult . mainCompilationHash
226
+ } ;
226
227
227
- // If the template and the assets did not change we don't have to emit the html
228
- const newAssetJson = JSON . stringify ( getAssetFiles ( assets ) ) ;
229
- if ( isCompilationCached && options . cache && assetJson === newAssetJson ) {
230
- return callback ( ) ;
231
- } else {
232
- assetJson = newAssetJson ;
233
- }
228
+ const childCompilationOutputName = compilation . getAssetPath ( options . filename , compiledEntries ) ;
234
229
235
- // The html-webpack plugin uses a object representation for the html-tags which will be injected
236
- // to allow altering them more easily
237
- // Just before they are converted a third-party-plugin author might change the order and content
238
- const assetsPromise = getFaviconPublicPath ( options . favicon , compilation , assets . publicPath )
239
- . then ( ( faviconPath ) => {
240
- assets . favicon = faviconPath ;
241
- return getHtmlWebpackPluginHooks ( compilation ) . beforeAssetTagGeneration . promise ( {
242
- assets : assets ,
243
- outputName : childCompilationOutputName ,
244
- plugin : plugin
245
- } ) ;
246
- } ) ;
230
+ // If the child compilation was not executed during a previous main compile run
231
+ // it is a cached result
232
+ const isCompilationCached = templateResult . mainCompilationHash !== compilation . hash ;
247
233
248
- // Turn the js and css paths into grouped HtmlTagObjects
249
- const assetTagGroupsPromise = assetsPromise
250
- // And allow third-party-plugin authors to reorder and change the assetTags before they are grouped
251
- . then ( ( { assets } ) => getHtmlWebpackPluginHooks ( compilation ) . alterAssetTags . promise ( {
252
- assetTags : {
253
- scripts : generatedScriptTags ( assets . js ) ,
254
- styles : generateStyleTags ( assets . css ) ,
255
- meta : [
256
- ...generateBaseTag ( options . base ) ,
257
- ...generatedMetaTags ( options . meta ) ,
258
- ...generateFaviconTags ( assets . favicon )
259
- ]
260
- } ,
261
- outputName : childCompilationOutputName ,
262
- plugin : plugin
263
- } ) )
264
- . then ( ( { assetTags } ) => {
265
- // Inject scripts to body unless it set explicitly to head
266
- const scriptTarget = options . inject === 'head' ||
267
- ( options . inject === false && options . scriptLoading !== 'blocking' ) ? 'head' : 'body' ;
268
- // Group assets to `head` and `body` tag arrays
269
- const assetGroups = generateAssetGroups ( assetTags , scriptTarget ) ;
270
- // Allow third-party-plugin authors to reorder and change the assetTags once they are grouped
271
- return getHtmlWebpackPluginHooks ( compilation ) . alterAssetTagGroups . promise ( {
272
- headTags : assetGroups . headTags ,
273
- bodyTags : assetGroups . bodyTags ,
274
- outputName : childCompilationOutputName ,
275
- plugin : plugin
276
- } ) ;
277
- } ) ;
234
+ // Turn the entry point names into file paths
235
+ const assets = htmlWebpackPluginAssets ( compilation , childCompilationOutputName , sortedEntryNames , options . publicPath ) ;
278
236
279
- // Turn the compiled template into a nodejs function or into a nodejs string
280
- const templateEvaluationPromise = Promise . resolve ( )
281
- . then ( ( ) => {
282
- if ( 'error' in templateResult ) {
283
- return options . showErrors ? prettyError ( templateResult . error , compiler . context ) . toHtml ( ) : 'ERROR' ;
284
- }
285
- // Allow to use a custom function / string instead
286
- if ( options . templateContent !== false ) {
287
- return options . templateContent ;
237
+ // If the template and the assets did not change we don't have to emit the html
238
+ const newAssetJson = JSON . stringify ( getAssetFiles ( assets ) ) ;
239
+ if ( isCompilationCached && options . cache && assetJson === newAssetJson ) {
240
+ return callback ( ) ;
241
+ } else {
242
+ assetJson = newAssetJson ;
288
243
}
289
- // Once everything is compiled evaluate the html factory
290
- // and replace it with its content
291
- return ( 'compiledEntry' in templateResult )
292
- ? plugin . evaluateCompilationResult ( templateResult . compiledEntry . content , options . template )
293
- : Promise . reject ( new Error ( 'Child compilation contained no compiledEntry' ) ) ;
294
- } ) ;
295
-
296
- const templateExectutionPromise = Promise . all ( [ assetsPromise , assetTagGroupsPromise , templateEvaluationPromise ] )
297
- // Execute the template
298
- . then ( ( [ assetsHookResult , assetTags , compilationResult ] ) => typeof compilationResult !== 'function'
299
- ? compilationResult
300
- : executeTemplate ( compilationResult , assetsHookResult . assets , { headTags : assetTags . headTags , bodyTags : assetTags . bodyTags } , compilation ) ) ;
301
-
302
- const injectedHtmlPromise = Promise . all ( [ assetTagGroupsPromise , templateExectutionPromise ] )
303
- // Allow plugins to change the html before assets are injected
304
- . then ( ( [ assetTags , html ] ) => {
305
- const pluginArgs = { html, headTags : assetTags . headTags , bodyTags : assetTags . bodyTags , plugin : plugin , outputName : childCompilationOutputName } ;
306
- return getHtmlWebpackPluginHooks ( compilation ) . afterTemplateExecution . promise ( pluginArgs ) ;
307
- } )
308
- . then ( ( { html, headTags, bodyTags } ) => {
309
- return postProcessHtml ( html , assets , { headTags, bodyTags } ) ;
310
- } ) ;
311
244
312
- const emitHtmlPromise = injectedHtmlPromise
313
- // Allow plugins to change the html after assets are injected
314
- . then ( ( html ) => {
315
- const pluginArgs = { html, plugin : plugin , outputName : childCompilationOutputName } ;
316
- return getHtmlWebpackPluginHooks ( compilation ) . beforeEmit . promise ( pluginArgs )
317
- . then ( result => result . html ) ;
318
- } )
319
- . catch ( err => {
320
- // In case anything went wrong the promise is resolved
321
- // with the error message and an error is logged
322
- compilation . errors . push ( prettyError ( err , compiler . context ) . toString ( ) ) ;
323
- return options . showErrors ? prettyError ( err , compiler . context ) . toHtml ( ) : 'ERROR' ;
324
- } )
325
- . then ( html => {
326
- // Allow to use [templatehash] as placeholder for the html-webpack-plugin name
327
- // See also https://survivejs.com/webpack/optimizing/adding-hashes-to-filenames/
328
- // From https://github.com/webpack-contrib/extract-text-webpack-plugin/blob/8de6558e33487e7606e7cd7cb2adc2cccafef272/src/index.js#L212-L214
329
- const finalOutputName = childCompilationOutputName . replace ( / \[ (?: ( \w + ) : ) ? t e m p l a t e h a s h (?: : ( [ a - z ] + \d * ) ) ? (?: : ( \d + ) ) ? \] / ig, ( _ , hashType , digestType , maxLength ) => {
330
- return loaderUtils . getHashDigest ( Buffer . from ( html , 'utf8' ) , hashType , digestType , parseInt ( maxLength , 10 ) ) ;
245
+ // The html-webpack plugin uses a object representation for the html-tags which will be injected
246
+ // to allow altering them more easily
247
+ // Just before they are converted a third-party-plugin author might change the order and content
248
+ const assetsPromise = getFaviconPublicPath ( options . favicon , compilation , assets . publicPath )
249
+ . then ( ( faviconPath ) => {
250
+ assets . favicon = faviconPath ;
251
+ return getHtmlWebpackPluginHooks ( compilation ) . beforeAssetTagGeneration . promise ( {
252
+ assets : assets ,
253
+ outputName : childCompilationOutputName ,
254
+ plugin : plugin
255
+ } ) ;
256
+ } ) ;
257
+
258
+ // Turn the js and css paths into grouped HtmlTagObjects
259
+ const assetTagGroupsPromise = assetsPromise
260
+ // And allow third-party-plugin authors to reorder and change the assetTags before they are grouped
261
+ . then ( ( { assets } ) => getHtmlWebpackPluginHooks ( compilation ) . alterAssetTags . promise ( {
262
+ assetTags : {
263
+ scripts : generatedScriptTags ( assets . js ) ,
264
+ styles : generateStyleTags ( assets . css ) ,
265
+ meta : [
266
+ ...generateBaseTag ( options . base ) ,
267
+ ...generatedMetaTags ( options . meta ) ,
268
+ ...generateFaviconTags ( assets . favicon )
269
+ ]
270
+ } ,
271
+ outputName : childCompilationOutputName ,
272
+ plugin : plugin
273
+ } ) )
274
+ . then ( ( { assetTags } ) => {
275
+ // Inject scripts to body unless it set explicitly to head
276
+ const scriptTarget = options . inject === 'head' ||
277
+ ( options . inject === false && options . scriptLoading !== 'blocking' ) ? 'head' : 'body' ;
278
+ // Group assets to `head` and `body` tag arrays
279
+ const assetGroups = generateAssetGroups ( assetTags , scriptTarget ) ;
280
+ // Allow third-party-plugin authors to reorder and change the assetTags once they are grouped
281
+ return getHtmlWebpackPluginHooks ( compilation ) . alterAssetTagGroups . promise ( {
282
+ headTags : assetGroups . headTags ,
283
+ bodyTags : assetGroups . bodyTags ,
284
+ outputName : childCompilationOutputName ,
285
+ plugin : plugin
286
+ } ) ;
287
+ } ) ;
288
+
289
+ // Turn the compiled template into a nodejs function or into a nodejs string
290
+ const templateEvaluationPromise = Promise . resolve ( )
291
+ . then ( ( ) => {
292
+ if ( 'error' in templateResult ) {
293
+ return options . showErrors ? prettyError ( templateResult . error , compiler . context ) . toHtml ( ) : 'ERROR' ;
294
+ }
295
+ // Allow to use a custom function / string instead
296
+ if ( options . templateContent !== false ) {
297
+ return options . templateContent ;
298
+ }
299
+ // Once everything is compiled evaluate the html factory
300
+ // and replace it with its content
301
+ return ( 'compiledEntry' in templateResult )
302
+ ? plugin . evaluateCompilationResult ( templateResult . compiledEntry . content , options . template )
303
+ : Promise . reject ( new Error ( 'Child compilation contained no compiledEntry' ) ) ;
304
+ } ) ;
305
+
306
+ const templateExectutionPromise = Promise . all ( [ assetsPromise , assetTagGroupsPromise , templateEvaluationPromise ] )
307
+ // Execute the template
308
+ . then ( ( [ assetsHookResult , assetTags , compilationResult ] ) => typeof compilationResult !== 'function'
309
+ ? compilationResult
310
+ : executeTemplate ( compilationResult , assetsHookResult . assets , { headTags : assetTags . headTags , bodyTags : assetTags . bodyTags } , compilation ) ) ;
311
+
312
+ const injectedHtmlPromise = Promise . all ( [ assetTagGroupsPromise , templateExectutionPromise ] )
313
+ // Allow plugins to change the html before assets are injected
314
+ . then ( ( [ assetTags , html ] ) => {
315
+ const pluginArgs = { html, headTags : assetTags . headTags , bodyTags : assetTags . bodyTags , plugin : plugin , outputName : childCompilationOutputName } ;
316
+ return getHtmlWebpackPluginHooks ( compilation ) . afterTemplateExecution . promise ( pluginArgs ) ;
317
+ } )
318
+ . then ( ( { html, headTags, bodyTags } ) => {
319
+ return postProcessHtml ( html , assets , { headTags, bodyTags } ) ;
320
+ } ) ;
321
+
322
+ const emitHtmlPromise = injectedHtmlPromise
323
+ // Allow plugins to change the html after assets are injected
324
+ . then ( ( html ) => {
325
+ const pluginArgs = { html, plugin : plugin , outputName : childCompilationOutputName } ;
326
+ return getHtmlWebpackPluginHooks ( compilation ) . beforeEmit . promise ( pluginArgs )
327
+ . then ( result => result . html ) ;
328
+ } )
329
+ . catch ( err => {
330
+ // In case anything went wrong the promise is resolved
331
+ // with the error message and an error is logged
332
+ compilation . errors . push ( prettyError ( err , compiler . context ) . toString ( ) ) ;
333
+ return options . showErrors ? prettyError ( err , compiler . context ) . toHtml ( ) : 'ERROR' ;
334
+ } )
335
+ . then ( html => {
336
+ // Allow to use [templatehash] as placeholder for the html-webpack-plugin name
337
+ // See also https://survivejs.com/webpack/optimizing/adding-hashes-to-filenames/
338
+ // From https://github.com/webpack-contrib/extract-text-webpack-plugin/blob/8de6558e33487e7606e7cd7cb2adc2cccafef272/src/index.js#L212-L214
339
+ const finalOutputName = childCompilationOutputName . replace ( / \[ (?: ( \w + ) : ) ? t e m p l a t e h a s h (?: : ( [ a - z ] + \d * ) ) ? (?: : ( \d + ) ) ? \] / ig, ( _ , hashType , digestType , maxLength ) => {
340
+ return loaderUtils . getHashDigest ( Buffer . from ( html , 'utf8' ) , hashType , digestType , parseInt ( maxLength , 10 ) ) ;
341
+ } ) ;
342
+ // Add the evaluated html code to the webpack assets
343
+ compilation . emitAsset ( finalOutputName , new webpack . sources . RawSource ( html , false ) ) ;
344
+ return finalOutputName ;
345
+ } )
346
+ . then ( ( finalOutputName ) => getHtmlWebpackPluginHooks ( compilation ) . afterEmit . promise ( {
347
+ outputName : finalOutputName ,
348
+ plugin : plugin
349
+ } ) . catch ( err => {
350
+ console . error ( err ) ;
351
+ return null ;
352
+ } ) . then ( ( ) => null ) ) ;
353
+
354
+ // Once all files are added to the webpack compilation
355
+ // let the webpack compiler continue
356
+ emitHtmlPromise . then ( ( ) => {
357
+ callback ( ) ;
331
358
} ) ;
332
- // Add the evaluated html code to the webpack assets
333
- compilation . emitAsset ( finalOutputName , new webpack . sources . RawSource ( html , false ) ) ;
334
- return finalOutputName ;
335
- } )
336
- . then ( ( finalOutputName ) => getHtmlWebpackPluginHooks ( compilation ) . afterEmit . promise ( {
337
- outputName : finalOutputName ,
338
- plugin : plugin
339
- } ) . catch ( err => {
340
- console . error ( err ) ;
341
- return null ;
342
- } ) . then ( ( ) => null ) ) ;
343
-
344
- // Once all files are added to the webpack compilation
345
- // let the webpack compiler continue
346
- emitHtmlPromise . then ( ( ) => {
347
- callback ( ) ;
348
- } ) ;
359
+ } ) ;
349
360
} ) ;
350
361
351
362
/**
0 commit comments