The Plugin
The oh-image Vite plugin optimizes images automatically for you.
To use the plugin, follow two steps:
1. Add the image plugin to the plugins array
import { defineConfig } from "vite";import react from "@vitejs/plugin-react";import { ohImage } from "@lonik/oh-image/plugin";
export default defineConfig({ plugins: [ohImage(), react()],});2. Add the ?oh suffix to the image import path
import photo from "./assets/photo.jpg?oh";Configuration
Section titled “Configuration”The oh-image plugin can be configured at different levels.
Global configuration
Section titled “Global configuration”You can pass a configuration object when you add the plugin:
import { ohImage } from "@lonik/oh-image/plugin";
ohImage({ format: "avif", placeholder: false, bps: [640, 828, 1200, 1920], distDir: "optimized-images",});Import-level configuration
Section titled “Import-level configuration”When you import an image with the ?oh suffix, you can add additional query parameters to configure that specific image:
import hero from "./assets/hero.jpg?oh&format=avif";import thumbnail from "./assets/photo.jpg?oh&width=400&height=300";import custom from "./assets/portrait.jpg?oh&bps=640,1080";Default configuration
Section titled “Default configuration”These are the default values used by the plugin when no configuration is provided:
{ format: "webp", placeholder: true, bps: [16, 48, 96, 128, 384, 640, 750, 828, 1080, 1200, 1920], distDir: "oh-images",}Global config options
Section titled “Global config options”| Option | Type | Default | Description |
|---|---|---|---|
format | string | "webp" | Output format for the image (e.g., webp, avif, png) |
placeholder | boolean | true | Whether to generate a placeholder image for lazy loading |
bps | number[] | [16, 48, 96, 128, 384, 640, 750, 828, 1080, 1200, 1920] | Breakpoints — widths in pixels for responsive srcSet generation |
distDir | string | "oh-images" | Directory name where processed images are output during build |
Import-level options
Section titled “Import-level options”| Option | Type | Default | Description |
|---|---|---|---|
format | string | Inherits global | Output format for this image (e.g., webp, avif, png) |
width | number | — | Target width for the processed image in pixels |
height | number | — | Target height for the processed image in pixels |
placeholder | boolean | Inherits global | Whether to generate a placeholder image for lazy loading |
bps | number[] | Inherits global | Breakpoints — widths in pixels for responsive srcSet generation |
Nulling out an option
Section titled “Nulling out an option”Some import-level options (width, height, format) accept null to explicitly unset them — for example, to override a globally configured format and fall back to the original file’s format.
To pass null via a query parameter, include the key without a value:
// Set format to null — keeps the original file format instead of convertingimport photo from "./assets/photo.jpg?oh&format";
// Set width to null — no width constraint appliedimport photo from "./assets/photo.jpg?oh&width";
// Set height to null — no height constraint appliedimport photo from "./assets/photo.jpg?oh&height";
// Set bps to null — disables responsive srcSet generation for this imageimport photo from "./assets/photo.jpg?oh&bps";
// Null out all at onceimport photo from "./assets/photo.jpg?oh&format&width&height&bps";A key with no = value is parsed as null by the query string parser.
Build vs Dev mode
Section titled “Build vs Dev mode”The plugin behaves differently depending on whether you’re in development or building for production.
Eager processing — All images are processed during the build step before deployment.
The process:
- Vite builds your application
- The plugin processes all registered images
- Optimized images are output to
assets/oh-images/ - Files are ready to be served from your CDN
The plugin uses parallel processing (up to 30 images concurrently) to keep build times reasonable.
Lazy processing — Images are only optimized when they are requested. This keeps the dev server responsive.
When a page with an optimized image loads:
- The browser requests the image
- The plugin intercepts the request
- The image is processed on-the-fly
- The result is cached for subsequent requests
This approach is ideal for development since you don’t need to wait for all images to process on every server restart.
| Aspect | Dev | Build |
|---|---|---|
| When images are processed | When first requested | During build |
| Where they’re stored | Vite cache directory | dist/assets/oh-images/ |
| Speed priority | Fast iteration | Optimized output |
Image placement
Section titled “Image placement”Images should not be placed in the public/ folder, as Vite does not process files from that directory.
Instead, place images in src/assets/ or any other directory within your source folder.
Supported images
Section titled “Supported images”The plugin supports the following image formats as input:
.jpg/.jpeg.png.webp.avif.gif.svg