Simple CLI tool that checks file(s) size and report if limits have been reached
npm install @node-cli/bundlesize!npm
> Bundlesize is a simple CLI tool that checks file(s) size and report if limits have been reached.
``sh`
> npm install --dev @node-cli/bundlesize
A configuration file must be provided via the -c parameter.
For IDE autocompletion and validation, you can use either JSDoc type hints or the defineConfig helper function.
#### Using JSDoc (recommended for JavaScript configs)
`js`
// @ts-check
/* @type {import('@node-cli/bundlesize').BundlesizeConfig} /
export default {
sizes: [
{
path: "dist/bundle.js",
limit: "10 kB"
}
]
};
#### Using defineConfig helper
`js
// @ts-check
import { defineConfig } from "@node-cli/bundlesize";
export default defineConfig({
sizes: [
{
path: "dist/bundle.js",
limit: "10 kB"
}
]
});
`
Both approaches provide:
- Autocompletion for configuration options
- Inline documentation for each property
- Type validation in your IDE
Note: The // @ts-check comment enables TypeScript checking for the file, which is required for validation errors to appear.
For the size option, it must export an object named "size" which is an array of objects with the following properties:
- path: the path to the file to checklimit
- : the limit to check against
For the report option, it must export an object named "report" which is an object with the following properties:
- header: the header to display (optional, string)footer
- : the footer to display (optional, function receiving a boolean indicating if the limit has been reached, and a value corresponding to the diff. It must return a string)previous
- : the previous path to the report to compare against (required, string)current
- : the current path to the report to compare against (required, string)columns
- : the columns to display (optional, array of objects)threshold
- : the minimum gzip size change in bytes to consider as a change (optional, number, defaults to 0). Changes below this threshold are treated as no change.
#### Single file
`js`
export default {
sizes: [
{
path: "dist/some-bundle.js",
limit: "10 kB"
}
]
};
#### Multiple files
`js`
export default {
sizes: [
{
path: "dist/some-bundle.js",
limit: "10 kB"
},
{
path: "dist/some-other-bundle.js",
limit: "100 kB"
}
]
};
#### With glob patterns
`js`
export default {
sizes: [
{
path: "dist/**/some-bundle.js",
limit: "10 kB"
},
{
path: "dist/*/some-other-bundle-.js",
limit: "100 kB"
},
{
path: "dist/**/extra-+([a-zA-Z0-9]).js",
limit: "100 kB"
}
]
};
#### With aliases
`js`
export default {
sizes: [
{
path: "dist/**/some-bundle.js",
limit: "10 kB",
alias: "Some bundle"
},
{
path: "dist/*/some-other-bundle-.js",
limit: "100 kB",
alias: "Some other bundle"
},
{
path: "dist/**/extra-+([a-zA-Z0-9]).js",
limit: "100 kB",
alias: "Extra bundle"
}
]
};
#### With a hash
The special keyword can be used to match a hash in the filename. It cannot used if multiple files match the pattern.
NOTE: Using is equivalent to using +([a-zA-Z0-9]) in the glob pattern. However, the result will be indexed with the hash key instead of the match key, so that subsequent scripts can use the hash value.
| Status | Pattern | Comment |
| ------ | ------------------------------- | ------------------------------------ |
| OK | dist/**/some-bundle- | If only one file matches the pattern |dist/**/same-prefix-
| Not OK | | If multiple files match the pattern |
#### With a version
The special keyword can be used to match a version in the filename. It cannot be used if multiple files match the pattern.
NOTE: Using is equivalent to using * in the glob pattern. However, the result will be indexed with the semver key instead of the match key, so that subsequent scripts can use the semver value.
| Status | Pattern | Comment |
| ------ | --------------------------------- | ------------------------------------ |
| OK | dist/**/some-bundle- | If only one file matches the pattern |dist/**/same-prefix-
| Not OK | | If multiple files match the pattern |
#### Simple report
`js`
export default {
report: {
prev: "stats/previous.json",
current: "stats/current.json"
}
};
#### Simple report with custom header
`js`
export default {
report: {
header: "## My custom header",
prev: "stats/previous.json",
current: "stats/current.json"
}
};
#### Simple report with custom footer
`js## My custom footer: ${limitReached} ${diff}
export default {
report: {
footer: (limitReached, diff) => {
return ;`
},
prev: "stats/previous.json",
current: "stats/current.json"
}
};
#### Simple report with custom columns
The columns option allows you to customize the report table columns. Each column is defined as an object with a key (column identifier) and value (column header text displayed in the table).
Available column keys:
| Key | Description | Default Header |
| -------- | ---------------------------------------------------- | -------------- |
| status | Shows ✅ if within limit, 🚫 if limit exceeded | "Status" |file
| | Displays the file name or alias | "File" |size
| | Shows the gzipped size with diff from previous stats | "Size (Gzip)" |limits
| | Displays the configured size limit | "Limits" |
Default columns:
`js`
columns: [
{ status: "Status" },
{ file: "File" },
{ size: "Size (Gzip)" },
{ limits: "Limits" }
];
Customizing column headers:
You can change the header text while keeping the same column:
`js`
export default {
report: {
columns: [
{ status: "✓/✗" },
{ file: "Bundle" },
{ size: "Gzip Size" },
{ limits: "Max" }
],
previous: "stats/previous.json",
current: "stats/current.json"
}
};
Removing columns:
You can remove columns by omitting them from the array:
`js`
export default {
report: {
columns: [{ file: "File" }, { size: "Size (Gzip)" }],
previous: "stats/previous.json",
current: "stats/current.json"
}
};
Reordering columns:
You can change the column order by rearranging the array:
`js`
export default {
report: {
columns: [
{ file: "File" },
{ status: "Status" },
{ limits: "Limits" },
{ size: "Size (Gzip)" }
],
previous: "stats/previous.json",
current: "stats/current.json"
}
};
#### Simple report with custom threshold
By default, all gzip size changes are reported. You can set a threshold to ignore small changes:
`js`
export default {
report: {
threshold: 10, // ignore changes smaller than 10 bytes
prev: "stats/previous.json",
current: "stats/current.json"
}
};
Note on threshold with subgroups: When using subgroup headers, the threshold is applied consistently. If individual file changes are below the threshold (and thus treated as zero), the sub-bundle total will also reflect this. For example, if file A changes by +3 bytes and file B changes by +4 bytes with a threshold of 5, both individual changes are ignored, and the sub-bundle will show no change (even though the raw total would be +7 bytes).
#### Report with subgroup headers (multiple tables)
You can interleave header objects inside the sizes array to break the report output into multiple markdown tables. Each header object must contain a header property (any markdown heading is allowed). A sub-bundle total line will be printed after each group along with its diff to previous stats (if available), followed by the overall bundle size and status at the end.
`js`
export default {
report: {
header: "## Bundle Size With Groups",
previous: "stats/previous.json",
current: "stats/current.json"
},
sizes: [
{ header: "### Core" },
{ path: "dist/core.js", limit: "20 kB" },
{ path: "dist/core-extra.js", limit: "10 kB" },
{ header: "### Widgets" },
{ path: "dist/widget-a.js", limit: "15 kB" },
{ path: "dist/widget-b.js", limit: "15 kB" }
]
};
Example output:
`Bundle Size With Groups
| Status | File | Size (Gzip) | Limits |
| --- | --- | --- | --- |
| ✅ | core.js | 12.34 KB (-1.2 KB -8.80%) | 20 kB |
| ✅ | core-extra.js | 3.21 KB | 10 kB |
Sub-bundle size: 15.55 KB (-1.2 KB -7.17%)
| Status | File | Size (Gzip) | Limits |
| --- | --- | --- | --- |
| ✅ | widget-a.js | 5.00 KB (+500 B +10.84%) | 15 kB |
| ✅ | widget-b.js | 4.50 KB | 15 kB |
Sub-bundle size: 9.50 KB (+500 B +5.56%)
Overall bundle size: 25.05 KB (-700 B -2.72%)
Overall status: ✅
`
Notes:
- If no header objects are present, the legacy single-table format is used (backwards compatible).
- Headers are rendered in the order they appear in sizes.
- Only size entries that resolve in the current stats are printed; missing ones are skipped silently.
- Sub-bundle diff lines only show percentage / size diff when previous stats for at least one file in the subgroup exist.
`json`
"scripts": {
"stats": "bundlesize -c bundlesize.config.js"
}
`json`
"scripts": {
"stats": "bundlesize -c bundlesize.config.js -o stats.json"
}
`json`
"scripts": {
"stats": "bundlesize -c bundlesize.config.js -o stats.json -s"
}
`json`
"scripts": {
"stats": "bundlesize -c bundlesize.config.js -o stats.json -p 'My prefix'"
}
`json`
"scripts": {
"stats": "bundlesize -c bundlesize.config.js -o stats.json -p \"$npm_package_version\""
}
`json`
"scripts": {
"stats": "bundlesize -c bundlesize.config.js --type report"
}
`sh``
> bundlesize --help
MIT © Arno Versini