Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ _Note: Gaps between patch versions are faulty, broken or test releases._

## UNRELEASED

* **Bug Fix**
* Prevent `TypeError` when `assets` or `modules` are undefined in `analyzer.js`
([#679](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/679) by [@Srushti-33](https://github.com/Srushti-33))


* **Breaking Change**
* Remove explicit support for Node versions below 20.9.0 ([#676](https://github.com/webpack-contrib/webpack-bundle-analyzer/pull/676) by [@valscion](https://github.com/valscion))

Expand Down
6 changes: 3 additions & 3 deletions src/analyzer.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function getViewerData(bundleStats, bundleDir, opts) {
}

// Picking only `*.js, *.cjs or *.mjs` assets from bundle that has non-empty `chunks` array
bundleStats.assets = bundleStats.assets.filter(asset => {
bundleStats.assets = (bundleStats.assets || []).filter(asset => {
// Filter out non 'asset' type asset if type is provided (Webpack 5 add a type to indicate asset types)
if (asset.type && asset.type !== 'asset') {
return false;
Expand Down Expand Up @@ -116,7 +116,7 @@ function getViewerData(bundleStats, bundleDir, opts) {
}

// Picking modules from current bundle script
let assetModules = modules.filter(statModule => assetHasModule(statAsset, statModule));
let assetModules = (modules || []).filter(statModule => assetHasModule(statAsset, statModule));

// Adding parsed sources
if (parsedModules) {
Expand All @@ -140,7 +140,7 @@ function getViewerData(bundleStats, bundleDir, opts) {
unparsedEntryModules[0].parsedSrc = assetSources.runtimeSrc;
} else {
// If there are multiple entry points we move all of them under synthetic concatenated module.
assetModules = assetModules.filter(mod => !unparsedEntryModules.includes(mod));
assetModules = (assetModules || []).filter(mod => !unparsedEntryModules.includes(mod));
assetModules.unshift({
identifier: './entry modules',
name: './entry modules',
Expand Down
55 changes: 55 additions & 0 deletions test/real-world-stats.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
const {expect} = require('chai');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's have this test use the same pattern we are using in https://github.com/webpack/webpack-bundle-analyzer/blob/main/test/analyzer.js which utilizes the stats.json files we have in https://github.com/webpack/webpack-bundle-analyzer/tree/main/test/stats. So don't create a new long test case for this but add one to the existing set we have.

For example this one:

it('should support stats files with modules inside `chunks` array', async function () {
generateReportFrom('with-modules-in-chunks/stats.json');
const chartData = await getChartData();
expect(chartData).to.containSubset(
require('./stats/with-modules-in-chunks/expected-chart-data')
);
});

The stats.json should be generated with some valid webpack configuration and you should let us know in the PR how that stats.json was generated. Generating that file through AI directly is not OK but it should be generated with some actual webpack config.

Such as the assets: false one that @alexander-akait said earlier.

const analyzer = require('../lib/analyzer');

describe('Real-world incomplete stats scenarios', function() {
it('should handle stats from minimal webpack config', function() {
const realWorldStats = {
version: "5.0.0",
hash: "abc123def456",
publicPath: "/dist/",
outputPath: "/project/dist",
chunks: [
{
id: 0,
names: ["main"],
files: ["main.js"],
hash: "abc123",
size: 1024
}
],
// Real-world scenario: assets array missing (common in minimal configs)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is not true, but yes you can set assets: false and we will not have the field

// Real-world scenario: modules array missing (some webpack versions)
errors: [],
warnings: [],
entrypoints: {
main: {
chunks: [0],
assets: ["main.js"]
}
}
};

expect(() => {
const result = analyzer.getViewerData(realWorldStats);
expect(result).to.be.an('array');
}).not.to.throw();
});

it('should handle stats with only essential webpack 5 fields', function() {
const webpack5MinimalStats = {
version: "5.0.0",
hash: "webpack5minimal",
publicPath: "/",
outputPath: "/build",
chunks: [],
entrypoints: {},
// Common real-world scenario: missing assets and modules
errors: [],
warnings: [],
namedChunkGroups: {}
};

const result = analyzer.getViewerData(webpack5MinimalStats);
expect(result).to.be.an('array').that.is.empty;
});
});