@@ -18,7 +18,7 @@ import path from 'path';
18
18
import promisify from 'util.promisify' ;
19
19
import globPromise from 'glob' ;
20
20
import minimatch from 'minimatch' ;
21
- import gzipSize from 'gzip-size ' ;
21
+ import zlib from 'zlib ' ;
22
22
import chalk from 'chalk' ;
23
23
import prettyBytes from 'pretty-bytes' ;
24
24
import escapeRegExp from 'escape-string-regexp' ;
@@ -29,6 +29,15 @@ import fs from 'fs-extra';
29
29
const glob = promisify ( globPromise ) ;
30
30
const NAME = 'SizePlugin' ;
31
31
32
+ const GZIP_OPTS = {
33
+ level : 9
34
+ } ;
35
+ const BROTLI_OPTS = {
36
+ params : {
37
+ [ zlib . constants . BROTLI_PARAM_QUALITY ] : zlib . constants . BROTLI_MAX_QUALITY
38
+ }
39
+ } ;
40
+
32
41
/**
33
42
* `new SizePlugin(options)`
34
43
* @param {Object } options
@@ -38,6 +47,7 @@ const NAME = 'SizePlugin';
38
47
* @param {boolean } [options.publish] option to publish filesizes to size-plugin-store
39
48
* @param {boolean } [options.writeFile] option to save filesizes to disk
40
49
* @param {function } [options.stripHash] custom function to remove/normalize hashed filenames for comparison
50
+ * @param {'none' | 'gzip' | 'brotli' } [options.compression = 'gzip'] change the compression algorithm used for calculated sizes
41
51
* @param {string } [options.mode] custom Webpack "mode" - only use this to emulate "mode" in Webpack 3.
42
52
* @param {(item:Item)=>string? } [options.decorateItem] custom function to decorate items
43
53
* @param {(data:Data)=>string? } [options.decorateAfter] custom function to decorate all output
@@ -48,6 +58,7 @@ export default class SizePlugin {
48
58
this . options = options || { } ;
49
59
this . pattern = this . options . pattern || '**/*.{mjs,js,css,html}' ;
50
60
this . exclude = this . options . exclude ;
61
+ this . compression = this . options . compression || 'gzip' ;
51
62
this . options . filename = this . options . filename || 'size-plugin.json' ;
52
63
this . options . writeFile = this . options . writeFile !== false ;
53
64
this . filename = path . join ( process . cwd ( ) , this . options . filename ) ;
@@ -191,7 +202,7 @@ export default class SizePlugin {
191
202
file => isMatched ( file ) && ! isExcluded ( file )
192
203
) ;
193
204
const sizes = await Promise . all (
194
- assetNames . map ( name => gzipSize ( assets [ name ] . source ( ) ) )
205
+ assetNames . map ( name => this . getCompressedSize ( assets [ name ] . source ( ) ) )
195
206
) ;
196
207
197
208
// map of de-hashed filenames to their final size
@@ -271,11 +282,29 @@ export default class SizePlugin {
271
282
const files = await glob ( this . pattern , { cwd, ignore : this . exclude } ) ;
272
283
273
284
const sizes = await Promise . all (
274
- files . map ( file => gzipSize . file ( path . join ( cwd , file ) ) . catch ( ( ) => null ) )
285
+ files . map ( async file => {
286
+ const source = await fs . promises . readFile ( path . join ( cwd , file ) ) . catch ( ( ) => null ) ;
287
+ if ( source == null ) return null ;
288
+ return this . getCompressedSize ( source ) ;
289
+ } )
275
290
) ;
276
291
277
292
return toMap ( files . map ( filename => this . stripHash ( filename ) ) , sizes ) ;
278
293
}
294
+
295
+ async getCompressedSize ( source ) {
296
+ let compressed = source ;
297
+ if ( this . compression === 'gzip' ) {
298
+ const gz = promisify ( zlib . gzip ) ;
299
+ compressed = await gz ( source , GZIP_OPTS ) ;
300
+ }
301
+ else if ( this . compression === 'brotli' ) {
302
+ if ( ! zlib . brotliCompress ) throw Error ( 'Brotli not supported in this Node version.' ) ;
303
+ const br = promisify ( zlib . brotliCompress ) ;
304
+ compressed = await br ( source , BROTLI_OPTS ) ;
305
+ }
306
+ return Buffer . byteLength ( compressed ) ;
307
+ }
279
308
}
280
309
281
310
0 commit comments