import webpack from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
class HtmlInlinePlugin implements webpack.Plugin {
private htmlWebpackPlugin: HtmlWebpackPlugin;
private tests: Array;
constructor(htmlWebpackPlugin: HtmlWebpackPlugin, tests: Array) {
this.htmlWebpackPlugin = htmlWebpackPlugin;
this.tests = tests;
}
private findAsset(
publicPath: string,
assets: any,
tag: HtmlWebpackPlugin.HtmlTagObject,
attributeName: string,
) {
if (!(tag.attributes && tag.attributes[attributeName])) {
return null;
}
const scriptName = publicPath
? (tag.attributes[attributeName] as string).replace(publicPath, '')
: (tag.attributes[attributeName] as string);
const asset = assets[scriptName];
if (asset === null) {
return null;
}
if (!this.tests.some(test => scriptName.match(test))) {
return null;
}
return asset;
}
private getInlinedTag(
publicPath: string,
assets: any,
tag: HtmlWebpackPlugin.HtmlTagObject,
): HtmlWebpackPlugin.HtmlTagObject {
switch (tag.tagName) {
case 'script': {
const asset = this.findAsset(publicPath, assets, tag, 'src');
if (!asset) {
return tag;
}
return {
tagName: 'script',
innerHTML: asset.source(),
attributes: {},
voidTag: false,
};
}
case 'link': {
const asset = this.findAsset(publicPath, assets, tag, 'href');
if (!asset) {
return tag;
}
return {
tagName: 'style',
innerHTML: asset.source(),
attributes: {},
voidTag: false,
};
}
default: {
return tag;
}
}
}
apply(compiler: webpack.Compiler) {
let publicPath = compiler.options?.output?.publicPath ?? '';
if (publicPath && !publicPath.endsWith('/')) {
publicPath += '/';
}
compiler.hooks.compilation.tap('HtmlInlinePlugin', compilation => {
const tagFunction = (tag: HtmlWebpackPlugin.HtmlTagObject) =>
this.getInlinedTag(publicPath, compilation.assets, tag);
// @ts-ignore
const hooks = this.htmlWebpackPlugin.getHooks(
compilation,
) as HtmlWebpackPlugin.Hooks;
hooks.alterAssetTagGroups.tap('HtmlInlinePlugin', assets => {
assets.headTags = assets.headTags.map(tagFunction);
assets.bodyTags = assets.bodyTags.map(tagFunction);
return assets;
});
});
}
}
export default HtmlInlinePlugin;