Skip to content

Commit

Permalink
fix: reemit favicon in serve/watch mode (#1804)
Browse files Browse the repository at this point in the history
  • Loading branch information
alexander-akait authored Jun 19, 2023
1 parent d3819ab commit 57c5a4e
Showing 1 changed file with 37 additions and 41 deletions.
78 changes: 37 additions & 41 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
// @ts-check
// Import types
/** @typedef {import("./typings").HtmlTagObject} HtmlTagObject */
/** @typedef {import("./typings").Options} HtmlWebpackOptions */
/** @typedef {import("./typings").ProcessedOptions} ProcessedHtmlWebpackOptions */
/** @typedef {import("./typings").TemplateParameter} TemplateParameter */
/** @typedef {import("webpack/lib/Compiler.js")} WebpackCompiler */
/** @typedef {import("webpack/lib/Compilation.js")} WebpackCompilation */
'use strict';

const promisify = require('util').promisify;
Expand All @@ -23,7 +16,13 @@ const chunkSorter = require('./lib/chunksorter.js');
const getHtmlWebpackPluginHooks = require('./lib/hooks.js').getHtmlWebpackPluginHooks;
const { assert } = require('console');

const fsReadFileAsync = promisify(fs.readFile);
/** @typedef {import("./typings").HtmlTagObject} HtmlTagObject */
/** @typedef {import("./typings").Options} HtmlWebpackOptions */
/** @typedef {import("./typings").ProcessedOptions} ProcessedHtmlWebpackOptions */
/** @typedef {import("./typings").TemplateParameter} TemplateParameter */
/** @typedef {import("webpack/lib/Compiler.js")} WebpackCompiler */
/** @typedef {import("webpack/lib/Compilation.js")} WebpackCompilation */
/** @typedef {Array<{ source: import('webpack').sources.Source, name: string }>} PreviousEmittedAssets */

class HtmlWebpackPlugin {
/**
Expand Down Expand Up @@ -216,7 +215,7 @@ function hookIntoCompiler (compiler, options, plugin) {
/**
* store the previous generated asset to emit them even if the content did not change
* to support watch mode for third party plugins like the clean-webpack-plugin or the compression plugin
* @type {Array<{html: string, name: string}>}
* @type {PreviousEmittedAssets}
*/
let previousEmittedAssets = [];

Expand Down Expand Up @@ -302,8 +301,8 @@ function hookIntoCompiler (compiler, options, plugin) {
// If the template and the assets did not change we don't have to emit the html
const newAssetJson = JSON.stringify(getAssetFiles(assets));
if (isCompilationCached && options.cache && assetJson === newAssetJson) {
previousEmittedAssets.forEach(({ name, html }) => {
compilation.emitAsset(name, new webpack.sources.RawSource(html, false));
previousEmittedAssets.forEach(({ name, source }) => {
compilation.emitAsset(name, source);
});
return callback();
} else {
Expand All @@ -314,7 +313,7 @@ function hookIntoCompiler (compiler, options, plugin) {
// The html-webpack plugin uses a object representation for the html-tags which will be injected
// to allow altering them more easily
// Just before they are converted a third-party-plugin author might change the order and content
const assetsPromise = getFaviconPublicPath(options.favicon, compilation, assets.publicPath)
const assetsPromise = generateFavicon(options.favicon, compilation, assets.publicPath, previousEmittedAssets)
.then((faviconPath) => {
assets.favicon = faviconPath;
return getHtmlWebpackPluginHooks(compilation).beforeAssetTagGeneration.promise({
Expand Down Expand Up @@ -408,9 +407,12 @@ function hookIntoCompiler (compiler, options, plugin) {
'[templatehash] is now [contenthash]')
);
const replacedFilename = replacePlaceholdersInFilename(filename, html, compilation);
const source = new webpack.sources.RawSource(html, false);

// Add the evaluated html code to the webpack assets
compilation.emitAsset(replacedFilename.path, new webpack.sources.RawSource(html, false), replacedFilename.info);
previousEmittedAssets.push({ name: replacedFilename.path, html });
compilation.emitAsset(replacedFilename.path, source, replacedFilename.info);
previousEmittedAssets.push({ name: replacedFilename.path, source });

return replacedFilename.path;
})
.then((finalOutputName) => getHtmlWebpackPluginHooks(compilation).afterEmit.promise({
Expand Down Expand Up @@ -529,26 +531,6 @@ function hookIntoCompiler (compiler, options, plugin) {
return Promise.resolve(htmlAfterMinification);
}

/*
* Pushes the content of the given filename to the compilation assets
* @param {string} filename
* @param {WebpackCompilation} compilation
*
* @returns {string} file basename
*/
function addFileToAssets (filename, compilation) {
filename = path.resolve(compilation.compiler.context, filename);
return fsReadFileAsync(filename)
.then(source => new webpack.sources.RawSource(source, false))
.catch(() => Promise.reject(new Error('HtmlWebpackPlugin: could not load file ' + filename)))
.then(rawSource => {
const basename = path.basename(filename);
compilation.fileDependencies.add(filename);
compilation.emitAsset(basename, rawSource);
return basename;
});
}

/**
* Replace [contenthash] in filename
*
Expand Down Expand Up @@ -757,23 +739,37 @@ function hookIntoCompiler (compiler, options, plugin) {
* Converts a favicon file from disk to a webpack resource
* and returns the url to the resource
*
* @param {string|false} faviconFilePath
* @param {string|false} favicon
* @param {WebpackCompilation} compilation
* @param {string} publicPath
* @param {PreviousEmittedAssets} previousEmittedAssets
* @returns {Promise<string|undefined>}
*/
function getFaviconPublicPath (faviconFilePath, compilation, publicPath) {
if (!faviconFilePath) {
function generateFavicon (favicon, compilation, publicPath, previousEmittedAssets) {
if (!favicon) {
return Promise.resolve(undefined);
}
return addFileToAssets(faviconFilePath, compilation)
.then((faviconName) => {
const faviconPath = publicPath + faviconName;

const filename = path.resolve(compilation.compiler.context, favicon);

return promisify(compilation.inputFileSystem.readFile)(filename)
.then((buf) => {
const source = new webpack.sources.RawSource(buf, false);
const name = path.basename(filename);

compilation.fileDependencies.add(filename);
compilation.emitAsset(name, source);
previousEmittedAssets.push({ name, source });

const faviconPath = publicPath + name;

if (options.hash) {
return appendHash(faviconPath, compilation.hash);
}

return faviconPath;
});
})
.catch(() => Promise.reject(new Error('HtmlWebpackPlugin: could not load file ' + filename)));
}

/**
Expand Down

0 comments on commit 57c5a4e

Please sign in to comment.