forked from projectmoon/tenebrous-dicebot
301 lines
8.7 KiB
JavaScript
301 lines
8.7 KiB
JavaScript
|
"use strict";
|
||
|
|
||
|
Object.defineProperty(exports, "__esModule", {
|
||
|
value: true
|
||
|
});
|
||
|
exports.default = void 0;
|
||
|
|
||
|
var _path = _interopRequireDefault(require("path"));
|
||
|
|
||
|
var _crypto = _interopRequireDefault(require("crypto"));
|
||
|
|
||
|
var _schemaUtils = require("schema-utils");
|
||
|
|
||
|
var _serializeJavascript = _interopRequireDefault(require("serialize-javascript"));
|
||
|
|
||
|
var _options = _interopRequireDefault(require("./options.json"));
|
||
|
|
||
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||
|
|
||
|
/*
|
||
|
MIT License http://www.opensource.org/licenses/mit-license.php
|
||
|
Author Tobias Koppers @sokra
|
||
|
*/
|
||
|
class CompressionPlugin {
|
||
|
constructor(options = {}) {
|
||
|
(0, _schemaUtils.validate)(_options.default, options, {
|
||
|
name: "Compression Plugin",
|
||
|
baseDataPath: "options"
|
||
|
});
|
||
|
const {
|
||
|
test,
|
||
|
include,
|
||
|
exclude,
|
||
|
algorithm = "gzip",
|
||
|
compressionOptions = {},
|
||
|
filename = "[path][base].gz",
|
||
|
threshold = 0,
|
||
|
minRatio = 0.8,
|
||
|
deleteOriginalAssets = false
|
||
|
} = options;
|
||
|
this.options = {
|
||
|
test,
|
||
|
include,
|
||
|
exclude,
|
||
|
algorithm,
|
||
|
compressionOptions,
|
||
|
filename,
|
||
|
threshold,
|
||
|
minRatio,
|
||
|
deleteOriginalAssets
|
||
|
};
|
||
|
this.algorithm = this.options.algorithm;
|
||
|
|
||
|
if (typeof this.algorithm === "string") {
|
||
|
// eslint-disable-next-line global-require
|
||
|
const zlib = require("zlib");
|
||
|
|
||
|
this.algorithm = zlib[this.algorithm];
|
||
|
|
||
|
if (!this.algorithm) {
|
||
|
throw new Error(`Algorithm "${this.options.algorithm}" is not found in "zlib"`);
|
||
|
}
|
||
|
|
||
|
const defaultCompressionOptions = {
|
||
|
gzip: {
|
||
|
level: zlib.constants.Z_BEST_COMPRESSION
|
||
|
},
|
||
|
deflate: {
|
||
|
level: zlib.constants.Z_BEST_COMPRESSION
|
||
|
},
|
||
|
deflateRaw: {
|
||
|
level: zlib.constants.Z_BEST_COMPRESSION
|
||
|
},
|
||
|
brotliCompress: {
|
||
|
params: {
|
||
|
[zlib.constants.BROTLI_PARAM_QUALITY]: zlib.constants.BROTLI_MAX_QUALITY
|
||
|
}
|
||
|
}
|
||
|
}[algorithm] || {};
|
||
|
this.options.compressionOptions = { ...defaultCompressionOptions,
|
||
|
...this.options.compressionOptions
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
runCompressionAlgorithm(input) {
|
||
|
return new Promise((resolve, reject) => {
|
||
|
this.algorithm(input, this.options.compressionOptions, (error, result) => {
|
||
|
if (error) {
|
||
|
return reject(error);
|
||
|
}
|
||
|
|
||
|
if (!Buffer.isBuffer(result)) {
|
||
|
// eslint-disable-next-line no-param-reassign
|
||
|
result = Buffer.from(result);
|
||
|
}
|
||
|
|
||
|
return resolve(result);
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
async compress(compiler, compilation, assets) {
|
||
|
const cache = compilation.getCache("CompressionWebpackPlugin");
|
||
|
const assetsForMinify = (await Promise.all(Object.keys(assets).map(async name => {
|
||
|
const {
|
||
|
info,
|
||
|
source
|
||
|
} = compilation.getAsset(name);
|
||
|
|
||
|
if (info.compressed) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (!compiler.webpack.ModuleFilenameHelpers.matchObject.bind( // eslint-disable-next-line no-undefined
|
||
|
undefined, this.options)(name)) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
let relatedName;
|
||
|
|
||
|
if (typeof this.options.algorithm === "function") {
|
||
|
if (typeof this.options.filename === "function") {
|
||
|
relatedName = `compression-function-${_crypto.default.createHash("md5").update((0, _serializeJavascript.default)(this.options.filename)).digest("hex")}`;
|
||
|
} else {
|
||
|
let filenameForRelatedName = this.options.filename;
|
||
|
const index = filenameForRelatedName.indexOf("?");
|
||
|
|
||
|
if (index >= 0) {
|
||
|
filenameForRelatedName = filenameForRelatedName.substr(0, index);
|
||
|
}
|
||
|
|
||
|
relatedName = `${_path.default.extname(filenameForRelatedName).slice(1)}ed`;
|
||
|
}
|
||
|
} else if (this.options.algorithm === "gzip") {
|
||
|
relatedName = "gzipped";
|
||
|
} else {
|
||
|
relatedName = `${this.options.algorithm}ed`;
|
||
|
}
|
||
|
|
||
|
if (info.related && info.related[relatedName]) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
const cacheItem = cache.getItemCache((0, _serializeJavascript.default)({
|
||
|
name,
|
||
|
algorithm: this.options.algorithm,
|
||
|
compressionOptions: this.options.compressionOptions
|
||
|
}), cache.getLazyHashedEtag(source));
|
||
|
const output = (await cacheItem.getPromise()) || {};
|
||
|
let buffer; // No need original buffer for cached files
|
||
|
|
||
|
if (!output.source) {
|
||
|
if (typeof source.buffer === "function") {
|
||
|
buffer = source.buffer();
|
||
|
} // Compatibility with webpack plugins which don't use `webpack-sources`
|
||
|
// See https://github.com/webpack-contrib/compression-webpack-plugin/issues/236
|
||
|
else {
|
||
|
buffer = source.source();
|
||
|
|
||
|
if (!Buffer.isBuffer(buffer)) {
|
||
|
// eslint-disable-next-line no-param-reassign
|
||
|
buffer = Buffer.from(buffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (buffer.length < this.options.threshold) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
name,
|
||
|
source,
|
||
|
info,
|
||
|
buffer,
|
||
|
output,
|
||
|
cacheItem,
|
||
|
relatedName
|
||
|
};
|
||
|
}))).filter(assetForMinify => Boolean(assetForMinify));
|
||
|
const {
|
||
|
RawSource
|
||
|
} = compiler.webpack.sources;
|
||
|
const scheduledTasks = [];
|
||
|
|
||
|
for (const asset of assetsForMinify) {
|
||
|
scheduledTasks.push((async () => {
|
||
|
const {
|
||
|
name,
|
||
|
source,
|
||
|
buffer,
|
||
|
output,
|
||
|
cacheItem,
|
||
|
info,
|
||
|
relatedName
|
||
|
} = asset;
|
||
|
|
||
|
if (!output.source) {
|
||
|
if (!output.compressed) {
|
||
|
try {
|
||
|
output.compressed = await this.runCompressionAlgorithm(buffer);
|
||
|
} catch (error) {
|
||
|
compilation.errors.push(error);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (output.compressed.length / buffer.length > this.options.minRatio) {
|
||
|
await cacheItem.storePromise({
|
||
|
compressed: output.compressed
|
||
|
});
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
output.source = new RawSource(output.compressed);
|
||
|
await cacheItem.storePromise(output);
|
||
|
}
|
||
|
|
||
|
const match = /^([^?#]*)(\?[^#]*)?(#.*)?$/.exec(name);
|
||
|
const [, replacerFile] = match;
|
||
|
const replacerQuery = match[2] || "";
|
||
|
const replacerFragment = match[3] || "";
|
||
|
|
||
|
const replacerExt = _path.default.extname(replacerFile);
|
||
|
|
||
|
const replacerBase = _path.default.basename(replacerFile);
|
||
|
|
||
|
const replacerName = replacerBase.slice(0, replacerBase.length - replacerExt.length);
|
||
|
const replacerPath = replacerFile.slice(0, replacerFile.length - replacerBase.length);
|
||
|
const pathData = {
|
||
|
file: replacerFile,
|
||
|
query: replacerQuery,
|
||
|
fragment: replacerFragment,
|
||
|
path: replacerPath,
|
||
|
base: replacerBase,
|
||
|
name: replacerName,
|
||
|
ext: replacerExt || ""
|
||
|
};
|
||
|
let newFilename = this.options.filename;
|
||
|
|
||
|
if (typeof newFilename === "function") {
|
||
|
newFilename = newFilename(pathData);
|
||
|
}
|
||
|
|
||
|
const newName = newFilename.replace(/\[(file|query|fragment|path|base|name|ext)]/g, (p0, p1) => pathData[p1]);
|
||
|
const newInfo = {
|
||
|
compressed: true
|
||
|
};
|
||
|
|
||
|
if (info.immutable && /(\[name]|\[base]|\[file])/.test(newFilename)) {
|
||
|
newInfo.immutable = true;
|
||
|
}
|
||
|
|
||
|
if (this.options.deleteOriginalAssets) {
|
||
|
if (this.options.deleteOriginalAssets === "keep-source-map") {
|
||
|
compilation.updateAsset(name, source, {
|
||
|
related: {
|
||
|
sourceMap: null
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
compilation.deleteAsset(name);
|
||
|
} else {
|
||
|
compilation.updateAsset(name, source, {
|
||
|
related: {
|
||
|
[relatedName]: newName
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
compilation.emitAsset(newName, output.source, newInfo);
|
||
|
})());
|
||
|
}
|
||
|
|
||
|
return Promise.all(scheduledTasks);
|
||
|
}
|
||
|
|
||
|
apply(compiler) {
|
||
|
const pluginName = this.constructor.name;
|
||
|
compiler.hooks.thisCompilation.tap(pluginName, compilation => {
|
||
|
compilation.hooks.processAssets.tapPromise({
|
||
|
name: pluginName,
|
||
|
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER,
|
||
|
additionalAssets: true
|
||
|
}, assets => this.compress(compiler, compilation, assets));
|
||
|
compilation.hooks.statsPrinter.tap(pluginName, stats => {
|
||
|
stats.hooks.print.for("asset.info.compressed").tap("compression-webpack-plugin", (compressed, {
|
||
|
green,
|
||
|
formatFlag
|
||
|
}) => // eslint-disable-next-line no-undefined
|
||
|
compressed ? green(formatFlag("compressed")) : undefined);
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
var _default = CompressionPlugin;
|
||
|
exports.default = _default;
|