Skip to content

Commit

Permalink
Add compressionAlgorithm option
Browse files Browse the repository at this point in the history
  • Loading branch information
dcsaszar committed Apr 13, 2021
1 parent 4dfbb5c commit 6f12b2f
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 20 deletions.
17 changes: 10 additions & 7 deletions client/components/ModulesTreemap.jsx
Expand Up @@ -18,11 +18,13 @@ import Search from './Search';
import {store} from '../store';
import ModulesList from './ModulesList';

const SIZE_SWITCH_ITEMS = [
{label: 'Stat', prop: 'statSize'},
{label: 'Parsed', prop: 'parsedSize'},
{label: 'Gzipped', prop: 'gzipSize'}
];
function allSizeSwitchItems() {
return [
{label: 'Stat', prop: 'statSize'},
{label: 'Parsed', prop: 'parsedSize'},
{label: window.compressedSizeLabel, prop: 'gzipSize'}
];
}

@observer
export default class ModulesTreemap extends Component {
Expand Down Expand Up @@ -138,7 +140,7 @@ export default class ModulesTreemap extends Component {
renderModuleSize(module, sizeType) {
const sizeProp = `${sizeType}Size`;
const size = module[sizeProp];
const sizeLabel = SIZE_SWITCH_ITEMS.find(item => item.prop === sizeProp).label;
const sizeLabel = allSizeSwitchItems().find(item => item.prop === sizeProp).label;
const isActive = (store.activeSize === sizeProp);

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

@computed get sizeSwitchItems() {
return store.hasParsedSizes ? SIZE_SWITCH_ITEMS : SIZE_SWITCH_ITEMS.slice(0, 1);
const items = allSizeSwitchItems();
return store.hasParsedSizes ? items : items.slice(0, 1);
}

@computed get activeSizeItem() {
Expand Down
3 changes: 3 additions & 0 deletions src/BundleAnalyzerPlugin.js
Expand Up @@ -104,6 +104,7 @@ class BundleAnalyzerPlugin {
host: this.opts.analyzerHost,
port: this.opts.analyzerPort,
reportTitle: this.opts.reportTitle,
compressionAlgorithm: this.opts.compressionAlgorithm,
bundleDir: this.getBundleDirFromCompiler(),
logger: this.logger,
defaultSizes: this.opts.defaultSizes,
Expand All @@ -115,6 +116,7 @@ class BundleAnalyzerPlugin {
async generateJSONReport(stats) {
await viewer.generateJSONReport(stats, {
reportFilename: path.resolve(this.compiler.outputPath, this.opts.reportFilename || 'report.json'),
compressionAlgorithm: this.opts.compressionAlgorithm,
bundleDir: this.getBundleDirFromCompiler(),
logger: this.logger,
excludeAssets: this.opts.excludeAssets
Expand All @@ -126,6 +128,7 @@ class BundleAnalyzerPlugin {
openBrowser: this.opts.openAnalyzer,
reportFilename: path.resolve(this.compiler.outputPath, this.opts.reportFilename || 'report.html'),
reportTitle: this.opts.reportTitle,
compressionAlgorithm: this.opts.compressionAlgorithm,
bundleDir: this.getBundleDirFromCompiler(),
logger: this.logger,
defaultSizes: this.opts.defaultSizes,
Expand Down
12 changes: 10 additions & 2 deletions src/analyzer.js
Expand Up @@ -7,11 +7,16 @@ const Logger = require('./Logger');
const Folder = require('./tree/Folder').default;
const {parseBundle} = require('./parseUtils');
const {createAssetsFilter} = require('./utils');
const {gzipSize} = require('./sizeUtils');
const {gzipSize, brotliSize} = require('./sizeUtils');

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

const COMPRESSED_SIZE = {
gzip: gzipSize,
brotli: brotliSize
};

module.exports = {
getViewerData,
readStatsFromFile
Expand All @@ -21,11 +26,14 @@ function getViewerData(bundleStats, bundleDir, opts) {
const {
logger = new Logger(),
excludeAssets = null,
compressedSize = gzipSize
compressionAlgorithm
} = opts || {};

const isAssetIncluded = createAssetsFilter(excludeAssets);

const compressedSize = COMPRESSED_SIZE[compressionAlgorithm];
if (!compressedSize) throw new Error(`Unsupported compression algorithm: ${compressionAlgorithm}.`);

// Sometimes all the information is located in `children` array (e.g. problem in #10)
if (_.isEmpty(bundleStats.assets) && !_.isEmpty(bundleStats.children)) {
const {children} = bundleStats;
Expand Down
25 changes: 20 additions & 5 deletions src/bin/analyzer.js
Expand Up @@ -13,13 +13,15 @@ const utils = require('../utils');
const SIZES = new Set(['stat', 'parsed', 'compressed']);
const ACCEPTED_SIZES = new Set([...SIZES, 'gzip']);

const ALGORITHMS = new Set(['gzip', 'brotli']);

const program = commander
.version(require('../../package.json').version)
.usage(
`<bundleStatsFile> [bundleDir] [options]
`<bundleStatsFile> [bundleDir] [options]
Arguments:
bundleStatsFile Path to Webpack Stats JSON file.
bundleDir Directory containing all generated bundles.
You should provided it if you want analyzer to show you the real parsed module sizes.
Expand Down Expand Up @@ -56,17 +58,23 @@ const program = commander
.option(
'-s, --default-sizes <type>',
'Module sizes to show in treemap by default.' +
br(`Possible values: ${[...SIZES].join(', ')}`),
br(`Possible values: ${[...SIZES].join(', ')}`),
'parsed'
)
.option(
'--compression-algorithm <type>',
'Compression algorithm that will be used to calculate the compressed module sizes.' +
br(`Possible values: ${[...ALGORITHMS].join(', ')}`),
'gzip'
)
.option(
'-O, --no-open',
"Don't open report in default browser automatically."
)
.option(
'-e, --exclude <regexp>',
'Assets that should be excluded from the report.' +
br('Can be specified multiple times.'),
br('Can be specified multiple times.'),
array()
)
.option(
Expand All @@ -84,6 +92,7 @@ let {
report: reportFilename,
title: reportTitle,
defaultSizes,
compressionAlgorithm,
logLevel,
open: openBrowser,
exclude: excludeAssets,
Expand All @@ -108,6 +117,9 @@ if (mode === 'server') {
if (!ACCEPTED_SIZES.has(defaultSizes)) {
showHelp(`Invalid default sizes option. Possible values are: ${[...SIZES].join(', ')}`);
}
if (!ALGORITHMS.has(compressionAlgorithm)) {
showHelp(`Invalid compression algorithm option. Possible values are: ${[...ALGORITHMS].join(', ')}`);
}

bundleStatsFile = resolve(bundleStatsFile);

Expand All @@ -128,6 +140,7 @@ if (mode === 'server') {
port,
host,
defaultSizes,
compressionAlgorithm,
reportTitle,
bundleDir,
excludeAssets,
Expand All @@ -139,13 +152,15 @@ if (mode === 'server') {
reportFilename: resolve(reportFilename || 'report.html'),
reportTitle,
defaultSizes,
compressionAlgorithm,
bundleDir,
excludeAssets,
logger: new Logger(logLevel)
});
} else if (mode === 'json') {
viewer.generateJSONReport(bundleStats, {
reportFilename: resolve(reportFilename || 'report.json'),
compressionAlgorithm,
bundleDir,
excludeAssets,
logger: new Logger(logLevel)
Expand All @@ -159,7 +174,7 @@ function showHelp(error) {
}

function br(str) {
return `\n${' '.repeat(28)}${str}`;
return `\n${' '.repeat(32)}${str}`;
}

function array() {
Expand Down
3 changes: 2 additions & 1 deletion src/template.js
Expand Up @@ -39,7 +39,7 @@ function getScript(filename, mode) {
}
}

function renderViewer({title, enableWebSocket, chartData, defaultSizes, mode} = {}) {
function renderViewer({title, enableWebSocket, chartData, defaultSizes, compressedSizeLabel, mode} = {}) {
return html`<!DOCTYPE html>
<html>
<head>
Expand All @@ -59,6 +59,7 @@ function renderViewer({title, enableWebSocket, chartData, defaultSizes, mode} =
<script>
window.chartData = ${escapeJson(chartData)};
window.defaultSizes = ${escapeJson(defaultSizes)};
window.compressedSizeLabel = ${escapeJson(compressedSizeLabel)};
</script>
</body>
</html>`;
Expand Down
19 changes: 14 additions & 5 deletions src/viewer.js
Expand Up @@ -26,6 +26,10 @@ function resolveDefaultSizes(defaultSizes) {
return defaultSizes === 'compressed' ? 'gzip' : defaultSizes;
}

function resolveCompressedSizeLabel(compressionAlgorithm) {
return {gzip: 'Gzipped', brotli: 'Brotli'}[compressionAlgorithm];
}

module.exports = {
startServer,
generateReport,
Expand All @@ -43,10 +47,11 @@ async function startServer(bundleStats, opts) {
logger = new Logger(),
defaultSizes = 'parsed',
excludeAssets = null,
reportTitle
reportTitle,
compressionAlgorithm = 'gzip'
} = opts || {};

const analyzerOpts = {logger, excludeAssets};
const analyzerOpts = {logger, excludeAssets, compressionAlgorithm};

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

Expand All @@ -64,6 +69,7 @@ async function startServer(bundleStats, opts) {
title: resolveTitle(reportTitle),
chartData,
defaultSizes: resolveDefaultSizes(defaultSizes),
compressedSizeLabel: resolveCompressedSizeLabel(compressionAlgorithm),
enableWebSocket: true
});
res.writeHead(200, {'Content-Type': 'text/html'});
Expand Down Expand Up @@ -130,13 +136,14 @@ async function generateReport(bundleStats, opts) {
openBrowser = true,
reportFilename,
reportTitle,
compressionAlgorithm = 'gzip',
bundleDir = null,
logger = new Logger(),
defaultSizes = 'parsed',
excludeAssets = null
} = opts || {};

const chartData = getChartData({logger, excludeAssets}, bundleStats, bundleDir);
const chartData = getChartData({logger, excludeAssets, compressionAlgorithm}, bundleStats, bundleDir);

if (!chartData) return;

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

async function generateJSONReport(bundleStats, opts) {
const {reportFilename, bundleDir = null, logger = new Logger(), excludeAssets = null} = opts || {};
const {reportFilename, bundleDir = null, logger = new Logger(), excludeAssets = null,
compressionAlgorithm = 'gzip'} = opts || {};

const chartData = getChartData({logger, excludeAssets}, bundleStats, bundleDir);
const chartData = getChartData({logger, excludeAssets, compressionAlgorithm}, bundleStats, bundleDir);

if (!chartData) return;

Expand Down
22 changes: 22 additions & 0 deletions test/analyzer.js
Expand Up @@ -216,6 +216,23 @@ describe('Analyzer', function () {
expect(generatedReportTitle).to.match(/^webpack-bundle-analyzer \[.* at \d{2}:\d{2}\]/u);
});
});

describe('compression algorithm', function () {
it('should accept --compression-algorithm brotli', async function () {
generateReportFrom('with-modules-chunk.json', '--compression-algorithm brotli');
expect(await getCompressedSizeLabel()).to.equal('Brotli');
});

it('should accept --compression-algorithm gzip', async function () {
generateReportFrom('with-modules-chunk.json', '--compression-algorithm gzip');
expect(await getCompressedSizeLabel()).to.equal('Gzipped');
});

it('should default to gzip', async function () {
generateReportFrom('with-modules-chunk.json');
expect(await getCompressedSizeLabel()).to.equal('Gzipped');
});
});
});
});

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

async function getCompressedSizeLabel() {
return await nightmare.goto(`file://${__dirname}/output/report.html`).evaluate(
() => window.compressedSizeLabel);
}

function forEachChartItem(chartData, cb) {
for (const item of chartData) {
cb(item);
Expand Down
39 changes: 39 additions & 0 deletions test/plugin.js
Expand Up @@ -170,6 +170,45 @@ describe('Plugin', function () {
expect(error).to.equal(reportTitleError);
});
});

describe('compressionAlgorithm', function () {
it('should default to gzip', async function () {
const config = makeWebpackConfig({
analyzerOpts: {}
});
await webpackCompile(config, '4.44.2');
await expectValidReport({
parsedSize: 1311,
gzipSize: 342
});
});

it('should support gzip', async function () {
const config = makeWebpackConfig({
analyzerOpts: {
compressionAlgorithm: 'gzip'
}
});
await webpackCompile(config, '4.44.2');
await expectValidReport({
parsedSize: 1311,
gzipSize: 342
});
});

it('should support brotli', async function () {
const config = makeWebpackConfig({
analyzerOpts: {
compressionAlgorithm: 'brotli'
}
});
await webpackCompile(config, '4.44.2');
await expectValidReport({
parsedSize: 1311,
gzipSize: 302
});
});
});
});

async function expectValidReport(opts) {
Expand Down

0 comments on commit 6f12b2f

Please sign in to comment.