@nometria-ai/img-opt
v2.1.1
Published
Auto-scan, download, compress (WebP + WebM), and rewrite image & video URLs. Zero config.
Downloads
569
Maintainers
Readme
img-opt
Auto-scan your codebase for external images & videos, compress to WebP/WebM, rewrite all URLs. Zero config.
Eliminates external media dependencies, cuts image payload by 60-80%, compresses videos to WebM, and updates every URL reference in your source automatically. Works with Vite, Next.js, Astro, Vue, and Svelte projects.
Quick start
# Install
npm install --save-dev @nometria-ai/img-opt sharp
# Run — that's it. No config file needed.
npx img-optimg-opt auto-scans your src/ directory for external image and video URLs, downloads them, compresses images to WebP and videos to WebM, then rewrites every URL reference.
What's new in v2.0
- Auto-scan — no more manual
sourcesconfig. img-opt discovers external URLs automatically. - Video support — download and compress videos to WebM via ffmpeg.
- Zero-config — works without
image-assets.config.js. Sensible defaults for all settings.
Install
# As a dev dependency (recommended)
npm install --save-dev @nometria-ai/img-opt sharp
# For video compression, install ffmpeg:
# macOS: brew install ffmpeg
# Ubuntu: sudo apt install ffmpeg
# Windows: choco install ffmpeg
sharpis a peer dependency for image compression.ffmpegis a system dependency for video compression. Both are optional — the pipeline skips steps gracefully if they're missing.
Commands
npx img-opt # full pipeline (scan → download → compress → replace)
npx img-opt scan # discover external image/video URLs (dry-run)
npx img-opt download # fetch external images + videos
npx img-opt compress # convert PNG/JPG → WebP via Sharp
npx img-opt video # convert MP4/MOV → WebM via ffmpeg
npx img-opt replace # rewrite external URLs in source filesAdd to package.json scripts:
{
"scripts": {
"optimize": "img-opt",
"optimize:scan": "img-opt scan"
}
}How it works
Auto-scan (new in v2.0)
When no sources are configured, img-opt scans your codebase and detects:
<img src="https://...">and<Image src="...">(React, Next.js)<video src="...">,<source src="...">,poster="..."- CSS
url(https://...) - Markdown
 - String literals containing image/video URLs (
.png,.jpg,.mp4, etc.) srcsetattribute entries
Run npx img-opt scan to preview what will be found before downloading.
Local asset compression
Even without external URLs, img-opt compresses local uncompressed images and videos already in your project. It scans src/, public/, and any configured replaceInDirs for .png, .jpg, .mp4, etc., compresses them in place, and rewrites all references.
This means dropping a .png into src/assets/ and running npx img-opt will automatically convert it to .webp and update your imports. Set compressLocal: false to disable.
Ignore patterns
Use the ignore config to skip certain URLs or file paths:
export default {
ignore: [
'cdn.dynamic-api.com', // skip any URL containing this string
'/user-avatar-\\d+/', // regex: skip dynamic avatar URLs
'src/assets/brand-logo', // skip a specific local file
],
};Ignored items are excluded from scanning, downloading, and compression.
Pipeline
- Scan — auto-discovers external image and video URLs in your source files
- Download — fetches each URL (follows redirects), saves to
public/images/andpublic/videos/ - Compress images — converts PNG/JPG to WebP at configured quality using Sharp
- Compress videos — converts MP4/MOV/AVI to WebM using ffmpeg (VP9 + Opus)
- Replace — rewrites all URLs in source files (
.png→.webp,.mp4→.webm, external URLs → local paths)
Configuration (optional)
Create image-assets.config.js in your project root to override defaults:
export default {
autoScan: true, // scan codebase for URLs (default: true)
compressLocal: true, // compress local uncompressed assets too (default: true)
imagesDir: 'public/images', // where to save downloaded images
videosDir: 'public/videos', // where to save downloaded videos
replaceInDirs: ['src'], // directories to scan
compress: {
format: 'webp',
quality: 82,
removeOriginals: true,
},
videoCompress: {
format: 'webm',
quality: 'good', // 'fast' | 'good' | 'best'
maxWidth: 1920,
removeOriginals: true,
},
// Skip certain URLs or file paths
ignore: [
// 'cdn.dynamic-api.com', // substring match
// '/avatar-\\d+/', // regex match
],
// Manual sources (optional — auto-scanned if empty)
sources: [],
videoSources: [],
};Configuration options
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| autoScan | boolean | true | Auto-discover external URLs when sources is empty |
| compressLocal | boolean | true | Also compress local uncompressed images/videos in the project |
| ignore | string[] | [] | Patterns to skip (substring or /regex/). Applied to URLs and file paths |
| imagesDir | string | 'public/images' | Directory where images are saved |
| videosDir | string | 'public/videos' | Directory where videos are saved |
| replaceInDirs | string[] | ['src'] | Directories scanned for URL replacement |
| replaceExtensions | string[] | see below | File extensions to scan |
| compress.format | 'webp' | 'jpeg' | 'png' | 'webp' | Output image format |
| compress.quality | number | 82 | Image compression quality (1-100) |
| compress.removeOriginals | boolean | true | Delete source files after converting |
| videoCompress.format | string | 'webm' | Output video format |
| videoCompress.quality | 'fast' | 'good' | 'best' | 'good' | Video quality preset |
| videoCompress.maxWidth | number | 1920 | Scale down videos wider than this |
| videoCompress.removeOriginals | boolean | true | Delete source video after converting |
| sources | Array | [] | Manual { url, file } list (auto-scanned if empty) |
| videoSources | Array | [] | Manual { url, file } list (auto-scanned if empty) |
Default replaceExtensions: .js, .jsx, .ts, .tsx, .html, .vue, .svelte, .md, .mdx, .css, .astro
Supported frameworks
Works with any framework that serves a public/ directory:
| Framework | Config imagesDir | Config replaceInDirs |
|-----------|-------------------|----------------------|
| Vite / Vue | public/images | ['src'] |
| Next.js | public/images | ['app', 'pages', 'components'] |
| Astro | public/images | ['src'] |
| Svelte | public/images | ['src'] |
| Plain HTML | images | ['.'] |
CI integration
Run as part of your build:
# .github/workflows/build.yml
- name: Optimize assets
run: npx img-optTypical results
| Metric | Before | After | |--------|--------|-------| | External requests at load | 8-12 | 0 | | Image payload | 2.4 MB | 480 KB | | Video payload | 15 MB | 4 MB | | Largest Contentful Paint | 3.1 s | 1.2 s |
Contributing
PRs welcome. Run tests with npm test.
License
MIT - Nometria
