bun-image-optimizer
v0.1.9
Published
Bun CLI for safely optimizing web images and enforcing image budgets.
Maintainers
Readme
Bun Image Optimizer
bio is a fast Bun-powered image optimization CLI for web projects. It scans image folders, previews exact savings, writes optimized files with visible progress, and can enforce image budgets in CI.
It is built for teams that want image assets to stay small without turning every release into a manual image-compression chore.
Why bio
- Safe by default: same-format optimization is lossless-only unless you explicitly opt into lossy JPEG/WebP re-encoding.
- No surprise WebP files:
bio --write .optimizes existing files in place. New WebP files are created only with--webp. - Progress you can trust: write mode prints
[done/total] pathprogress for large folders. - Fast local runs: write concurrency defaults to available CPU count and can be tuned with
--concurrency. - CI-friendly: JSON reports, budget checks, and deterministic
--cimode. - Tiny install surface: powered by Bun's built-in image pipeline plus SVGO for SVGs.
Install
bun add -g bun-image-optimizerCheck the installed binary:
bio --versionRequires Bun >=1.3.14.
Quick Start
Preview optimizations:
bio ./publicWrite lossless same-format optimizations:
bio ./public --writeLimit CPU/disk pressure:
bio ./public --write --concurrency 4Generate WebP files beside supported source images:
bio ./public --webp --writeWrite generated files into a separate output directory:
bio ./public --webp --write --out ./optimizedWhat Gets Optimized
Default bio ./public --write is conservative:
| Input | Default behavior | | --- | --- | | PNG | lossless same-format optimization | | WebP | lossless same-format optimization | | SVG | SVGO optimization | | JPEG/JPG | skipped by default because Bun does not expose lossless JPEG optimization | | GIF | unsupported |
To intentionally re-encode JPEG/WebP with lossy settings:
bio ./public --write --lossy --jpeg-quality 82
bio ./public --webp --write --quality 80bio never writes outputs that are larger than the source unless you pass --no-skip-larger.
CI Usage
Print a machine-readable report:
bio ./public --ci --jsonFail if any image exceeds a per-file budget:
bio ./public --ci --json --max-size 500kb --fail-on-budgetFail if the whole image set exceeds a total budget:
bio ./public --ci --json --max-total-size 25mb --fail-on-budgetWrite a report artifact:
bio ./public --ci --json --report ./image-report.jsonExit codes:
| Code | Meaning |
| --- | --- |
| 0 | success |
| 2 | invalid CLI option |
| 3 | no images found |
| 4 | strict mode found failed or unsupported files |
| 5 | budget violation with --fail-on-budget |
Common Recipes
Optimize only assets:
bio ./public/assets --writePreview WebP generation without writing:
bio ./public --webpGenerate WebP into a separate folder:
bio ./public --webp --write --out ./public-webpUse include/exclude globs:
bio ./public --include "**/*.{png,webp,svg}" --exclude "**/legacy/**"Run a strict check in CI:
bio ./public --ci --json --strict --max-total-size 30mb --fail-on-budgetOptions
bio <path> [options]
--ci deterministic non-interactive CI mode
--dry-run preview only
--write apply write-capable operations
--json print JSON report
--report <file> write JSON report to file
--concurrency <n> write up to n files at once (default: CPU count)
--webp generate WebP files
--avif accepted for future AVIF support; AVIF writing is not enabled yet
--include <glob> include image glob
--exclude <glob> exclude image glob
--out <dir> write outputs to directory
--quality <n> lossy quality for generated formats
--jpeg-quality <n> JPEG quality for explicit lossy JPEG re-encoding
--webp-quality <n> WebP quality for explicit lossy WebP re-encoding
--lossless force lossless mode (default)
--lossy allow lossy re-encoding
--skip-larger skip outputs larger than source (default)
--no-skip-larger allow outputs larger than source
--max-size <size> check max per-file size
--max-total-size <size> check max total image size
--fail-on-budget exit 5 when budget is violated
--strict exit 4 when files are failed or unsupported
--no-recursive scan only the top-level input directory
-h, --help show help
-v, --version show versionConfig File
bio reads the first matching config file from the current working directory:
bio.config.tsbio.config.jsbio.config.json
Example:
{
"input": "public",
"concurrency": 4,
"exclude": ["**/node_modules/**", "**/.git/**", "**/legacy/**"],
"budget": {
"maxTotalSize": "30mb",
"failOnBudget": true
}
}CLI flags override config values.
Benchmark
Compare bio against @343dev/optimizt on an isolated copy of an image corpus:
bun run benchmark -- ./public/images --mode webp --out benchmark-results.jsonUse real project images for meaningful numbers. Tiny test fixtures are useful for correctness tests, not performance claims.
Download public-domain/CC0 benchmark fixtures:
bun run fixtures:downloadDevelopment
bun install
bun run dev -- ./public/images
bun test
bunx tsc --noEmitSee PRD.md for product requirements.
