@@ -14,7 +14,6 @@ const vm = require('vm');
1414const fs = require ( 'fs' ) ;
1515const _ = require ( 'lodash' ) ;
1616const path = require ( 'path' ) ;
17- const loaderUtils = require ( 'loader-utils' ) ;
1817const { CachedChildCompilation } = require ( './lib/cached-child-compiler' ) ;
1918
2019const { createHtmlTagObject, htmlTagObjectToString, HtmlTagArray } = require ( './lib/html-tags' ) ;
@@ -132,8 +131,7 @@ class HtmlWebpackPlugin {
132131 ...global ,
133132 HTML_WEBPACK_PLUGIN : true ,
134133 require : require ,
135- htmlWebpackPluginPublicPath :
136- publicPath ,
134+ htmlWebpackPluginPublicPath : publicPath ,
137135 URL : require ( 'url' ) . URL ,
138136 __filename : templateWithoutLoaders
139137 } ) ;
@@ -189,13 +187,6 @@ function hookIntoCompiler (compiler, options, plugin) {
189187 options . filename = path . relative ( outputPath , filename ) ;
190188 }
191189
192- // `contenthash` is introduced in webpack v4.3
193- // which conflicts with the plugin's existing `contenthash` method,
194- // hence it is renamed to `templatehash` to avoid conflicts
195- options . filename = options . filename . replace ( / \[ (?: ( \w + ) : ) ? c o n t e n t h a s h (?: : ( [ a - z ] + \d * ) ) ? (?: : ( \d + ) ) ? \] / ig, ( match ) => {
196- return match . replace ( 'contenthash' , 'templatehash' ) ;
197- } ) ;
198-
199190 // Check if webpack is running in production mode
200191 // @see https://github.com/webpack/webpack/blob/3366421f1784c449f415cda5930a8e445086f688/lib/WebpackOptionsDefaulter.js#L12-L14
201192 const isProductionLikeMode = compiler . options . mode === 'production' || ! compiler . options . mode ;
@@ -249,21 +240,12 @@ function hookIntoCompiler (compiler, options, plugin) {
249240 compilation . errors . push ( prettyError ( templateResult . error , compiler . context ) . toString ( ) ) ;
250241 }
251242
252- const compiledEntries = 'compiledEntry' in templateResult ? {
253- hash : templateResult . compiledEntry . hash ,
254- chunk : templateResult . compiledEntry . entry
255- } : {
256- hash : templateResult . mainCompilationHash
257- } ;
258-
259- const childCompilationOutputName = compilation . getAssetPath ( options . filename , compiledEntries ) ;
260-
261243 // If the child compilation was not executed during a previous main compile run
262244 // it is a cached result
263245 const isCompilationCached = templateResult . mainCompilationHash !== compilation . hash ;
264246
265247 /** The public path used inside the html file */
266- const htmlPublicPath = getPublicPath ( compilation , childCompilationOutputName , options . publicPath ) ;
248+ const htmlPublicPath = getPublicPath ( compilation , options . filename , options . publicPath ) ;
267249
268250 /** Generated file paths from the entry point names */
269251 const assets = htmlWebpackPluginAssets ( compilation , sortedEntryNames , htmlPublicPath ) ;
@@ -288,7 +270,7 @@ function hookIntoCompiler (compiler, options, plugin) {
288270 assets . favicon = faviconPath ;
289271 return getHtmlWebpackPluginHooks ( compilation ) . beforeAssetTagGeneration . promise ( {
290272 assets : assets ,
291- outputName : childCompilationOutputName ,
273+ outputName : options . filename ,
292274 plugin : plugin
293275 } ) ;
294276 } ) ;
@@ -306,7 +288,7 @@ function hookIntoCompiler (compiler, options, plugin) {
306288 ...generateFaviconTags ( assets . favicon )
307289 ]
308290 } ,
309- outputName : childCompilationOutputName ,
291+ outputName : options . filename ,
310292 publicPath : htmlPublicPath ,
311293 plugin : plugin
312294 } ) )
@@ -320,7 +302,7 @@ function hookIntoCompiler (compiler, options, plugin) {
320302 return getHtmlWebpackPluginHooks ( compilation ) . alterAssetTagGroups . promise ( {
321303 headTags : assetGroups . headTags ,
322304 bodyTags : assetGroups . bodyTags ,
323- outputName : childCompilationOutputName ,
305+ outputName : options . filename ,
324306 publicPath : htmlPublicPath ,
325307 plugin : plugin
326308 } ) ;
@@ -351,7 +333,7 @@ function hookIntoCompiler (compiler, options, plugin) {
351333 const injectedHtmlPromise = Promise . all ( [ assetTagGroupsPromise , templateExectutionPromise ] )
352334 // Allow plugins to change the html before assets are injected
353335 . then ( ( [ assetTags , html ] ) => {
354- const pluginArgs = { html, headTags : assetTags . headTags , bodyTags : assetTags . bodyTags , plugin : plugin , outputName : childCompilationOutputName } ;
336+ const pluginArgs = { html, headTags : assetTags . headTags , bodyTags : assetTags . bodyTags , plugin : plugin , outputName : options . filename } ;
355337 return getHtmlWebpackPluginHooks ( compilation ) . afterTemplateExecution . promise ( pluginArgs ) ;
356338 } )
357339 . then ( ( { html, headTags, bodyTags } ) => {
@@ -361,7 +343,7 @@ function hookIntoCompiler (compiler, options, plugin) {
361343 const emitHtmlPromise = injectedHtmlPromise
362344 // Allow plugins to change the html after assets are injected
363345 . then ( ( html ) => {
364- const pluginArgs = { html, plugin : plugin , outputName : childCompilationOutputName } ;
346+ const pluginArgs = { html, plugin : plugin , outputName : options . filename } ;
365347 return getHtmlWebpackPluginHooks ( compilation ) . beforeEmit . promise ( pluginArgs )
366348 . then ( result => result . html ) ;
367349 } )
@@ -372,16 +354,15 @@ function hookIntoCompiler (compiler, options, plugin) {
372354 return options . showErrors ? prettyError ( err , compiler . context ) . toHtml ( ) : 'ERROR' ;
373355 } )
374356 . then ( html => {
375- // Allow to use [templatehash] as placeholder for the html-webpack-plugin name
376- // See also https://survivejs.com/webpack/optimizing/adding-hashes-to-filenames/
377- // From https://github.com/webpack-contrib/extract-text-webpack-plugin/blob/8de6558e33487e7606e7cd7cb2adc2cccafef272/src/index.js#L212-L214
378- 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 ) => {
379- return loaderUtils . getHashDigest ( Buffer . from ( html , 'utf8' ) , hashType , digestType , parseInt ( maxLength , 10 ) ) ;
380- } ) ;
357+ const filename = options . filename . replace ( / \[ t e m p l a t e h a s h ( [ ^ \] ] * ) \] / g, require ( 'util' ) . deprecate (
358+ ( match , options ) => `[contenthash${ options } ]` ,
359+ '[templatehash] is now [contenthash]' )
360+ ) ;
361+ const replacedFilename = replacePlaceholdersInFilename ( filename , html , compilation ) ;
381362 // Add the evaluated html code to the webpack assets
382- compilation . emitAsset ( finalOutputName , new webpack . sources . RawSource ( html , false ) ) ;
383- previousEmittedAssets . push ( { name : finalOutputName , html } ) ;
384- return finalOutputName ;
363+ compilation . emitAsset ( replacedFilename . path , new webpack . sources . RawSource ( html , false ) , replacedFilename . info ) ;
364+ previousEmittedAssets . push ( { name : replacedFilename . path , html } ) ;
365+ return replacedFilename . path ;
385366 } )
386367 . then ( ( finalOutputName ) => getHtmlWebpackPluginHooks ( compilation ) . afterEmit . promise ( {
387368 outputName : finalOutputName ,
@@ -519,6 +500,38 @@ function hookIntoCompiler (compiler, options, plugin) {
519500 } ) ;
520501 }
521502
503+ /**
504+ * Replace [contenthash] in filename
505+ *
506+ * @see https://survivejs.com/webpack/optimizing/adding-hashes-to-filenames/
507+ *
508+ * @param {string } filename
509+ * @param {string|Buffer } fileContent
510+ * @param {WebpackCompilation } compilation
511+ * @returns {{ path: string, info: {} } }
512+ */
513+ function replacePlaceholdersInFilename ( filename , fileContent , compilation ) {
514+ if ( / \[ \\ * ( [ \w : ] + ) \\ * \] / i. test ( filename ) === false ) {
515+ return { path : filename , info : { } } ;
516+ }
517+ const hash = compiler . webpack . util . createHash ( compilation . outputOptions . hashFunction ) ;
518+ hash . update ( fileContent ) ;
519+ if ( compilation . outputOptions . hashSalt ) {
520+ hash . update ( compilation . outputOptions . hashSalt ) ;
521+ }
522+ const contentHash = hash . digest ( compilation . outputOptions . hashDigest ) . slice ( 0 , compilation . outputOptions . hashDigestLength ) ;
523+ return compilation . getPathWithInfo (
524+ filename ,
525+ {
526+ contentHash,
527+ chunk : {
528+ hash : contentHash ,
529+ contentHash
530+ }
531+ }
532+ ) ;
533+ }
534+
522535 /**
523536 * Helper to sort chunks
524537 * @param {string[] } entryNames
0 commit comments