Package Exports
- vite-image-react
- vite-image-react/next-plugin
- vite-image-react/vite-plugin
Readme
vite-image-react
Content-aware, device-adaptive image optimizer for Vite + React.
Built by @ezitounioussama — gotodev.ma
Surpasses next/image in perceptual quality at equal or smaller file sizes. Works with any Vite project, not locked to any framework.
How it works
Build time (Vite plugin)
Every image is divided into 64×64 tiles and analyzed:
- Analyze — per-tile Shannon entropy, Sobel edge density, and skin-tone ratio produce an importance map
- Weight — top 30% most-important tiles drive 70% of the quality decision; center-bias and edge-bonuses refine it
- Preprocess — high-importance tiles are selectively sharpened (with overlapped boundaries to prevent seams)
- Encode — each tier/variant is encoded at the perceptually-weighted quality; SSIM auto-tune finds the Pareto-optimal quality/size point
- Emit — manifest with variants, tiers, LQIP placeholders, and SRI hashes is embedded in the module
Runtime (GImage component)
- Fingerprint — reads
effectiveType,deviceMemory,hardwareConcurrency,devicePixelRatio,saveData - Tier — scoring algorithm selects
ultra/high/medium/lowper device capability - Format —
<picture>with AVIF, WebP, and JPEG sources - Load — IntersectionObserver with scroll-velocity-adaptive preload distance (600–3000px)
- Placeholder — blur-up CSS transition from 32×32 WebP base64 to full image
Features
- Perceptually-optimized quality — 64×64 tile saliency drives quality per region. Faces, text, and detail get higher quality; backgrounds compress harder.
- Saliency-driven preprocessing — important tiles are sharpened before encoding, preserving detail where it matters.
- Skin-tone face detection — automatic quality boost around skin-colored regions. Zero extra dependencies.
- SSIM auto-tune — finds the lowest quality where SSIM >= 0.97, saving 20–40% file size with no visible loss.
- Device-adaptive delivery — runtime fingerprinting selects the optimal quality tier for each device.
- Automatic format conversion — AVIF, WebP, and JPEG sources in a
<picture>element. - Predictive lazy loading — scroll velocity sampling dynamically adjusts the preload distance.
- Blur-up placeholders — 32×32 WebP base64 with CSS fade-in.
- CLS prevention — fixed-aspect-ratio container from image metadata.
- SVG optimization — automatic SVGO compression with security sanitization.
Install
npm install vite-image-reactUsage
Vite plugin
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import viteImageReact from 'vite-image-react/vite-plugin'
export default defineConfig({
plugins: [
react(),
viteImageReact(),
],
})Next.js plugin
// next.config.mjs
import { withViteImageReact } from 'vite-image-react/next-plugin'
export default withViteImageReact({
// your Next.js config here
}, {
// optional: plugin options
remote: { domains: ['images.unsplash.com'] },
})Then import GImage from 'vite-image-react' in your components. Works in both App Router and Pages Router.
'use client'
import GImage from 'vite-image-react'
import hero from './hero.jpg'
export default function Page() {
return <GImage src={hero} alt="Hero" priority />
}React component
import GImage from 'vite-image-react'
import hero from './hero.jpg'
function Page() {
return (
<GImage
src={hero}
alt="Hero banner"
priority
sizes="(max-width: 768px) 100vw, 50vw"
/>
)
}Remote images
// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import viteImageReact from 'vite-image-react/vite-plugin'
export default defineConfig({
plugins: [
react(),
viteImageReact({
remote: {
domains: ['images.unsplash.com', 'cdn.example.com'],
},
}),
],
})import GImage from 'vite-image-react'
import hero from 'https://images.unsplash.com/photo-1234567890'
function Page() {
return (
<GImage src={hero} alt="Remote hero" />
)
}Public directory images
Images placed in your project's public/ directory are automatically scanned and optimized during build. No import needed:
public/
├── logo.png ← optimized to dist/logo.png
├── og-image.jpg ← optimized to dist/og-image.jpg
└── images/
└── banner.webp ← optimized to dist/images/banner.webpPublic images use the same compression pipeline (AVIF/WebP/JPEG encoding, SSIM auto-tune, saliency preprocessing) with the high quality tier defaults. Since they aren't directly imported, they get optimized on-disk in dist/ under their original paths.
All standard <img> props work: className, style, onLoad, onError, loading, etc.
Options
Plugin options
viteImageReact({
tiers?: Partial<Record<QualityTier, TierConfig>>
adaptive?: boolean // default: true
autoTune?: boolean // default: true
preprocess?: boolean // default: true — sharpen important tiles before encoding
faceDetection?: boolean // default: true — boost quality around skin tones
formats?: OutputFormat[] // default: ['avif', 'webp', 'jpeg']
maxFileSize?: number // default: 52_428_800 (50MB)
verbose?: boolean // default: false
remote?: {
domains: string[] // allowed remote image domains (e.g. ['images.unsplash.com'])
cacheDir?: string // cache directory (default: node_modules/.cache/vite-image-react)
}
})GImage props
interface GImageProps {
src: string | ImageMetadata // import result or metadata object
alt: string
priority?: boolean // eager load + fetchPriority='high'
sizes?: string // default: '100vw'
disableAdaptive?: boolean // always deliver highest quality
placeholder?: 'blur' | 'none' // default: 'blur'
onLoad?: () => void
onError?: () => void
// + all standard img props (className, style, loading, etc.)
}Comparison: next/image vs vite-image-react
| Aspect | next/image | vite-image-react |
|---|---|---|
| Quality strategy | Uniform (e.g. 75) | Perceptually-weighted — important regions drive quality |
| Preprocessing | None | Saliency-guided sharpen — detail preserved where it matters |
| Face/subject detection | None | Skin-tone heuristic — quality boost on faces |
| SSIM auto-tune | None | Smallest file at SSIM >= 0.97 |
| Device adaptation | Responsive srcSet only | Runtime tier switching — CPU/memory/connection-aware |
| Predictive loading | Fixed threshold | Velocity-adaptive — faster scroll = bigger preload zone |
| Format pipeline | AVIF/WebP/JPEG | Same + skin detection + selectable preprocessor |
| SVG optimization | None | SVGO integration with security sanitization |
Requirements
- Node.js >= 18.17
- React >= 19
- Vite >= 7 (optional — only for Vite plugin)
- Next.js >= 13 (optional — only for Next.js plugin)
License
MIT — built with care by @ezitounioussama · gotodev.ma