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 React. Works with Vite and Next.js.
Built by @ezitounioussama — gotodev.ma
Surpasses next/image in perceptual quality at equal or smaller file sizes. Framework-agnostic — use it with Vite, Next.js, or any React build pipeline.
How it works
Build time (Vite or Next.js)
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-react
# or
pnpm add vite-image-react
# or
bun add 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: Built-in 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