index.js 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. var async = require("async");
  6. var url = require('url');
  7. var RawSource = require("webpack-sources/lib/RawSource");
  8. function CompressionPlugin(options) {
  9. options = options || {};
  10. this.asset = options.asset || "[path].gz[query]";
  11. this.algorithm = options.algorithm || "gzip";
  12. this.compressionOptions = {};
  13. if(typeof this.algorithm === "string") {
  14. if (this.algorithm === "zopfli") {
  15. try {
  16. var zopfli = require("node-zopfli");
  17. } catch(err) {
  18. throw new Error("node-zopfli not found");
  19. }
  20. this.compressionOptions = {
  21. verbose: options.hasOwnProperty('verbose') ? options.verbose : false,
  22. verbose_more: options.hasOwnProperty('verbose_more') ? options.verbose_more : false,
  23. numiterations: options.numiterations ? options.numiterations : 15,
  24. blocksplitting: options.hasOwnProperty('blocksplitting') ? options.blocksplitting : true,
  25. blocksplittinglast: options.hasOwnProperty('blocksplittinglast') ? options.blocksplittinglast : false,
  26. blocksplittingmax: options.blocksplittingmax ? options.blocksplittingmax : 15
  27. };
  28. this.algorithm = function (content, options, fn) {
  29. zopfli.gzip(content, options, fn);
  30. };
  31. } else {
  32. var zlib = require("zlib");
  33. this.algorithm = zlib[this.algorithm];
  34. if(!this.algorithm) throw new Error("Algorithm not found in zlib");
  35. this.compressionOptions = {
  36. level: options.level || 9,
  37. flush: options.flush,
  38. chunkSize: options.chunkSize,
  39. windowBits: options.windowBits,
  40. memLevel: options.memLevel,
  41. strategy: options.strategy,
  42. dictionary: options.dictionary
  43. };
  44. }
  45. }
  46. this.test = options.test || options.regExp;
  47. this.threshold = options.threshold || 0;
  48. this.minRatio = options.minRatio || 0.8;
  49. }
  50. module.exports = CompressionPlugin;
  51. CompressionPlugin.prototype.apply = function(compiler) {
  52. compiler.plugin("this-compilation", function(compilation) {
  53. compilation.plugin("optimize-assets", function(assets, callback) {
  54. async.forEach(Object.keys(assets), function(file, callback) {
  55. if(Array.isArray(this.test)) {
  56. if(this.test.every(function(t) {
  57. return !t.test(file);
  58. })) return callback();
  59. } else if(this.test && !this.test.test(file))
  60. return callback();
  61. var asset = assets[file];
  62. var content = asset.source();
  63. if(!Buffer.isBuffer(content))
  64. content = new Buffer(content, "utf-8");
  65. var originalSize = content.length;
  66. if(originalSize < this.threshold) return callback();
  67. this.algorithm(content, this.compressionOptions, function(err, result) {
  68. if(err) return callback(err);
  69. if(result.length / originalSize > this.minRatio) return callback();
  70. var parse = url.parse(file);
  71. var sub = {
  72. file: file,
  73. path: parse.pathname,
  74. query: parse.query || ""
  75. };
  76. var newFile = this.asset.replace(/\[(file|path|query)\]/g, function(p0,p1) {
  77. return sub[p1];
  78. });
  79. assets[newFile] = new RawSource(result);
  80. callback();
  81. }.bind(this));
  82. }.bind(this), callback);
  83. }.bind(this));
  84. }.bind(this));
  85. };