brotliCompressor.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. var debug = require('debug')('ylt:brotliCompressor');
  2. var Q = require('q');
  3. var zlib = require('zlib');
  4. var gzipCompressor = require('./gzipCompressor');
  5. var GzipCompressor = function() {
  6. var BROTLI_COMPRESSION_LEVEL = 9;
  7. function compressFile(entry) {
  8. debug('Entering brotli compressor');
  9. return brotlifyFile(entry)
  10. .then(brotliOptimizedFile);
  11. }
  12. // Compress with Brotli files that were not compressed or not with brotli (with gzip or deflate)
  13. function brotlifyFile(entry) {
  14. var deferred = Q.defer();
  15. if (gzipCompressor.entryTypeCanBeCompressed(entry) && entry.weightCheck && entry.weightCheck.bodyBuffer) {
  16. if (!entry.weightCheck.isCompressed) {
  17. debug('File %s was not compressed at all, trying Brotli over it.', entry.url);
  18. } else if (entry.weightCheck.compressionTool !== 'brotli') {
  19. debug('File %s was compressed with %s. Trying with Brotli.', entry.url, entry.weightCheck.compressionTool);
  20. }
  21. zlib.brotliCompress(entry.weightCheck.bodyBuffer, {
  22. params: {
  23. [zlib.constants.BROTLI_PARAM_QUALITY]: 9
  24. }
  25. }, function(err, buffer) {
  26. if (err) {
  27. debug('Could not compress uncompressed file with brotli');
  28. debug(err);
  29. deferred.reject(err);
  30. } else {
  31. var compressedSize = buffer.length;
  32. if (!entry.weightCheck.isCompressed) {
  33. debug('Brotli size is %d, was %d, this is %d% better.', compressedSize, entry.weightCheck.bodySize, Math.round((entry.weightCheck.bodySize - compressedSize) * 100 / entry.weightCheck.bodySize));
  34. } else if (entry.weightCheck.compressionTool !== 'brotli') {
  35. debug('Brotli size is %d, was %d with %s, this is %d% better.', compressedSize, entry.weightCheck.bodySize, entry.weightCheck.compressionTool, Math.round((entry.weightCheck.bodySize - compressedSize) * 100 / entry.weightCheck.bodySize));
  36. }
  37. entry.weightCheck.afterBrotliCompression = compressedSize;
  38. deferred.resolve(entry);
  39. }
  40. }
  41. );
  42. } else {
  43. debug('Compression not needed');
  44. deferred.resolve(entry);
  45. }
  46. return deferred.promise;
  47. }
  48. // Gzip a file after minification or optimization if this step was successful
  49. function brotliOptimizedFile(entry) {
  50. var deferred = Q.defer();
  51. if (gzipCompressor.entryTypeCanBeCompressed(entry) && entry.weightCheck && entry.weightCheck.isOptimized === false) {
  52. debug('Trying to brotlify file after minification: %s', entry.url);
  53. var uncompressedSize = entry.weightCheck.optimized;
  54. zlib.brotliCompress(Buffer.from(entry.weightCheck.bodyAfterOptimization, 'utf8'), {
  55. params: {
  56. [zlib.constants.BROTLI_PARAM_QUALITY]: 9
  57. }
  58. }, function(err, buffer) {
  59. if (err) {
  60. debug('Could not compress minified file with brotli');
  61. debug(err);
  62. deferred.reject(err);
  63. } else {
  64. var compressedSize = buffer.length;
  65. debug('Correctly brotlified the minified file, was %d and is now %d bytes', uncompressedSize, compressedSize);
  66. entry.weightCheck.afterOptimizationAndBrotliCompression = compressedSize;
  67. deferred.resolve(entry);
  68. }
  69. }
  70. );
  71. } else {
  72. debug('Compressing optimized file not needed');
  73. deferred.resolve(entry);
  74. }
  75. return deferred.promise;
  76. }
  77. return {
  78. compressFile: compressFile
  79. };
  80. };
  81. module.exports = new GzipCompressor();