html-minimizer-webpack-plugin
Version:
html minimizer plugin for Webpack
222 lines (183 loc) • 6.36 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _os = _interopRequireDefault(require("os"));
var _schemaUtils = require("schema-utils");
var _serializeJavascript = _interopRequireDefault(require("serialize-javascript"));
var _pLimit = _interopRequireDefault(require("p-limit"));
var _jestWorker = _interopRequireDefault(require("jest-worker"));
var _options = _interopRequireDefault(require("./options.json"));
var _minify = require("./minify");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
class HtmlMinimizerPlugin {
constructor(options = {}) {
(0, _schemaUtils.validate)(_options.default, options, {
name: "Html Minimizer Plugin",
baseDataPath: "options"
});
const {
minify,
minimizerOptions = {},
test = /\.html(\?.*)?$/i,
parallel = true,
include,
exclude
} = options;
this.options = {
test,
parallel,
include,
exclude,
minify,
minimizerOptions
};
}
static buildError(error, file, context) {
return new Error(`${file} in "${context}" from Html Minimizer\n${error.stack}`);
}
static getAvailableNumberOfCores(parallel) {
// In some cases cpus() returns undefined
// https://github.com/nodejs/node/issues/19022
const cpus = _os.default.cpus() || {
length: 1
};
return parallel === true ? cpus.length - 1 : Math.min(Number(parallel) || 0, cpus.length - 1);
}
async optimize(compiler, compilation, assets, optimizeOptions) {
const cache = compilation.getCache("HtmlMinimizerWebpackPlugin");
let numberOfAssetsForMinify = 0;
const assetsForMinify = await Promise.all(Object.keys(assets).filter(name => {
const {
info
} = compilation.getAsset(name); // Skip double minimize assets from child compilation
if (info.minimized) {
return false;
}
if (!compiler.webpack.ModuleFilenameHelpers.matchObject.bind( // eslint-disable-next-line no-undefined
undefined, this.options)(name)) {
return false;
}
return true;
}).map(async name => {
const {
info,
source
} = compilation.getAsset(name);
const eTag = cache.getLazyHashedEtag(source);
const cacheItem = cache.getItemCache(name, eTag);
const output = await cacheItem.getPromise();
if (!output) {
numberOfAssetsForMinify += 1;
}
return {
name,
info,
inputSource: source,
output,
cacheItem
};
}));
let getWorker;
let initializedWorker;
let numberOfWorkers;
if (optimizeOptions.availableNumberOfCores > 0) {
// Do not create unnecessary workers when the number of files is less than the available cores, it saves memory
numberOfWorkers = Math.min(numberOfAssetsForMinify, optimizeOptions.availableNumberOfCores); // eslint-disable-next-line consistent-return
getWorker = () => {
if (initializedWorker) {
return initializedWorker;
}
initializedWorker = new _jestWorker.default(require.resolve("./minify"), {
numWorkers: numberOfWorkers,
enableWorkerThreads: true
}); // https://github.com/facebook/jest/issues/8872#issuecomment-524822081
const workerStdout = initializedWorker.getStdout();
if (workerStdout) {
workerStdout.on("data", chunk => process.stdout.write(chunk));
}
const workerStderr = initializedWorker.getStderr();
if (workerStderr) {
workerStderr.on("data", chunk => process.stderr.write(chunk));
}
return initializedWorker;
};
}
const limit = (0, _pLimit.default)(getWorker && numberOfAssetsForMinify > 0 ? numberOfWorkers : Infinity);
const {
RawSource
} = compiler.webpack.sources;
const scheduledTasks = [];
for (const asset of assetsForMinify) {
scheduledTasks.push(limit(async () => {
const {
name,
inputSource,
cacheItem
} = asset;
let {
output
} = asset;
let input;
const sourceFromInputSource = inputSource.source();
if (!output) {
input = sourceFromInputSource;
if (Buffer.isBuffer(input)) {
input = input.toString();
}
const options = {
name,
input,
minimizerOptions: { ...this.options.minimizerOptions
},
minify: this.options.minify
};
try {
output = await (getWorker ? getWorker().transform((0, _serializeJavascript.default)(options)) : (0, _minify.minify)(options));
} catch (error) {
compilation.errors.push(HtmlMinimizerPlugin.buildError(error, name, compiler.context));
return;
}
output.source = new RawSource(output.code);
await cacheItem.storePromise({
source: output.source
});
}
const newInfo = {
minimized: true
};
const {
source
} = output;
compilation.updateAsset(name, source, newInfo);
}));
}
await Promise.all(scheduledTasks);
if (initializedWorker) {
await initializedWorker.end();
}
}
apply(compiler) {
const pluginName = this.constructor.name;
const availableNumberOfCores = HtmlMinimizerPlugin.getAvailableNumberOfCores(this.options.parallel);
compiler.hooks.compilation.tap(pluginName, compilation => {
compilation.hooks.processAssets.tapPromise({
name: pluginName,
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE,
additionalAssets: true
}, assets => this.optimize(compiler, compilation, assets, {
availableNumberOfCores
}));
compilation.hooks.statsPrinter.tap(pluginName, stats => {
stats.hooks.print.for("asset.info.minimized").tap("html-minimizer-webpack-plugin", (minimized, {
green,
formatFlag
}) => // eslint-disable-next-line no-undefined
minimized ? green(formatFlag("minimized")) : undefined);
});
});
}
}
var _default = HtmlMinimizerPlugin;
exports.default = _default;