vite-plugin-sharp
v1.6.3
Published
A Vite plugin for image compression using sharp and svgo
Readme
vite-plugin-sharp
中文
基于 sharp(光栅图片)和 svgo(SVG)的 零配置 Vite 图片压缩插件。构建时自动压缩 bundle 产物及 public 目录中的所有图片,无需额外设置。
为什么选 vite-plugin-sharp?
- 性能:底层使用 libvips(C++ 原生绑定),比 imagemin 快 4–5 倍
- 全覆盖:同时处理 JS/CSS 引入的 bundle 资源 和
public/静态目录 - 智能缓存:基于文件内容 hash,未修改的文件零开销跳过
- 安全:压缩后体积更大时保留原图,永不劣化产物
- 透明:终端逐文件展示压缩前后体积,与 Vite 输出风格一致
功能概览
| 能力 | 说明 |
|------|------|
| 格式支持 | jpeg / jpg / png / gif / tiff / webp / avif(sharp)+ svg(svgo) |
| 处理范围 | bundle 内联资源 + public 静态目录 |
| 缓存 | 文件内容 hash,可自定义路径或禁用 |
| 过滤 | include / exclude 白黑名单 |
| 限流 | concurrency 并发控制、minSize / minRatio 阈值 |
| 缩放 | resize 限制最大宽高,不放大小图 |
| 兼容性 | Vite 4 / 5 / 6 / 7 / 8+,仅 build 阶段生效 |
安装
npm install vite-plugin-sharp -D快速开始
// vite.config.ts
import { defineConfig } from "vite";
import viteSharp from "vite-plugin-sharp";
export default defineConfig({
plugins: [viteSharp()],
});Tip:若使用
vite.config.js(CommonJS),建议重命名为vite.config.mjs以确保 ESM 依赖正常加载。
配置项
viteSharp(options?: Partial<OptionsType>)| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| filter | RegExp | /\.(jpe?g\|png\|gif\|tiff\|webp\|svg\|avif)$/i | 匹配需要处理的文件路径 |
| include | RegExp \| string \| string[] | — | 白名单(优先于 filter + exclude) |
| exclude | RegExp \| string \| string[] | — | 黑名单 |
| cache | string \| false | node_modules/.vite/sharp-cache.json | 缓存路径,false 禁用 |
| minRatio | number | 0 | 最小压缩率(0–1),低于此值保留原图 |
| minSize | number | 0 | 最小文件大小(字节),小于此值跳过 |
| concurrency | number | os.cpus().length | 最大并发压缩数 |
| resize | ResizeConfig | — | 压缩前缩放(withoutEnlargement: true) |
| compress | CompressType | 见下方 | 各格式压缩参数 |
| 格式 | 默认配置 |
|------|----------|
| jpeg / jpg | quality: 75,chromaSubsampling: "4:4:4" |
| png | quality: 75,compressionLevel: 6,palette: true |
| webp | quality: 75,effort: 4 |
| avif | lossless: true |
| tiff | quality: 75 |
| gif | sharp 默认参数 |
| svg | svgo preset-default,multipass: true |
完整参数参考:sharp output API · svgo 配置
使用示例
viteSharp({
compress: {
jpeg: { quality: 85 },
png: { quality: 80, compressionLevel: 9 },
webp: { quality: 80, lossless: false },
},
});// 只处理指定目录
viteSharp({ include: /^assets\/images\// });
// 排除特定文件
viteSharp({ exclude: ["logo.svg", "favicon.ico"] });// 禁用缓存
viteSharp({ cache: false });
// 自定义路径(CI 中可提交复用)
viteSharp({ cache: ".cache/sharp.json" });viteSharp({
minRatio: 0.05, // 节省 < 5% 则保留原图
minSize: 10240, // 跳过小于 10 KB 的文件
resize: { width: 1920, height: 1080 },
concurrency: 4,
});终端输出
构建完成后,插件以树形结构输出每个文件的压缩结果:
[vite-plugin-sharp] compressing images...
├── dist/assets/hero-CLDdwZDr.png 13.06 kB → 12.04 kB │ -1.02 kB (7.8%)
├── dist/assets/code-50bb2e8d.jpg 14.87 kB → 3.23 kB │ -11.65 kB (78.3%) [cached]
├── dist/images/banner.png 797.04 kB → 255.81 kB │ -541.24 kB (67.9%) [cached]
└── dist/favicon.svg 9.52 kB → 9.52 kB │ [skipped] [cached]
✓ 3 files compressed -553.14 kB (65.5%) 1 skipped| 标识 | 含义 |
|------|------|
| (无标识) | 本次新鲜压缩 |
| [cached] | 缓存命中,跳过重压缩,直接复用上次结果 |
| [skipped] | 压缩后体积更大,保留原图 |
缓存机制
| 场景 | 行为 |
|------|------|
| 首次构建 | 压缩所有匹配图片 |
| 图片未修改 | 缓存命中,[cached],构建更快 |
| 图片修改 | 仅重新压缩该文件 |
| cache: false | 每次都重新压缩 |
默认缓存文件位于 node_modules/.vite/ 内,随 .gitignore 自动忽略。CI 场景可指定自定义路径持久化。
工作原理
Vite Build Pipeline
────────────────────────────────────────────────────────────────
1. generateBundle (enforce: "post")
→ 处理 bundle 中的图片(JS/CSS import),内存中压缩
→ Vite 写入磁盘时即为压缩版本
2. closeBundle
→ 扫描 dist 目录,处理 public/ 复制过来的图片
→ 磁盘上原地压缩替换
→ 通过 processedBundleKeys 去重,不会重复处理
────────────────────────────────────────────────────────────────开发
npm run build # 构建插件
npm run dev # 监听模式
npm test # 运行测试
npm run test:watch # 监听测试使用 webpack?
本插件仅适用于 Vite。如果你的项目使用 webpack,推荐以 sharp 作为后端的等价方案:
- image-minimizer-webpack-plugin +
imagemin-sharp(或直接用 sharp minimizer)— webpack 生态的标准图片压缩插件,支持 sharp 作为处理引擎,功能上与本插件等价。
许可证
ISC
English
Zero-config Vite image compression plugin powered by sharp (raster) and svgo (SVG). Automatically compresses all images in both the bundle output and the public directory during build.
Why vite-plugin-sharp?
- Performance: libvips native bindings — 4–5× faster than imagemin
- Full coverage: processes JS/CSS bundle assets and
public/static files - Smart caching: content-hash based, zero overhead for unchanged files
- Safe: never replaces originals when compression yields a larger file
- Transparent: per-file terminal output aligned with Vite's own style
Feature Overview
| Capability | Details |
|------------|---------|
| Formats | jpeg / jpg / png / gif / tiff / webp / avif (sharp) + svg (svgo) |
| Scope | Bundle inline assets + public static directory |
| Caching | Content hash, customizable path or disable |
| Filtering | include / exclude allow/deny lists |
| Throttling | concurrency limiter, minSize / minRatio thresholds |
| Resizing | resize — max dimensions with withoutEnlargement |
| Compatibility | Vite 4 / 5 / 6 / 7 / 8+, build-only |
Installation
npm install vite-plugin-sharp -DQuick Start
// vite.config.ts
import { defineConfig } from "vite";
import viteSharp from "vite-plugin-sharp";
export default defineConfig({
plugins: [viteSharp()],
});Tip: If you use
vite.config.js(CommonJS), rename it tovite.config.mjsto ensure ESM dependencies load correctly.
Options
viteSharp(options?: Partial<OptionsType>)| Option | Type | Default | Description |
|--------|------|---------|-------------|
| filter | RegExp | /\.(jpe?g\|png\|gif\|tiff\|webp\|svg\|avif)$/i | Regex matching file paths to process |
| include | RegExp \| string \| string[] | — | Allowlist (overrides filter + exclude) |
| exclude | RegExp \| string \| string[] | — | Denylist |
| cache | string \| false | node_modules/.vite/sharp-cache.json | Cache path, or false to disable |
| minRatio | number | 0 | Min savings ratio (0–1) to replace original |
| minSize | number | 0 | Min file size in bytes to process |
| concurrency | number | os.cpus().length | Max parallel compressions |
| resize | ResizeConfig | — | Pre-compress resize (withoutEnlargement: true) |
| compress | CompressType | See below | Per-format compression options |
| Format | Defaults |
|--------|----------|
| jpeg / jpg | quality: 75, chromaSubsampling: "4:4:4" |
| png | quality: 75, compressionLevel: 6, palette: true |
| webp | quality: 75, effort: 4 |
| avif | lossless: true |
| tiff | quality: 75 |
| gif | sharp defaults |
| svg | svgo preset-default, multipass: true |
Full reference: sharp output API · svgo config
Examples
viteSharp({
compress: {
jpeg: { quality: 85 },
png: { quality: 80, compressionLevel: 9 },
webp: { quality: 80, lossless: false },
},
});// Process only specific directory
viteSharp({ include: /^assets\/images\// });
// Exclude specific files
viteSharp({ exclude: ["logo.svg", "favicon.ico"] });// Disable caching
viteSharp({ cache: false });
// Custom path (sharable in CI)
viteSharp({ cache: ".cache/sharp.json" });viteSharp({
minRatio: 0.05, // skip if savings < 5%
minSize: 10240, // skip files < 10 KB
resize: { width: 1920, height: 1080 },
concurrency: 4,
});Terminal Output
After the build completes, the plugin prints compression results in a tree format:
[vite-plugin-sharp] compressing images...
├── dist/assets/hero-CLDdwZDr.png 13.06 kB → 12.04 kB │ -1.02 kB (7.8%)
├── dist/assets/code-50bb2e8d.jpg 14.87 kB → 3.23 kB │ -11.65 kB (78.3%) [cached]
├── dist/images/banner.png 797.04 kB → 255.81 kB │ -541.24 kB (67.9%) [cached]
└── dist/favicon.svg 9.52 kB → 9.52 kB │ [skipped] [cached]
✓ 3 files compressed -553.14 kB (65.5%) 1 skipped| Indicator | Meaning |
|-----------|---------|
| (none) | Freshly compressed this build |
| [cached] | Result replayed from cache — no recompression needed |
| [skipped] | Compressed output was larger — original retained |
Caching
| Scenario | Behavior |
|----------|----------|
| First build | Compresses all matching images |
| File unchanged | Cache hit — [cached], faster build |
| File modified | Only the changed file is recompressed |
| cache: false | Recompresses every file every build |
The default cache file lives inside node_modules/.vite/ and is automatically git-ignored. For CI, specify a custom path to persist across builds.
How It Works
Vite Build Pipeline
────────────────────────────────────────────────────────────────
1. generateBundle (enforce: "post")
→ Compresses bundle images (JS/CSS imports) in memory
→ Vite writes the compressed version to disk
2. closeBundle
→ Scans dist for images not handled in step 1
→ Compresses public/ files in-place on disk
→ Deduplicates via processedBundleKeys — no double processing
────────────────────────────────────────────────────────────────Development
npm run build # Build the plugin
npm run dev # Watch mode
npm test # Run tests
npm run test:watch # Watch testsUsing webpack?
This plugin is Vite-only. For webpack projects, the recommended equivalent with sharp as the backend is:
- image-minimizer-webpack-plugin — the standard webpack image compression plugin that supports sharp as the processing engine, functionally equivalent to this plugin.
License
ISC
