The oh-image Vite image plugin lets you import optimized images as React components. It intercepts your image imports, processes them using Sharp, and generates responsive assets ready for the web.

Integration

To integrate the oh-image plugin into your project, add it to the plugins array in your vite.config.ts.

import { ohImage } from "@lonik/oh-image/plugin";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [ohImage()],
});

Usage

The oh-image plugin does not automatically process every image in your project; it is an opt-in behavior. To instruct the plugin to process an image, append the $oh query parameter to your import statement:

import SomeImage from "./assets/photo.jpg?$oh";

Important Caveat

Note: The plugin can only process images located within your project's source directory (e.g., src/assets/, src/images/).

Images placed in the public/ folder are served as-is by Vite and bypass the build process, meaning oh-image cannot optimize them. Move any images you wish to optimize into your src/ folder.

How it Works

When the plugin encounters an image import with the ?$oh query, it optimizes the image, generates necessary metadata (like dimensions and a placeholder), and wraps it in an <Image /> component.

The imported entity is a regular Image component that can be used directly in your application:

import SomeImage from "./assets/photo.jpg?$oh";

function App() {
  return <SomeImage />;
}

Since SomeImage is a Image component, you can pass any standard Image props to it, in addition to the ones pre-configured by the plugin.

The plugin automatically sets the following properties for you:

  • width
  • height
  • src
  • srcSet
  • placeholder

Because the image is static, the plugin can pre-calculate these values during the build process.

Configuration

The plugin can be configured globally in your Vite config or locally via query parameters.

Local Configuration

You can override processing options on a per-import basis by adding additional query parameters.

// Convert to AVIF and apply a blur
import SomeImage from "./assets/photo.jpg?blur=50&format=avif&$oh";

function App() {
  return <SomeImage />;
}

Global Configuration

You can configure the plugin in vite.config.ts to apply global defaults. Note the nested structure for transforms and placeholder.

import { ohImage } from "@lonik/oh-image/plugin";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [
    ohImage({
      distDir: "oh-images",
      // Default transformations for the main image
      transforms: {
        format: "webp",
        quality: 80,
      },
      // Breakpoints for responsive srcSet
      breakpoints: [640, 768, 1024],
      // Enable/Disable placeholder generation globally
      pl_show: true,
      // Default transformations for the placeholder image
      placeholder: {
        format: "webp",
        blur: 20,
      },
    }),
  ],
});

Query Param Options

These options can be passed globally (within transforms object) or as query parameters. When used as query parameters, they apply to the main image. To apply them to the placeholder, prefix the key with pl_ (e.g., pl_blur=10).

OptionTypeDescription
[pl_]widthnumberTarget width for the processed image.
[pl_]heightnumberTarget height for the processed image.
[pl_]formatstringOutput format (e.g., webp, avif, png).
[pl_]qualitynumberChange quality of the Image (1-100).
[pl_]blurnumberBlur the image with the specified sigma.
[pl_]flipbooleanFlip the image vertically.
[pl_]flopbooleanFlop the image horizontally.
[pl_]rotatenumberRotate the image by the specified angle.
[pl_]sharpennumberSharpen the image with the specified sigma.
[pl_]mediannumberApply a median filter with the specified size.
[pl_]gammanumberApply gamma correction.
[pl_]negatebooleanNegate the image colors.
[pl_]normalizebooleanNormalize the image contrast.
[pl_]thresholdnumberApply a threshold with the specified value.
pl_showbooleanGenerate a placeholder image ? (true/false).
breakpointsnumber[]Comma-separated list of widths for srcSet.

For more details on image operations, refer to the Sharp documentation.

Global-Only Options

In addition to the processing options, the global configuration accepts:

OptionTypeDefaultDescription
distDirstringoh-imagesThe subdirectory within your build output where images will be saved.
outDirstringThe directory relative to the project root where images will be saved, overriding Vite's build.outDir.

Default Configuration

By default, the plugin uses the following settings:

{
  distDir: "oh-images",
  breakpoints: [16, 48, 96, 128, 384, 640, 750, 828, 1080, 1200, 1920],
  pl_show: true,
  transforms: {
    format: "webp",
  },
  placeholder: {
    quality: 10,
    blur: 50,
    format: "webp",
  },
}

Passing Parameters via Query String

You can pass various data types as query parameters in your imports:

String

Pass the value directly.

import image from "./assets/image.png?format=png&$oh";

Number

Pass a numeric value.

import image from "./assets/image.png?blur=50&$oh";

Array

Pass comma-separated values.

import image from "./assets/image.png?breakpoints=16,32,64,128&$oh";

To pass an empty array (e.g., to disable breakpoints), pass the key without a value:

import image from "./assets/image.png?breakpoints&$oh";

Boolean

Pass true or false.

import image from "./assets/image.png?placeholder=true&$oh";
import image from "./assets/image.png?placeholder=false&$oh";

Unset a Value

Except boolean type, To unset a default option (effectively setting it to undefined or null), pass the key name only.

// Prevent Sharp from changing the format (uses original)
import image from "./assets/image.png?format&$oh";

Build vs. Dev Mode

The plugin operates differently depending on your environment to balance speed and performance.

Development (Lazy Processing)

In development, images are processed lazily. Images are only processed when requested by the browser and are cached in the Vite cache directory. This ensures fast startup times.

Production Build (Eager Processing)

During the build process, the plugin eagerly optimizes all imported images with $oh query parameter. It automatically generates the main image, responsive variants (srcSet), and placeholders based on your configuration.