'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _crypto = require('crypto');
var _crypto2 = _interopRequireDefault(_crypto);
var _url = require('url');
var _url2 = _interopRequireDefault(_url);
var _neoAsync = require('neo-async');
var _neoAsync2 = _interopRequireDefault(_neoAsync);
var _RawSource = require('webpack-sources/lib/RawSource');
var _RawSource2 = _interopRequireDefault(_RawSource);
var _ModuleFilenameHelpers = require('webpack/lib/ModuleFilenameHelpers');
var _ModuleFilenameHelpers2 = _interopRequireDefault(_ModuleFilenameHelpers);
var _cacache = require('cacache');
var _cacache2 = _interopRequireDefault(_cacache);
var _findCacheDir = require('find-cache-dir');
var _findCacheDir2 = _interopRequireDefault(_findCacheDir);
var _serializeJavascript = require('serialize-javascript');
var _serializeJavascript2 = _interopRequireDefault(_serializeJavascript);
var _schemaUtils = require('schema-utils');
var _schemaUtils2 = _interopRequireDefault(_schemaUtils);
var _package = require('../package.json');
var _package2 = _interopRequireDefault(_package);
var _options = require('./options.json');
var _options2 = _interopRequireDefault(_options);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
class CompressionPlugin {
constructor(options = {}) {
(0, _schemaUtils2.default)(_options2.default, options, 'Compression Plugin');
const {
test,
include,
exclude,
cache = false,
algorithm = 'gzip',
compressionOptions = {},
filename = '[path].gz[query]',
threshold = 0,
minRatio = 0.8,
deleteOriginalAssets = false
} = options;
this.options = {
test,
include,
exclude,
cache,
algorithm,
compressionOptions,
filename,
threshold,
minRatio,
deleteOriginalAssets
};
if (typeof algorithm === 'string') {
// eslint-disable-next-line global-require
const zlib = require('zlib');
this.options.algorithm = zlib[this.options.algorithm];
if (!this.options.algorithm) {
throw new Error('Algorithm not found in zlib');
}
const defaultCompressionOptions = { level: 9 };
this.options.compressionOptions = Object.assign({}, defaultCompressionOptions, this.options.compressionOptions);
}
}
apply(compiler) {
const emit = (compilation, callback) => {
const {
cache,
threshold,
minRatio,
filename,
deleteOriginalAssets
} = this.options;
const cacheDir = cache === true ? (0, _findCacheDir2.default)({ name: 'compression-webpack-plugin' }) : cache;
const { assets } = compilation;
// eslint-disable-next-line consistent-return
_neoAsync2.default.forEach(Object.keys(assets), (file, cb) => {
if (!_ModuleFilenameHelpers2.default.matchObject(this.options, file)) {
return cb();
}
const asset = assets[file];
let input = asset.source();
if (!Buffer.isBuffer(input)) {
input = Buffer.from(input);
}
const originalSize = input.length;
if (originalSize < threshold) {
return cb();
}
return Promise.resolve().then(() => {
if (cache) {
const { outputPath } = compiler;
const cacheKey = (0, _serializeJavascript2.default)({
// Invalidate cache after upgrade `zlib` module (build-in in `nodejs`)
node: process.version,
'compression-webpack-plugin': _package2.default.version,
'compression-webpack-plugin-options': this.options,
path: `${outputPath ? `${outputPath}/` : ''}${file}`,
hash: _crypto2.default.createHash('md4').update(input).digest('hex')
});
return _cacache2.default.get(cacheDir, cacheKey).then(result => result.data, () => Promise.resolve().then(() => this.compress(input)).then(data => _cacache2.default.put(cacheDir, cacheKey, data).then(() => data)));
}
return this.compress(input);
}).then(result => {
if (result.length / originalSize > minRatio) {
return cb();
}
const parse = _url2.default.parse(file);
const info = {
file,
path: parse.pathname,
query: parse.query ? `?${parse.query}` : ''
};
const newAssetName = typeof filename === 'function' ? filename(info) : filename.replace(/\[(file|path|query)\]/g, (p0, p1) => info[p1]);
assets[newAssetName] = new _RawSource2.default(result);
if (deleteOriginalAssets) {
delete assets[file];
}
return cb();
}).catch(error => {
compilation.errors.push(error);
return cb();
});
}, callback);
};
compiler.hooks.emit.tapAsync({ name: 'CompressionPlugin' }, emit);
}
compress(input) {
return new Promise((resolve, reject) => {
const { algorithm, compressionOptions } = this.options;
algorithm(input, compressionOptions, (error, result) => {
if (error) {
return reject(error);
}
return resolve(result);
});
});
}
} /*
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
exports.default = CompressionPlugin;