Framework-agnostic command-line tool: runs your build (or analyzes an existing folder), measures artifact sizes (raw, gzip, brotli), classifies files, generates rankings, and outputs an HTML/JSON report. It can optionally integrate dependency auditing based on your package manager (npm, pnpm, Yarn, Bun) and allows you to compare two Git branches in isolated environments (worktrees).
- Requirements
- Installation
- Getting started (5 minutes)
- Practical examples by stack
- CLI Commands
- Configuration file
- Outputs and reports
- Precedence: file vs flags
- CI/CD usage
- Comparing branches with Git
- Troubleshooting
- Development and npm publishing
- License
| Requirement | Detail |
|---|---|
| Node.js | 18 or higher (engines in package.json) |
| Git | Required only for the compare command |
| Network | Needed if you enable audit: true (queries package registry) |
Choose one of these methods depending on your workflow.
Ideal for trying it out or for one-off CI scripts:
npx bundlelens@latest --helpThe first run downloads the package; later runs may use npm cache.
Recommended for teams and reproducible pipelines:
npm install --save-dev bundlelensThen invoke the binary with npx or from package.json:
{
"scripts": {
"bundlelens": "bundlelens run",
"bundlelens:analyze": "bundlelens analyze"
}
}npm run bundlelensnpm install -g bundlelens
bundlelens --helpIf you contribute to the source code:
git clone <repo-url>
cd bundlelens
npm install
npm run build
node ./dist/cli/index.js --helpTo use the bundlelens command from the local tree without publishing:
npm link
# or
npx bundlelens --help # after npm pack / npm install ./pathIn your project root (where package.json is):
npx bundlelens initThis creates bundlelens.config.json with default values and, if .gitignore exists, adds an entry for the report folder (default bundlelens/), unless you use --skip-gitignore.
Open bundlelens.config.json and check:
buildCommand: the same command you would use in terminal to produce the build (e.g.npm run build,pnpm run build).buildDir: folder relative to the config file where artifacts are generated (e.g.dist,build,.next/outdepending on your stack).
npx bundlelens runIf you did not set buildCommand in the file, the tool can ask for it interactively (requires a TTY terminal).
After a successful run or analyze, open in your browser:
./bundlelens/index.html(path relative to your project; folder name depends onoutputDirin config).
The examples below assume you are in the project root and already installed bundlelens (npx or devDependency).
Typical case where artifacts are generated in dist/.
bundlelens.config.json
{
"buildCommand": "npm run build",
"buildDir": "dist",
"outputDir": "bundlelens",
"audit": true
}Run
npx bundlelens runAngular CLI usually outputs to dist/<project-name>/browser (Angular 17+) or dist/<project-name>.
bundlelens.config.json
{
"buildCommand": "npm run build",
"buildDir": "dist/my-angular-app/browser",
"outputDir": "bundlelens",
"audit": true
}If your output path is different, replace buildDir with the value configured in your angular.json.
Run
npx bundlelens runIonic builds for web commonly output to www/.
bundlelens.config.json
{
"buildCommand": "npm run build",
"buildDir": "www",
"outputDir": "bundlelens",
"audit": true
}Run
npx bundlelens runFor Create React App, output is typically build/. For Vite-based React, it is usually dist/.
bundlelens.config.json (CRA example)
{
"buildCommand": "npm run build",
"buildDir": "build",
"outputDir": "bundlelens",
"audit": true
}Run
npx bundlelens runFor Vite React, switch only:
{
"buildDir": "dist"
}If you use static export, the output folder is usually out/.
bundlelens.config.json (static export)
{
"buildCommand": "npm run build",
"buildDir": "out",
"outputDir": "bundlelens",
"audit": true
}Run
npx bundlelens runIf you want to analyze .next artifacts instead of export output:
npx bundlelens analyze .next --output bundlelens --no-auditUse these when you do not want to create bundlelens.config.json.
JavaScript (Vite/webpack generic):
npx bundlelens run "npm run build" --build-dir dist --output bundlelens --auditAngular:
npx bundlelens run "npm run build" --build-dir dist/my-angular-app/browser --output bundlelens --auditIonic:
npx bundlelens run "npm run build" --build-dir www --output bundlelens --auditReact (CRA):
npx bundlelens run "npm run build" --build-dir build --output bundlelens --auditReact (Vite):
npx bundlelens run "npm run build" --build-dir dist --output bundlelens --auditNext.js (static export):
npx bundlelens run "npm run build" --build-dir out --output bundlelens --auditNext.js (.next analysis only):
npx bundlelens analyze .next --output bundlelens --no-auditTip: if your CI job should fail when build fails, add --fail-on-build to the run commands.
Compare main vs your feature branch and get a side-by-side report:
npx bundlelens compare --base main --head feature/my-changeOpen:
bundlelens/compare/compare.html
General invocation:
bundlelens <command> [arguments] [options]If you run bundlelens with no arguments, help is shown and the process exits with a non-zero code (so scripts fail explicitly).
Creates bundlelens.config.json in the current directory and optionally updates .gitignore.
| Option | Description |
|---|---|
--force |
Overwrites bundlelens.config.json if it already exists. |
--skip-gitignore |
Does not modify .gitignore. |
--output <dir> |
Writes the outputDir value in config (JSON default: bundlelens). |
Examples:
bundlelens init
bundlelens init --output reports/bundlelens
bundlelens init --force --skip-gitignore- Optionally adjusts
.npmrcif lockfile consistency is needed (same logic ascompare). - If
node_modulesis missing butpackage.jsonexists, it can run or ask for an install command (depending on config and TTY). - Runs the build command in the project directory.
- Analyzes
buildDirand writes reports tooutputDir.
| Argument / option | Description |
|---|---|
[buildCommand] |
Build command (positional). If omitted and not present in config, can be requested interactively. |
--build-dir <dir> |
Build output folder to analyze. |
--output <dir> |
Folder to write reports (default ./bundlelens if not configured). |
--config <file> |
Path to a configuration JSON different from default. |
--audit |
Forces dependency audit even if config has audit: false. |
--no-audit |
Skips audit even if config has audit: true. |
--fail-on-build |
If build exits with code != 0, Node process inherits that exit code (subject to flags vs config policy). |
--no-fail-on-build |
Do not propagate build error code even if failOnBuild is true in config. |
Examples:
bundlelens run
bundlelens run "npm run build"
bundlelens run --build-dir dist --no-audit
bundlelens run --config ./config/bundlelens.config.jsonAnalyzes an already generated build folder (does not run the build command).
| Argument / option | Description |
|---|---|
[buildDir] |
Build path (positional). Practically equivalent to --build-dir. |
--build-dir <dir> |
Same as positional; useful in scripts. |
--output <dir> |
Report folder. |
--config <file> |
Configuration file. |
--audit / --no-audit |
Same behavior as run. |
Examples:
bundlelens analyze dist
bundlelens analyze --build-dir .nextBuilds and analyzes two Git refs (branches, tags, or commits) using temporary worktrees, then generates a comparison report.
Requirements: inside a Git repository; base and head must be different refs.
| Option | Description |
|---|---|
--base <ref> |
"Base" ref (reference). |
--head <ref> |
"Changes" ref / comparison target. |
--build-command <cmd> |
Build command override (per side; merged like in run). |
--build-dir <dir> |
Build folder override. |
--install-command <cmd> |
Install command when node_modules is missing (after config-defined command). |
--output <dir> |
Report root; compare output is written to <output>/compare/ (after merging with config outputDir). |
--config <file> |
Configuration file. |
--audit / --no-audit |
Explicit audit control. |
--fail-on-build / --no-fail-on-build |
Propagate build failures on one or both sides. |
If you do not pass --base / --head, you can define compare.baseBranch and compare.headBranch in config, or choose refs interactively when TTY is available.
Example:
bundlelens compare --base main --head feature/metricsThe default file is named bundlelens.config.json in the project root. You can validate it and get IDE autocomplete by pointing $schema to the schema included in the package:
{
"$schema": "./node_modules/bundlelens/bundlelens.schema.json",
"buildCommand": "npm run build",
"buildDir": "dist",
"outputDir": "bundlelens",
"audit": true,
"failOnBuild": false,
"compression": {
"gzip": true,
"brotli": true
},
"thresholds": {
"enabled": false,
"categories": {}
},
"compare": {
"baseBranch": "main",
"headBranch": "develop"
},
"install": {
"command": "npm ci"
}
}| Property | Type | Description |
|---|---|---|
$schema |
string | JSON Schema URI (recommended for IDE support). |
buildCommand |
string | Shell command for bundlelens run. |
buildDir |
string | Build output directory. Relative paths are resolved from the config file location. |
outputDir |
string | Report output folder (relative to project cwd when running CLI). |
audit |
boolean | If true, runs package-manager audit detected by lockfile. Tool behavior usually treats this as true unless specified otherwise in file/flags. |
failOnBuild |
boolean | If true, propagates build exit code on failure. |
compression |
object | gzip and brotli: compute compressed sizes per file during indexing. |
thresholds |
object | enabled and categories with limits by file type (maxFileRawBytes, maxFileGzipBytes, maxTotalRawBytes, maxTotalGzipBytes). |
compare |
object | Default baseBranch and headBranch for bundlelens compare. |
install |
object | command: non-interactive install when node_modules is missing (useful in CI). |
The exact list of keys and types is in bundlelens.schema.json in the published package.
After run or analyze, in outputDir (e.g. ./bundlelens/) you will typically find:
| File / folder | Content |
|---|---|
index.html |
Main report (metrics and links to other views). |
rankings.html |
Size rankings. |
files.html |
Per-file detail (only if files were indexed). |
report.json |
Same information as JSON (useful for pipelines). |
| Static assets | Shared CSS/JS generated next to HTML. |
After compare, under <outputDir>/compare/ (outputDir is the resolved config value + compare folder):
| File | Content |
|---|---|
compare.html |
Base vs head comparison view. |
compare-report.json |
Compare JSON payload. |
At the end, CLI prints useful absolute or relative paths so you can open or archive these files.
Current merge behavior (important for CI and scripts):
- It looks up and reads
bundlelens.config.json(or path from--config). buildCommand: if file hasbuildCommand, that value wins; otherwise CLI value is used (positional inrunor equivalent options incompare). Same??idea: file first, CLI fallback.outputDir: if file definesoutputDir, it wins over--output; if file does not define it, then flag is used and finally default (bundlelens).buildDir: if file definesbuildDir, it wins over--build-dir; if only CLI provides it, relative path resolves against config file directory when config exists on disk, otherwise against project cwd.auditandfailOnBuild: if key exists in JSON (eithertrueorfalse), file wins and flags--audit/--no-auditand--fail-on-build/--no-fail-on-buildapply only when key is not defined in file.
If you need CLI to always override (for example --no-audit in CI) and your JSON sets audit: true, you must remove or omit the audit key from JSON, or generate config without that property.
- No TTY: there are no interactive prompts. You should provide
buildCommand,buildDir, and, when needed,install.commandin config or flags. analyzeis ideal when another job already ran the build and you only want to measure artifacts.--no-auditspeeds up execution and avoids network dependency if you do not need vulnerability reporting in that job.
name: BundleLens
on: [push, pull_request]
jobs:
metrics:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
- run: npm ci
- run: npm run build
- run: npx bundlelens@latest analyze dist --output bundlelens --no-audit
- uses: actions/upload-artifact@v4
with:
name: bundlelens-report
path: bundlelens/Replace dist with your actual buildDir (build, out, etc.).
bundlelens compare:
- Creates Git worktrees in a temporary directory.
- In each worktree it can install dependencies and run the build.
- Writes the report under
.../compare/.
Best practices:
- Make sure
buildDirandbuildCommandare valid in both refs (or pass flags). - If
bundlelens.config.jsonis not tracked in Git, the code attempts to reuse config from your main working tree sobuildCommand/buildDirare not lost in the worktree.
| Symptom | What to check |
|---|---|
| 0 files indexed | Wrong buildDir, empty folder, or read permissions (on macOS you may need "Full Disk Access" for your terminal app). |
compare failure |
Are you in a Git repo? Are base and head different? Do you have network if using audit? |
| Empty audit or audit error | Connectivity, correct lockfile, package manager installed (pnpm, yarn, etc.). |
| Config not found | --config path or cwd where you launch command. |
ENOENT in buildDir |
Build did not generate output or path is relative to wrong base (config location vs cwd). |
For quick debugging: open report.json or compare-report.json and inspect metadata.analysisNotices when present.
For package maintainers.
| Script | Action |
|---|---|
npm run build |
Compiles TypeScript to dist/ (tsc). |
npm run dev |
tsc --watch for development. |
prepublishOnly |
Before publishing, npm runs npm run build automatically. |
dist/(compiled code).bundlelens.schema.json(schema for editors and documentation).
- Version updated in
package.json(npm version patch|minor|major). npm run buildruns without errors.- Test binary locally:
node dist/cli/index.js runin a sample project. - Log in to npm:
npm login. - Publish:
npm publish(add--access publicif scope requires it).
End users usually consume the already compiled package; TypeScript is not required in their projects to use the CLI.
MIT - see the repository LICENSE file if present, or the license field in package.json.
- Repository (code and issues): github.com/alejandrorodrom/bundlelens
- Author (LinkedIn): Alejandro Rodriguez Romero
- Config JSON Schema:
bundlelens.schema.json(in installed package root or repo root). - Terminal help:
bundlelens --help,bundlelens run --help, etc.
If anything in this README does not match your installed version, check version with:
bundlelens --version