Skip to content

Commit

Permalink
Merge pull request #178 from webpack-contrib/exclude-assets
Browse files Browse the repository at this point in the history
Add option to exclude assets from the report
  • Loading branch information
th0r authored May 15, 2018
2 parents c9aa406 + a6cb49c commit 4016ab0
Show file tree
Hide file tree
Showing 10 changed files with 173 additions and 31 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ _Note: Gaps between patch versions are faulty, broken or test releases._

<!-- Add changelog entries for new changes under this section -->

* **New Feature**
* Add option that allows to exclude assets from the report ([#178](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/178))

## 2.11.3

* **Bug Fix**
Expand Down
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ new BundleAnalyzerPlugin(options?: object)
|**`generateStatsFile`**|`{Boolean}`|Default: `false`. If `true`, webpack stats JSON file will be generated in bundle output directory|
|**`statsFilename`**|`{String}`|Default: `stats.json`. Name of webpack stats JSON file that will be generated if `generateStatsFile` is `true`. Relative to bundle output directory.|
|**`statsOptions`**|`null` or `{Object}`|Default: `null`. Options for `stats.toJson()` method. For example you can exclude sources of your modules from stats file with `source: false` option. [See more options here](https://github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21). |
|**`excludeAssets`**|`{null\|pattern\|pattern[]}` where `pattern` equals to `{String\|RegExp\|function}`|Default: `null`. Patterns that will be used to match against asset names to exclude them from the report. If pattern is a string it will be converted to RegExp via `new RegExp(str)`. If pattern is a function it should have the following signature `(assetName: string) => boolean` and should return `true` to *exclude* matching asset. If multiple patterns are provided asset should match at least one of them to be excluded. |
|**`logLevel`**|One of: `info`, `warn`, `error`, `silent`|Default: `info`. Used to control how much details the plugin outputs.|

<h2 align="center">Usage (as a CLI utility)</h2>
Expand Down Expand Up @@ -106,22 +107,21 @@ Directory containing all generated bundles.
### `options`

```
-h, --help output usage information
-V, --version output the version number
-m, --mode <mode> Analyzer mode. Should be `server` or `static`.
In `server` mode analyzer will start HTTP server to show bundle report.
In `static` mode single HTML file with bundle report will be generated.
Default is `server`.
-h, --host <host> Host that will be used in `server` mode to start HTTP server.
Default is `127.0.0.1`.
-p, --port <n> Port that will be used in `server` mode to start HTTP server.
Default is 8888.
-r, --report <file> Path to bundle report file that will be generated in `static` mode.
Default is `report.html`.
In `static` mode single HTML file with bundle report will be generated. (default: server)
-h, --host <host> Host that will be used in `server` mode to start HTTP server. (default: 127.0.0.1)
-p, --port <n> Port that will be used in `server` mode to start HTTP server. (default: 8888)
-r, --report <file> Path to bundle report file that will be generated in `static` mode. (default: report.html)
-s, --default-sizes <type> Module sizes to show in treemap by default.
Possible values: stat, parsed, gzip
Default is `parsed`.
Possible values: stat, parsed, gzip (default: parsed)
-O, --no-open Don't open report in default browser automatically.
-e, --exclude <regexp> Assets that should be excluded from the report.
Can be specified multiple times.
-l, --log-level <level> Log level.
Possible values: debug, info, warn, error, silent (default: info)
-h, --help output usage information
```

<h2 align="center" id="size-definitions">Size definitions</h2>
Expand Down
7 changes: 5 additions & 2 deletions src/BundleAnalyzerPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class BundleAnalyzerPlugin {
generateStatsFile: false,
statsFilename: 'stats.json',
statsOptions: null,
excludeAssets: null,
logLevel: 'info',
// deprecated
startAnalyzer: true,
Expand Down Expand Up @@ -100,7 +101,8 @@ class BundleAnalyzerPlugin {
port: this.opts.analyzerPort,
bundleDir: this.getBundleDirFromCompiler(),
logger: this.logger,
defaultSizes: this.opts.defaultSizes
defaultSizes: this.opts.defaultSizes,
excludeAssets: this.opts.excludeAssets
});
}
}
Expand All @@ -111,7 +113,8 @@ class BundleAnalyzerPlugin {
reportFilename: path.resolve(this.compiler.outputPath, this.opts.reportFilename),
bundleDir: this.getBundleDirFromCompiler(),
logger: this.logger,
defaultSizes: this.opts.defaultSizes
defaultSizes: this.opts.defaultSizes,
excludeAssets: this.opts.excludeAssets
});
}

Expand Down
8 changes: 6 additions & 2 deletions src/analyzer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const gzipSize = require('gzip-size');
const Logger = require('./Logger');
const Folder = require('./tree/Folder').default;
const { parseBundle } = require('./parseUtils');
const { createAssetsFilter } = require('./utils');

const FILENAME_QUERY_REGEXP = /\?.*$/;

Expand All @@ -17,9 +18,12 @@ module.exports = {

function getViewerData(bundleStats, bundleDir, opts) {
const {
logger = new Logger()
logger = new Logger(),
excludeAssets = null
} = opts || {};

const isAssetIncluded = createAssetsFilter(excludeAssets);

// Sometimes all the information is located in `children` array (e.g. problem in #10)
if (_.isEmpty(bundleStats.assets) && !_.isEmpty(bundleStats.children)) {
bundleStats = bundleStats.children[0];
Expand All @@ -31,7 +35,7 @@ function getViewerData(bundleStats, bundleDir, opts) {
// See #22
asset.name = asset.name.replace(FILENAME_QUERY_REGEXP, '');

return _.endsWith(asset.name, '.js') && !_.isEmpty(asset.chunks);
return _.endsWith(asset.name, '.js') && !_.isEmpty(asset.chunks) && isAssetIncluded(asset.name);
});

// Trying to parse bundle assets and get real module sizes if `bundleDir` is provided
Expand Down
17 changes: 17 additions & 0 deletions src/bin/analyzer.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ const program = commander
'-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.'),
array()
)
.option(
'-l, --log-level <level>',
'Log level.' +
Expand All @@ -73,6 +79,7 @@ let {
defaultSizes,
logLevel,
open: openBrowser,
exclude: excludeAssets,
args: [bundleStatsFile, bundleDir]
} = program;
const logger = new Logger(logLevel);
Expand Down Expand Up @@ -103,6 +110,7 @@ if (mode === 'server') {
host,
defaultSizes,
bundleDir,
excludeAssets,
logger: new Logger(logLevel)
});
} else {
Expand All @@ -111,6 +119,7 @@ if (mode === 'server') {
reportFilename: resolve(reportFilename),
defaultSizes,
bundleDir,
excludeAssets,
logger: new Logger(logLevel)
});
}
Expand All @@ -124,3 +133,11 @@ function showHelp(error) {
function br(str) {
return `\n${_.repeat(' ', 28)}${str}`;
}

function array() {
const arr = [];
return (val) => {
arr.push(val);
return arr;
};
}
34 changes: 34 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
const { inspect } = require('util');
const _ = require('lodash');

exports.createAssetsFilter = createAssetsFilter;

function createAssetsFilter(excludePatterns) {
const excludeFunctions = _(excludePatterns)
.castArray()
.compact()
.map(pattern => {
if (typeof pattern === 'string') {
pattern = new RegExp(pattern);
}

if (_.isRegExp(pattern)) {
return (asset) => pattern.test(asset);
}

if (!_.isFunction(pattern)) {
throw new TypeError(
`Pattern should be either string, RegExp or a function, but "${inspect(pattern, { depth: 0 })}" got.`
);
}

return pattern;
})
.value();

if (excludeFunctions.length) {
return (asset) => _.every(excludeFunctions, fn => fn(asset) !== true);
} else {
return () => true;
}
}
21 changes: 13 additions & 8 deletions src/viewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@ async function startServer(bundleStats, opts) {
openBrowser = true,
bundleDir = null,
logger = new Logger(),
defaultSizes = 'parsed'
defaultSizes = 'parsed',
excludeAssets = null
} = opts || {};

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

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

if (!chartData) return;

Expand Down Expand Up @@ -90,7 +93,7 @@ async function startServer(bundleStats, opts) {
};

function updateChartData(bundleStats) {
const newChartData = getChartData(logger, bundleStats, bundleDir);
const newChartData = getChartData(analyzerOpts, bundleStats, bundleDir);

if (!newChartData) return;

Expand All @@ -113,10 +116,11 @@ function generateReport(bundleStats, opts) {
reportFilename = 'report.html',
bundleDir = null,
logger = new Logger(),
defaultSizes = 'parsed'
defaultSizes = 'parsed',
excludeAssets = null
} = opts || {};

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

if (!chartData) return;

Expand Down Expand Up @@ -151,18 +155,19 @@ function getAssetContent(filename) {
return fs.readFileSync(`${projectRoot}/public/${filename}`, 'utf8');
}

function getChartData(logger, ...args) {
function getChartData(analyzerOpts, ...args) {
let chartData;
const { logger } = analyzerOpts;

try {
chartData = analyzer.getViewerData(...args, { logger });
chartData = analyzer.getViewerData(...args, analyzerOpts);
} catch (err) {
logger.error(`Could't analyze webpack bundle:\n${err}`);
logger.debug(err.stack);
chartData = null;
}

if (_.isEmpty(chartData)) {
if (_.isPlainObject(chartData) && _.isEmpty(chartData)) {
logger.error("Could't find any javascript bundles in provided stats file");
chartData = null;
}
Expand Down
8 changes: 4 additions & 4 deletions test/helpers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const chai = require('chai');
const webpack = require('webpack');
const _ = require('lodash');

chai.use(require('chai-subset'));

Expand All @@ -17,16 +18,15 @@ function webpackCompile(config) {
}

function makeWebpackConfig(opts) {
opts = {
opts = _.merge({
analyzerOpts: {
analyzerMode: 'static',
openAnalyzer: false,
logLevel: 'error'
},
minify: false,
multipleChunks: false,
...opts
};
multipleChunks: false
}, opts);

return {
context: __dirname,
Expand Down
28 changes: 24 additions & 4 deletions test/webpack-configs.js → test/plugin.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
const fs = require('fs');
const del = require('del');
const _ = require('lodash');

let nightmare;

describe('Webpack config', function () {
describe('Plugin', function () {
let clock;

this.timeout(3000);
Expand All @@ -28,7 +29,7 @@ describe('Webpack config', function () {
clock.restore();
});

it('with query in bundle filename should be supported', async function () {
it('should support webpack config with query in bundle filename', async function () {
const config = makeWebpackConfig();

config.output.filename = 'bundle.js?what=is-this-for';
Expand All @@ -39,7 +40,7 @@ describe('Webpack config', function () {
await expectValidReport();
});

it('with custom `jsonpFunction` name should be supported', async function () {
it('should support webpack config with custom `jsonpFunction` name', async function () {
const config = makeWebpackConfig({
multipleChunks: true
});
Expand All @@ -55,7 +56,7 @@ describe('Webpack config', function () {
});
});

it('with `multi` module should be supported', async function () {
it('should support webpack config with `multi` module', async function () {
const config = makeWebpackConfig();

config.entry.bundle = [
Expand All @@ -73,6 +74,25 @@ describe('Webpack config', function () {
groups: undefined
}]);
});

describe('options', function () {
describe('excludeAssets', function () {
it('should filter out assets from the report', async function () {
const config = makeWebpackConfig({
multipleChunks: true,
analyzerOpts: {
excludeAssets: 'manifest'
}
});

await webpackCompile(config);
clock.tick(1);

const chartData = await getChartDataFromReport();
expect(_.map(chartData, 'label')).not.to.include('manifest.js');
});
});
});
});

async function expectValidReport(opts) {
Expand Down
Loading

0 comments on commit 4016ab0

Please sign in to comment.