11// @ts -check
2- // Import types
3- /** @typedef {import("./typings").HtmlTagObject } HtmlTagObject */
4- /** @typedef {import("./typings").Options } HtmlWebpackOptions */
5- /** @typedef {import("./typings").ProcessedOptions } ProcessedHtmlWebpackOptions */
6- /** @typedef {import("./typings").TemplateParameter } TemplateParameter */
7- /** @typedef {import("webpack/lib/Compiler.js") } WebpackCompiler */
8- /** @typedef {import("webpack/lib/Compilation.js") } WebpackCompilation */
92'use strict' ;
103
114const promisify = require ( 'util' ) . promisify ;
@@ -23,7 +16,13 @@ const chunkSorter = require('./lib/chunksorter.js');
2316const getHtmlWebpackPluginHooks = require ( './lib/hooks.js' ) . getHtmlWebpackPluginHooks ;
2417const { assert } = require ( 'console' ) ;
2518
26- const fsReadFileAsync = promisify ( fs . readFile ) ;
19+ /** @typedef {import("./typings").HtmlTagObject } HtmlTagObject */
20+ /** @typedef {import("./typings").Options } HtmlWebpackOptions */
21+ /** @typedef {import("./typings").ProcessedOptions } ProcessedHtmlWebpackOptions */
22+ /** @typedef {import("./typings").TemplateParameter } TemplateParameter */
23+ /** @typedef {import("webpack/lib/Compiler.js") } WebpackCompiler */
24+ /** @typedef {import("webpack/lib/Compilation.js") } WebpackCompilation */
25+ /** @typedef {Array<{ source: import('webpack').sources.Source, name: string }> } PreviousEmittedAssets */
2726
2827class HtmlWebpackPlugin {
2928 /**
@@ -216,7 +215,7 @@ function hookIntoCompiler (compiler, options, plugin) {
216215 /**
217216 * store the previous generated asset to emit them even if the content did not change
218217 * to support watch mode for third party plugins like the clean-webpack-plugin or the compression plugin
219- * @type {Array<{html: string, name: string}> }
218+ * @type {PreviousEmittedAssets }
220219 */
221220 let previousEmittedAssets = [ ] ;
222221
@@ -302,8 +301,8 @@ function hookIntoCompiler (compiler, options, plugin) {
302301 // If the template and the assets did not change we don't have to emit the html
303302 const newAssetJson = JSON . stringify ( getAssetFiles ( assets ) ) ;
304303 if ( isCompilationCached && options . cache && assetJson === newAssetJson ) {
305- previousEmittedAssets . forEach ( ( { name, html } ) => {
306- compilation . emitAsset ( name , new webpack . sources . RawSource ( html , false ) ) ;
304+ previousEmittedAssets . forEach ( ( { name, source } ) => {
305+ compilation . emitAsset ( name , source ) ;
307306 } ) ;
308307 return callback ( ) ;
309308 } else {
@@ -314,7 +313,7 @@ function hookIntoCompiler (compiler, options, plugin) {
314313 // The html-webpack plugin uses a object representation for the html-tags which will be injected
315314 // to allow altering them more easily
316315 // Just before they are converted a third-party-plugin author might change the order and content
317- const assetsPromise = getFaviconPublicPath ( options . favicon , compilation , assets . publicPath )
316+ const assetsPromise = generateFavicon ( options . favicon , compilation , assets . publicPath , previousEmittedAssets )
318317 . then ( ( faviconPath ) => {
319318 assets . favicon = faviconPath ;
320319 return getHtmlWebpackPluginHooks ( compilation ) . beforeAssetTagGeneration . promise ( {
@@ -408,9 +407,12 @@ function hookIntoCompiler (compiler, options, plugin) {
408407 '[templatehash] is now [contenthash]' )
409408 ) ;
410409 const replacedFilename = replacePlaceholdersInFilename ( filename , html , compilation ) ;
410+ const source = new webpack . sources . RawSource ( html , false ) ;
411+
411412 // Add the evaluated html code to the webpack assets
412- compilation . emitAsset ( replacedFilename . path , new webpack . sources . RawSource ( html , false ) , replacedFilename . info ) ;
413- previousEmittedAssets . push ( { name : replacedFilename . path , html } ) ;
413+ compilation . emitAsset ( replacedFilename . path , source , replacedFilename . info ) ;
414+ previousEmittedAssets . push ( { name : replacedFilename . path , source } ) ;
415+
414416 return replacedFilename . path ;
415417 } )
416418 . then ( ( finalOutputName ) => getHtmlWebpackPluginHooks ( compilation ) . afterEmit . promise ( {
@@ -529,26 +531,6 @@ function hookIntoCompiler (compiler, options, plugin) {
529531 return Promise . resolve ( htmlAfterMinification ) ;
530532 }
531533
532- /*
533- * Pushes the content of the given filename to the compilation assets
534- * @param {string } filename
535- * @param {WebpackCompilation } compilation
536- *
537- * @returns {string } file basename
538- */
539- function addFileToAssets ( filename , compilation ) {
540- filename = path . resolve ( compilation . compiler . context , filename ) ;
541- return fsReadFileAsync ( filename )
542- . then ( source => new webpack . sources . RawSource ( source , false ) )
543- . catch ( ( ) => Promise . reject ( new Error ( 'HtmlWebpackPlugin: could not load file ' + filename ) ) )
544- . then ( rawSource => {
545- const basename = path . basename ( filename ) ;
546- compilation . fileDependencies . add ( filename ) ;
547- compilation . emitAsset ( basename , rawSource ) ;
548- return basename ;
549- } ) ;
550- }
551-
552534 /**
553535 * Replace [contenthash] in filename
554536 *
@@ -757,23 +739,37 @@ function hookIntoCompiler (compiler, options, plugin) {
757739 * Converts a favicon file from disk to a webpack resource
758740 * and returns the url to the resource
759741 *
760- * @param {string|false } faviconFilePath
742+ * @param {string|false } favicon
761743 * @param {WebpackCompilation } compilation
762744 * @param {string } publicPath
745+ * @param {PreviousEmittedAssets } previousEmittedAssets
763746 * @returns {Promise<string|undefined> }
764747 */
765- function getFaviconPublicPath ( faviconFilePath , compilation , publicPath ) {
766- if ( ! faviconFilePath ) {
748+ function generateFavicon ( favicon , compilation , publicPath , previousEmittedAssets ) {
749+ if ( ! favicon ) {
767750 return Promise . resolve ( undefined ) ;
768751 }
769- return addFileToAssets ( faviconFilePath , compilation )
770- . then ( ( faviconName ) => {
771- const faviconPath = publicPath + faviconName ;
752+
753+ const filename = path . resolve ( compilation . compiler . context , favicon ) ;
754+
755+ return promisify ( compilation . inputFileSystem . readFile ) ( filename )
756+ . then ( ( buf ) => {
757+ const source = new webpack . sources . RawSource ( buf , false ) ;
758+ const name = path . basename ( filename ) ;
759+
760+ compilation . fileDependencies . add ( filename ) ;
761+ compilation . emitAsset ( name , source ) ;
762+ previousEmittedAssets . push ( { name, source } ) ;
763+
764+ const faviconPath = publicPath + name ;
765+
772766 if ( options . hash ) {
773767 return appendHash ( faviconPath , compilation . hash ) ;
774768 }
769+
775770 return faviconPath ;
776- } ) ;
771+ } )
772+ . catch ( ( ) => Promise . reject ( new Error ( 'HtmlWebpackPlugin: could not load file ' + filename ) ) ) ;
777773 }
778774
779775 /**
0 commit comments