Open-source project
FatehAK/vite-plugin-image-optimizer avatar
FatehAK/vite-plugin-image-optimizer

vite-plugin-image-optimizer: Sharp and SVGO inside the Vite build

Optimize your image assets using Sharp.js and SVGO.

518 stars26 forksTypeScriptMIT

At a glance

What is it?
vite-plugin-image-optimizer rewrites SVG and raster assets smaller during a Vite build, using Sharp.js for png, jpeg, gif, tiff, webp and avif and SVGO for vectors. The plugin ships neither library, so you install the one you need, and the defaults are tuned for lossless output.
Who is it for?
vite-plugin-image-optimizer fits a Vite project with a large image payload that wants the compression applied automatically on every build rather than as a manual step. It is the wrong choice for a project that does not use Vite, for assets that arrive at runtime from a CMS or an upload directory, and for a build environment where a native `sharp` install is a problem.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A build-time image optimiser for Vite that uses Sharp and SVGO

vite-plugin-image-optimizer is a Vite plugin to optimize all image assets using Sharp.js and SVGO at build time. The scope is small and clear. It is not a CDN, not a runtime resizer and not a general asset pipeline. It sits in the Vite build, walks your assets, and rewrites them smaller on disk. The plugin supports Vite >= 3 and Node >= 14, and it is MIT licensed with the author credited as fatehak. The README records releases v2.0.1 in June 2025, v2.0.2 later that month and v2.0.3 in October 2025, with the last push on 2026-10-20.

The stated origin is a webpack plugin that did not exist for Vite

The Motivation section explains where the idea came from. The plugin is based on the image-minimizer-webpack-plugin for Webpack, and the author wanted to combine the optimization capabilities of Sharp.js and SVGO in a single package and could not find a Vite plugin that did it. The author also considered adding squoosh and imagemin support and dropped the idea because they are no longer maintained. That last point is the design rationale in miniature. This plugin delegates compression to two libraries that are still maintained, rather than bundling its own encoders, and that delegation is what shapes everything else about how it works.

Sharp and SVGO are peer dependencies you install yourself

The Installation section is one command, and then a warning that is easy to skim past:

console
npm install vite-plugin-image-optimizer --save-dev

The plugin does not bring `sharp` and `svgo` with it. You have to install them manually and add them as dev dependencies, and the README says this is a design decision so you can skip installing `sharp` if you only want to optimize SVG assets with `svgo`, and vice versa. The two commands given are `npm install sharp --save-dev` and `npm install svgo --save-dev`. In practice that means a Vite project using this plugin ends up with three dev dependencies, and the size of the install depends on which of the two you actually need.

Adding the plugin is a Vite config entry

Usage is a single import and one entry in the plugins array:

js
import { ViteImageOptimizer } from 'vite-plugin-image-optimizer';
import { defineConfig } from 'vite';

export default defineConfig(() => {
  return {
    plugins: [
      ViteImageOptimizer({
        /* pass your config */
      }),
    ],
  };
});

The exported factory is `ViteImageOptimizer` and it takes an options object, which the README shows as an empty placeholder in the usage example because the defaults are meant to cover most cases. The package is an ES module with a `type` of `module`, and the exports map provides both `import` and `require` entry points alongside the type definitions, so it works in projects that have not finished migrating to ESM. The build output itself is small, since the heavy lifting happens in the two native or compiled dependencies rather than in the plugin.

Defaults target lossless compression, and the SVG preset is deliberately conservative

The default configuration is made for lossless compression of image assets, and the shape of it explains a lot about the plugin's priorities:

js
const DEFAULT_OPTIONS = {
  logStats: true,
  ansiColors: true,
  test: /\.(jpe?g|png|gif|tiff|webp|svg|avif)$/i,
  exclude: undefined,
  include: undefined,
  includePublic: true,
  svg: {

The `test` pattern matches jpeg, jpg, png, gif, tiff, webp, svg and avif with a case-insensitive extension test, `includePublic` is true so everything under the bundler's public directory is processed, and `cache` is off. The SVG section is the interesting part. It runs `preset-default` with `cleanupNumericValues`, `convertPathData` and the `cleanupIds` minify and remove flags all turned off, then adds `sortAttrs` and a plugin that adds the `xmlns` attribute to the SVG element. The overrides are conservative because path data rewriting and ID removal are the two operations most likely to change how a file renders or breaks references to it from elsewhere in the document.

Filter options let you narrow the scope, and include wins over exclude

The plugin options are listed with the `test`, `include`, `exclude`, `includePublic`, `logStats`, `ansiColors` and per-format sections, plus `cache` and `cacheLocation`. The three filters behave differently from each other, and the difference matters. `test` is a regular expression matched against files. `exclude` accepts a string, a regular expression or an array of strings, and a regular expression can be applied to the source path to exclude a particular folder, with `/textures/` given as the example. `include` accepts the same types and works the same way. The README attaches a warning to `include` specifically: it will override any options set in `test` and `exclude` and has a higher preference, so use it if you want to include specific assets only. The practical upshot is that `test` is the broad default, `exclude` carves holes in it, and `include` replaces the whole selection.

Caching and the rule that a bigger output is discarded

Two behaviours are worth knowing about because they change what you see in a build log. The plugin has optional caching support to avoid re-optimization, configured with `cache` and `cacheLocation`, both off by default in the options listing. And there is a rule that skips processing assets if their optimized size is greater than their original size. That second rule is more than a nicety, because a lossless re-encode of an already well-compressed PNG can easily come out larger, and without the check your build would silently replace a file with a worse one. Combined with the `logStats` option, which logs the size difference in kB, the percent change and total savings, you can see at a glance whether the pipeline is doing anything.

Where the plugin is the wrong tool, and how a separate optimisation step differs

Three limits are concrete. The first is that it only touches Vite. A project that builds with webpack, Rollup directly, Parcel or esbuild gets nothing from it, and a monorepo with mixed bundlers ends up with two image pipelines. The second is that it is a build-time transformer, so it only sees assets that are in the bundle or under the public directory. An image loaded from a CMS, a user upload directory or a CDN at runtime is never touched. The third is the two-dependency install, where `sharp` is a native module with platform binaries, and that is a source of install friction in restricted CI environments, in Alpine-based containers where musl builds are needed, and in platforms where prebuilt binaries do not exist. The plugin cannot hide that, since the decision to not bundle `sharp` is deliberate.

The realistic alternative is to run your images through an optimisation command as a separate step in your build script, using the same Sharp and SVGO tools directly, and to commit the results. The difference in approach is when the work happens and what ends up in version control. With the plugin, the optimisation is part of the Vite build, so the originals stay in the repository and the output exists only in the build artifact, which means the images are reprocessed on every build unless you turn caching on. With a separate step, you optimise once, commit the results, and the build does nothing, which is faster and gives you a readable diff of what changed. The plugin route is better when you have many images and want the saving to be automatic and enforced. The separate step is better when build time matters, when your CI images are minimal, or when you want a human to look at what the optimiser did to each file.

Editorial conclusion

vite-plugin-image-optimizer fits a Vite project with a large image payload that wants the compression applied automatically on every build rather than as a manual step. It is the wrong choice for a project that does not use Vite, for assets that arrive at runtime from a CMS or an upload directory, and for a build environment where a native `sharp` install is a problem. Before you adopt it, add `sharp` and `svgo` as dev dependencies yourself and check that the lossless defaults do not break an SVG that depends on its original path data or element ids, since the plugin deliberately disables ID cleanup and path rewriting.

Frequently asked questions

How do I install vite-plugin-image-optimizer?

Run `npm install vite-plugin-image-optimizer --save-dev`. You also have to install `sharp` and `svgo` yourself as dev dependencies, which is a deliberate design decision so you can install only the one you need.

Which image formats does the Vite image optimizer handle?

SVG assets through SVGO, and raster assets in png, jpeg, gif, tiff, webp and avif through Sharp.js. Custom configs can be passed for each extension type, and the default `test` pattern matches all of them case-insensitively.

How do I add the plugin to a Vite config?

Import `ViteImageOptimizer` from `vite-plugin-image-optimizer` and `defineConfig` from `vite`, then add `ViteImageOptimizer({})` to the plugins array. The options object is optional, since the defaults cover lossless compression for every supported format.

What does the include option do in vite-plugin-image-optimizer?

It accepts a string, a RegExp or an array of strings and restricts processing to matching files, and a RegExp can target a folder on the source path. The README warns that it overrides any options set in `test` and `exclude` and has a higher preference.

Official sources

  1. FatehAK/vite-plugin-image-optimizer on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/fatehak-vite-plugin-image-optimizer.svg)](https://hysenlabs.com/projects/fatehak-vite-plugin-image-optimizer)

Was this useful?