Skip to content

Commit 57c5a4e

Browse files
fix: reemit favicon in serve/watch mode (#1804)
1 parent d3819ab commit 57c5a4e

File tree

1 file changed

+37
-41
lines changed

1 file changed

+37
-41
lines changed

index.js

Lines changed: 37 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
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

114
const promisify = require('util').promisify;
@@ -23,7 +16,13 @@ const chunkSorter = require('./lib/chunksorter.js');
2316
const getHtmlWebpackPluginHooks = require('./lib/hooks.js').getHtmlWebpackPluginHooks;
2417
const { 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

2827
class 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

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy