Skip to content

Commit

Permalink
Extract findHtmlWebpackPlugin function
Browse files Browse the repository at this point in the history
  • Loading branch information
andy128k committed Jun 8, 2023
1 parent 7d52c5f commit 3a800f0
Showing 1 changed file with 115 additions and 97 deletions.
212 changes: 115 additions & 97 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,106 +198,85 @@ class FaviconsWebpackPlugin {
compilation.fileDependencies.add(this.options.manifest);
}

// Hook into the html-webpack-plugin processing and add the html
const HtmlWebpackPlugin = compiler.options.plugins
.map(({ constructor }) => constructor)
.find(
/**
* Find only HtmlWebpkackPlugin constructors
* @type {(constructor: Function) => constructor is typeof import('html-webpack-plugin')}
*/
(constructor) =>
constructor && constructor.name === 'HtmlWebpackPlugin'
);

if (HtmlWebpackPlugin && this.options.inject) {
if (!verifyHtmlWebpackPluginVersion(HtmlWebpackPlugin)) {
compilation.errors.push(
new compiler.webpack.WebpackError(
`${
'FaviconsWebpackPlugin - This FaviconsWebpackPlugin version is not compatible with your current HtmlWebpackPlugin version.\n' +
'Please upgrade to HtmlWebpackPlugin >= 5 OR downgrade to FaviconsWebpackPlugin 2.x\n'
}${getHtmlWebpackPluginVersion()}`
)
);
if (this.options.inject) {
// Hook into the html-webpack-plugin processing and add the html
findHtmlWebpackPlugin(compilation)
?.getHooks(compilation)
.alterAssetTags.tapPromise(
'FaviconsWebpackPlugin',
async (htmlPluginData) => {
// Skip if a custom injectFunction returns false or if
// the htmlWebpackPlugin optuons includes a `favicons: false` flag
const isInjectionAllowed =
typeof this.options.inject === 'function'
? this.options.inject(htmlPluginData.plugin)
: this.options.inject !== false &&
htmlPluginData.plugin.userOptions.favicon !== false &&
htmlPluginData.plugin.userOptions.favicons !== false;

if (isInjectionAllowed === false) {
return htmlPluginData;
}

const faviconCompilationResult = await faviconCompilation;
// faviconCompilation.publicPath and htmlPluginData.publicPath can be:
// absolute: http://somewhere.com/app1/
// absolute: /demo/app1/
// relative: my/app/
const publicPathFromHtml = url.resolve(
htmlPluginData.publicPath,
faviconCompilationResult.publicPath
);

// Prefix links to icons
const pathReplacer =
!this.options.favicons.path ||
this.getCurrentCompilationMode(compiler) === 'light'
? /** @param {string} url */ (url) =>
typeof url === 'string' ? publicPathFromHtml + url : url
: /** @param {string} url */ (url) => url;

htmlPluginData.assetTags.meta.push(
...faviconCompilationResult.tags
.filter((tag) => tag && tag.length)
.map((tag) => parse5.parseFragment(tag).childNodes[0])
.map(({ tagName, attrs }) => {
const htmlTag = {
tagName,
voidTag: true,
meta: { plugin: 'favicons-webpack-plugin' },
attributes: attrs.reduce(
(obj, { name, value }) =>
Object.assign(obj, { [name]: value }),
{}
),
};
// Prefix link tags
if (typeof htmlTag.attributes.href === 'string') {
htmlTag.attributes.href = pathReplacer(
htmlTag.attributes.href
);
}
// Prefix meta tags
if (
htmlTag.tagName === 'meta' &&
[
'msapplication-TileImage',
'msapplication-config',
].includes(htmlTag.attributes.name)
) {
htmlTag.attributes.content = pathReplacer(
htmlTag.attributes.content
);
}

return htmlTag;
})
);

return;
}
HtmlWebpackPlugin.getHooks(compilation).alterAssetTags.tapPromise(
'FaviconsWebpackPlugin',
async (htmlPluginData) => {
// Skip if a custom injectFunction returns false or if
// the htmlWebpackPlugin optuons includes a `favicons: false` flag
const isInjectionAllowed =
typeof this.options.inject === 'function'
? this.options.inject(htmlPluginData.plugin)
: this.options.inject !== false &&
htmlPluginData.plugin.userOptions.favicon !== false &&
htmlPluginData.plugin.userOptions.favicons !== false;

if (isInjectionAllowed === false) {
return htmlPluginData;
}

const faviconCompilationResult = await faviconCompilation;
// faviconCompilation.publicPath and htmlPluginData.publicPath can be:
// absolute: http://somewhere.com/app1/
// absolute: /demo/app1/
// relative: my/app/
const publicPathFromHtml = url.resolve(
htmlPluginData.publicPath,
faviconCompilationResult.publicPath
);

// Prefix links to icons
const pathReplacer =
!this.options.favicons.path ||
this.getCurrentCompilationMode(compiler) === 'light'
? /** @param {string} url */ (url) =>
typeof url === 'string' ? publicPathFromHtml + url : url
: /** @param {string} url */ (url) => url;

htmlPluginData.assetTags.meta.push(
...faviconCompilationResult.tags
.filter((tag) => tag && tag.length)
.map((tag) => parse5.parseFragment(tag).childNodes[0])
.map(({ tagName, attrs }) => {
const htmlTag = {
tagName,
voidTag: true,
meta: { plugin: 'favicons-webpack-plugin' },
attributes: attrs.reduce(
(obj, { name, value }) =>
Object.assign(obj, { [name]: value }),
{}
),
};
// Prefix link tags
if (typeof htmlTag.attributes.href === 'string') {
htmlTag.attributes.href = pathReplacer(
htmlTag.attributes.href
);
}
// Prefix meta tags
if (
htmlTag.tagName === 'meta' &&
[
'msapplication-TileImage',
'msapplication-config',
].includes(htmlTag.attributes.name)
) {
htmlTag.attributes.content = pathReplacer(
htmlTag.attributes.content
);
}

return htmlTag;
})
);

return htmlPluginData;
}
);
);
}

// Save the promise and execute the callback immediately to not block
Expand Down Expand Up @@ -629,6 +608,45 @@ function getHtmlWebpackPluginVersion() {
}
}

/**
* Return `HtmlWebpackPlugin` if it is available.
*
* @param {import('webpack').Compilation} compilation
* @returns {typeof import('html-webpack-plugin') | undefined}
*/
function findHtmlWebpackPlugin(compilation) {
const compiler = compilation.compiler;

const HtmlWebpackPlugin = compiler.options.plugins
.map(({ constructor }) => constructor)
.find(
/**
* Find only HtmlWebpkackPlugin constructors
* @type {(constructor: Function) => constructor is typeof import('html-webpack-plugin')}
*/
(constructor) => constructor && constructor.name === 'HtmlWebpackPlugin'
);

if (!HtmlWebpackPlugin) {
return undefined;
}

if (!verifyHtmlWebpackPluginVersion(HtmlWebpackPlugin)) {
compilation.errors.push(
new compiler.webpack.WebpackError(
`${
'FaviconsWebpackPlugin - This FaviconsWebpackPlugin version is not compatible with your current HtmlWebpackPlugin version.\n' +
'Please upgrade to HtmlWebpackPlugin >= 5 OR downgrade to FaviconsWebpackPlugin 2.x\n'
}${getHtmlWebpackPluginVersion()}`
)
);

return undefined;
}

return HtmlWebpackPlugin;
}

/**
* Try to load favicon for the full favicon generation
*
Expand Down

0 comments on commit 3a800f0

Please sign in to comment.