Skip to content

Commit 6f12b2f

Browse files
committed
Add compressionAlgorithm option
1 parent 4dfbb5c commit 6f12b2f

8 files changed

Lines changed: 120 additions & 20 deletions

File tree

client/components/ModulesTreemap.jsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ import Search from './Search';
1818
import {store} from '../store';
1919
import ModulesList from './ModulesList';
2020

21-
const SIZE_SWITCH_ITEMS = [
22-
{label: 'Stat', prop: 'statSize'},
23-
{label: 'Parsed', prop: 'parsedSize'},
24-
{label: 'Gzipped', prop: 'gzipSize'}
25-
];
21+
function allSizeSwitchItems() {
22+
return [
23+
{label: 'Stat', prop: 'statSize'},
24+
{label: 'Parsed', prop: 'parsedSize'},
25+
{label: window.compressedSizeLabel, prop: 'gzipSize'}
26+
];
27+
}
2628

2729
@observer
2830
export default class ModulesTreemap extends Component {
@@ -138,7 +140,7 @@ export default class ModulesTreemap extends Component {
138140
renderModuleSize(module, sizeType) {
139141
const sizeProp = `${sizeType}Size`;
140142
const size = module[sizeProp];
141-
const sizeLabel = SIZE_SWITCH_ITEMS.find(item => item.prop === sizeProp).label;
143+
const sizeLabel = allSizeSwitchItems().find(item => item.prop === sizeProp).label;
142144
const isActive = (store.activeSize === sizeProp);
143145

144146
return (typeof size === 'number') ?
@@ -162,7 +164,8 @@ export default class ModulesTreemap extends Component {
162164
};
163165

164166
@computed get sizeSwitchItems() {
165-
return store.hasParsedSizes ? SIZE_SWITCH_ITEMS : SIZE_SWITCH_ITEMS.slice(0, 1);
167+
const items = allSizeSwitchItems();
168+
return store.hasParsedSizes ? items : items.slice(0, 1);
166169
}
167170

168171
@computed get activeSizeItem() {

src/BundleAnalyzerPlugin.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class BundleAnalyzerPlugin {
104104
host: this.opts.analyzerHost,
105105
port: this.opts.analyzerPort,
106106
reportTitle: this.opts.reportTitle,
107+
compressionAlgorithm: this.opts.compressionAlgorithm,
107108
bundleDir: this.getBundleDirFromCompiler(),
108109
logger: this.logger,
109110
defaultSizes: this.opts.defaultSizes,
@@ -115,6 +116,7 @@ class BundleAnalyzerPlugin {
115116
async generateJSONReport(stats) {
116117
await viewer.generateJSONReport(stats, {
117118
reportFilename: path.resolve(this.compiler.outputPath, this.opts.reportFilename || 'report.json'),
119+
compressionAlgorithm: this.opts.compressionAlgorithm,
118120
bundleDir: this.getBundleDirFromCompiler(),
119121
logger: this.logger,
120122
excludeAssets: this.opts.excludeAssets
@@ -126,6 +128,7 @@ class BundleAnalyzerPlugin {
126128
openBrowser: this.opts.openAnalyzer,
127129
reportFilename: path.resolve(this.compiler.outputPath, this.opts.reportFilename || 'report.html'),
128130
reportTitle: this.opts.reportTitle,
131+
compressionAlgorithm: this.opts.compressionAlgorithm,
129132
bundleDir: this.getBundleDirFromCompiler(),
130133
logger: this.logger,
131134
defaultSizes: this.opts.defaultSizes,

src/analyzer.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@ const Logger = require('./Logger');
77
const Folder = require('./tree/Folder').default;
88
const {parseBundle} = require('./parseUtils');
99
const {createAssetsFilter} = require('./utils');
10-
const {gzipSize} = require('./sizeUtils');
10+
const {gzipSize, brotliSize} = require('./sizeUtils');
1111

1212
const FILENAME_QUERY_REGEXP = /\?.*$/u;
1313
const FILENAME_EXTENSIONS = /\.(js|mjs)$/iu;
1414

15+
const COMPRESSED_SIZE = {
16+
gzip: gzipSize,
17+
brotli: brotliSize
18+
};
19+
1520
module.exports = {
1621
getViewerData,
1722
readStatsFromFile
@@ -21,11 +26,14 @@ function getViewerData(bundleStats, bundleDir, opts) {
2126
const {
2227
logger = new Logger(),
2328
excludeAssets = null,
24-
compressedSize = gzipSize
29+
compressionAlgorithm
2530
} = opts || {};
2631

2732
const isAssetIncluded = createAssetsFilter(excludeAssets);
2833

34+
const compressedSize = COMPRESSED_SIZE[compressionAlgorithm];
35+
if (!compressedSize) throw new Error(`Unsupported compression algorithm: ${compressionAlgorithm}.`);
36+
2937
// Sometimes all the information is located in `children` array (e.g. problem in #10)
3038
if (_.isEmpty(bundleStats.assets) && !_.isEmpty(bundleStats.children)) {
3139
const {children} = bundleStats;

src/bin/analyzer.js

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ const utils = require('../utils');
1313
const SIZES = new Set(['stat', 'parsed', 'compressed']);
1414
const ACCEPTED_SIZES = new Set([...SIZES, 'gzip']);
1515

16+
const ALGORITHMS = new Set(['gzip', 'brotli']);
17+
1618
const program = commander
1719
.version(require('../../package.json').version)
1820
.usage(
19-
`<bundleStatsFile> [bundleDir] [options]
21+
`<bundleStatsFile> [bundleDir] [options]
2022
2123
Arguments:
22-
24+
2325
bundleStatsFile Path to Webpack Stats JSON file.
2426
bundleDir Directory containing all generated bundles.
2527
You should provided it if you want analyzer to show you the real parsed module sizes.
@@ -56,17 +58,23 @@ const program = commander
5658
.option(
5759
'-s, --default-sizes <type>',
5860
'Module sizes to show in treemap by default.' +
59-
br(`Possible values: ${[...SIZES].join(', ')}`),
61+
br(`Possible values: ${[...SIZES].join(', ')}`),
6062
'parsed'
6163
)
64+
.option(
65+
'--compression-algorithm <type>',
66+
'Compression algorithm that will be used to calculate the compressed module sizes.' +
67+
br(`Possible values: ${[...ALGORITHMS].join(', ')}`),
68+
'gzip'
69+
)
6270
.option(
6371
'-O, --no-open',
6472
"Don't open report in default browser automatically."
6573
)
6674
.option(
6775
'-e, --exclude <regexp>',
6876
'Assets that should be excluded from the report.' +
69-
br('Can be specified multiple times.'),
77+
br('Can be specified multiple times.'),
7078
array()
7179
)
7280
.option(
@@ -84,6 +92,7 @@ let {
8492
report: reportFilename,
8593
title: reportTitle,
8694
defaultSizes,
95+
compressionAlgorithm,
8796
logLevel,
8897
open: openBrowser,
8998
exclude: excludeAssets,
@@ -108,6 +117,9 @@ if (mode === 'server') {
108117
if (!ACCEPTED_SIZES.has(defaultSizes)) {
109118
showHelp(`Invalid default sizes option. Possible values are: ${[...SIZES].join(', ')}`);
110119
}
120+
if (!ALGORITHMS.has(compressionAlgorithm)) {
121+
showHelp(`Invalid compression algorithm option. Possible values are: ${[...ALGORITHMS].join(', ')}`);
122+
}
111123

112124
bundleStatsFile = resolve(bundleStatsFile);
113125

@@ -128,6 +140,7 @@ if (mode === 'server') {
128140
port,
129141
host,
130142
defaultSizes,
143+
compressionAlgorithm,
131144
reportTitle,
132145
bundleDir,
133146
excludeAssets,
@@ -139,13 +152,15 @@ if (mode === 'server') {
139152
reportFilename: resolve(reportFilename || 'report.html'),
140153
reportTitle,
141154
defaultSizes,
155+
compressionAlgorithm,
142156
bundleDir,
143157
excludeAssets,
144158
logger: new Logger(logLevel)
145159
});
146160
} else if (mode === 'json') {
147161
viewer.generateJSONReport(bundleStats, {
148162
reportFilename: resolve(reportFilename || 'report.json'),
163+
compressionAlgorithm,
149164
bundleDir,
150165
excludeAssets,
151166
logger: new Logger(logLevel)
@@ -159,7 +174,7 @@ function showHelp(error) {
159174
}
160175

161176
function br(str) {
162-
return `\n${' '.repeat(28)}${str}`;
177+
return `\n${' '.repeat(32)}${str}`;
163178
}
164179

165180
function array() {

src/template.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ function getScript(filename, mode) {
3939
}
4040
}
4141

42-
function renderViewer({title, enableWebSocket, chartData, defaultSizes, mode} = {}) {
42+
function renderViewer({title, enableWebSocket, chartData, defaultSizes, compressedSizeLabel, mode} = {}) {
4343
return html`<!DOCTYPE html>
4444
<html>
4545
<head>
@@ -59,6 +59,7 @@ function renderViewer({title, enableWebSocket, chartData, defaultSizes, mode} =
5959
<script>
6060
window.chartData = ${escapeJson(chartData)};
6161
window.defaultSizes = ${escapeJson(defaultSizes)};
62+
window.compressedSizeLabel = ${escapeJson(compressedSizeLabel)};
6263
</script>
6364
</body>
6465
</html>`;

src/viewer.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ function resolveDefaultSizes(defaultSizes) {
2626
return defaultSizes === 'compressed' ? 'gzip' : defaultSizes;
2727
}
2828

29+
function resolveCompressedSizeLabel(compressionAlgorithm) {
30+
return {gzip: 'Gzipped', brotli: 'Brotli'}[compressionAlgorithm];
31+
}
32+
2933
module.exports = {
3034
startServer,
3135
generateReport,
@@ -43,10 +47,11 @@ async function startServer(bundleStats, opts) {
4347
logger = new Logger(),
4448
defaultSizes = 'parsed',
4549
excludeAssets = null,
46-
reportTitle
50+
reportTitle,
51+
compressionAlgorithm = 'gzip'
4752
} = opts || {};
4853

49-
const analyzerOpts = {logger, excludeAssets};
54+
const analyzerOpts = {logger, excludeAssets, compressionAlgorithm};
5055

5156
let chartData = getChartData(analyzerOpts, bundleStats, bundleDir);
5257

@@ -64,6 +69,7 @@ async function startServer(bundleStats, opts) {
6469
title: resolveTitle(reportTitle),
6570
chartData,
6671
defaultSizes: resolveDefaultSizes(defaultSizes),
72+
compressedSizeLabel: resolveCompressedSizeLabel(compressionAlgorithm),
6773
enableWebSocket: true
6874
});
6975
res.writeHead(200, {'Content-Type': 'text/html'});
@@ -130,13 +136,14 @@ async function generateReport(bundleStats, opts) {
130136
openBrowser = true,
131137
reportFilename,
132138
reportTitle,
139+
compressionAlgorithm = 'gzip',
133140
bundleDir = null,
134141
logger = new Logger(),
135142
defaultSizes = 'parsed',
136143
excludeAssets = null
137144
} = opts || {};
138145

139-
const chartData = getChartData({logger, excludeAssets}, bundleStats, bundleDir);
146+
const chartData = getChartData({logger, excludeAssets, compressionAlgorithm}, bundleStats, bundleDir);
140147

141148
if (!chartData) return;
142149

@@ -145,6 +152,7 @@ async function generateReport(bundleStats, opts) {
145152
title: resolveTitle(reportTitle),
146153
chartData,
147154
defaultSizes: resolveDefaultSizes(defaultSizes),
155+
compressedSizeLabel: resolveCompressedSizeLabel(compressionAlgorithm),
148156
enableWebSocket: false
149157
});
150158
const reportFilepath = path.resolve(bundleDir || process.cwd(), reportFilename);
@@ -160,9 +168,10 @@ async function generateReport(bundleStats, opts) {
160168
}
161169

162170
async function generateJSONReport(bundleStats, opts) {
163-
const {reportFilename, bundleDir = null, logger = new Logger(), excludeAssets = null} = opts || {};
171+
const {reportFilename, bundleDir = null, logger = new Logger(), excludeAssets = null,
172+
compressionAlgorithm = 'gzip'} = opts || {};
164173

165-
const chartData = getChartData({logger, excludeAssets}, bundleStats, bundleDir);
174+
const chartData = getChartData({logger, excludeAssets, compressionAlgorithm}, bundleStats, bundleDir);
166175

167176
if (!chartData) return;
168177

test/analyzer.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,23 @@ describe('Analyzer', function () {
216216
expect(generatedReportTitle).to.match(/^webpack-bundle-analyzer \[.* at \d{2}:\d{2}\]/u);
217217
});
218218
});
219+
220+
describe('compression algorithm', function () {
221+
it('should accept --compression-algorithm brotli', async function () {
222+
generateReportFrom('with-modules-chunk.json', '--compression-algorithm brotli');
223+
expect(await getCompressedSizeLabel()).to.equal('Brotli');
224+
});
225+
226+
it('should accept --compression-algorithm gzip', async function () {
227+
generateReportFrom('with-modules-chunk.json', '--compression-algorithm gzip');
228+
expect(await getCompressedSizeLabel()).to.equal('Gzipped');
229+
});
230+
231+
it('should default to gzip', async function () {
232+
generateReportFrom('with-modules-chunk.json');
233+
expect(await getCompressedSizeLabel()).to.equal('Gzipped');
234+
});
235+
});
219236
});
220237
});
221238

@@ -241,6 +258,11 @@ async function getChartData() {
241258
return await nightmare.goto(`file://${__dirname}/output/report.html`).evaluate(() => window.chartData);
242259
}
243260

261+
async function getCompressedSizeLabel() {
262+
return await nightmare.goto(`file://${__dirname}/output/report.html`).evaluate(
263+
() => window.compressedSizeLabel);
264+
}
265+
244266
function forEachChartItem(chartData, cb) {
245267
for (const item of chartData) {
246268
cb(item);

test/plugin.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,45 @@ describe('Plugin', function () {
170170
expect(error).to.equal(reportTitleError);
171171
});
172172
});
173+
174+
describe('compressionAlgorithm', function () {
175+
it('should default to gzip', async function () {
176+
const config = makeWebpackConfig({
177+
analyzerOpts: {}
178+
});
179+
await webpackCompile(config, '4.44.2');
180+
await expectValidReport({
181+
parsedSize: 1311,
182+
gzipSize: 342
183+
});
184+
});
185+
186+
it('should support gzip', async function () {
187+
const config = makeWebpackConfig({
188+
analyzerOpts: {
189+
compressionAlgorithm: 'gzip'
190+
}
191+
});
192+
await webpackCompile(config, '4.44.2');
193+
await expectValidReport({
194+
parsedSize: 1311,
195+
gzipSize: 342
196+
});
197+
});
198+
199+
it('should support brotli', async function () {
200+
const config = makeWebpackConfig({
201+
analyzerOpts: {
202+
compressionAlgorithm: 'brotli'
203+
}
204+
});
205+
await webpackCompile(config, '4.44.2');
206+
await expectValidReport({
207+
parsedSize: 1311,
208+
gzipSize: 302
209+
});
210+
});
211+
});
173212
});
174213

175214
async function expectValidReport(opts) {

0 commit comments

Comments
 (0)