@@ -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 ,
133132HTML_WEBPACK_PLUGIN :true ,
134133require :require ,
135- htmlWebpackPluginPublicPath :
136- publicPath ,
134+ htmlWebpackPluginPublicPath :publicPath ,
137135URL :require ( 'url' ) . URL ,
138136__filename :templateWithoutLoaders
139137} ) ;
@@ -189,13 +187,6 @@ function hookIntoCompiler (compiler, options, plugin) {
189187options . 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
201192const isProductionLikeMode = compiler . options . mode === 'production' || ! compiler . options . mode ;
@@ -249,21 +240,12 @@ function hookIntoCompiler (compiler, options, plugin) {
249240compilation . 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
263245const 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 */
269251const assets = htmlWebpackPluginAssets ( compilation , sortedEntryNames , htmlPublicPath ) ;
@@ -288,7 +270,7 @@ function hookIntoCompiler (compiler, options, plugin) {
288270assets . favicon = faviconPath ;
289271return getHtmlWebpackPluginHooks ( compilation ) . beforeAssetTagGeneration . promise ( {
290272assets :assets ,
291- outputName :childCompilationOutputName ,
273+ outputName :options . filename ,
292274plugin :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 ,
310292publicPath :htmlPublicPath ,
311293plugin :plugin
312294} ) )
@@ -320,7 +302,7 @@ function hookIntoCompiler (compiler, options, plugin) {
320302return getHtmlWebpackPluginHooks ( compilation ) . alterAssetTagGroups . promise ( {
321303headTags :assetGroups . headTags ,
322304bodyTags :assetGroups . bodyTags ,
323- outputName :childCompilationOutputName ,
305+ outputName :options . filename ,
324306publicPath :htmlPublicPath ,
325307plugin :plugin
326308} ) ;
@@ -351,7 +333,7 @@ function hookIntoCompiler (compiler, options, plugin) {
351333const 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 } ;
355337return getHtmlWebpackPluginHooks ( compilation ) . afterTemplateExecution . promise ( pluginArgs ) ;
356338} )
357339. then ( ( { html, headTags, bodyTags} ) => {
@@ -361,7 +343,7 @@ function hookIntoCompiler (compiler, options, plugin) {
361343const 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 } ;
365347return getHtmlWebpackPluginHooks ( compilation ) . beforeEmit . promise ( pluginArgs )
366348. then ( result => result . html ) ;
367349} )
@@ -372,16 +354,15 @@ function hookIntoCompiler (compiler, options, plugin) {
372354return 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 ( {
387368outputName :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