@fe-fast/rusty-pic
v0.3.2
Published
🚀 高性能图片压缩工具,基于 Rust + WebAssembly 构建
Maintainers
Readme
Rusty-Pic
High-performance image optimization toolkit for the web. Rusty-Pic integrates seamlessly with Vite and Webpack, compresses images at build time with content-hashed outputs and auto-updated references, and supports optional cross-format transcode (e.g. PNG → WebP/AVIF).
Rusty-Pic 是一款高性能图片优化工具,深度集成 Vite 与 Webpack。它在构建阶段直接替换打包资产的字节,自动生成带内容哈希的产物并重写所有引用,可选开启跨格式转码(例如 PNG → WebP/AVIF)。
✨ Features | 功能特性
Build-pipeline native integration (Vite + Webpack): auto content hash + auto reference rewrite
Optional cross-format transcode: PNG/JPEG → WebP/AVIF, safe rename & reference updates
Real compression in Node builds (sharp), WASM path for browsers (with Canvas fallback)
Cache-aware and size-aware: only replace when smaller; cache to avoid repeated work
Simple DX: one plugin, minimal config; integration tests provided
原生构建管线集成(Vite + Webpack):自动内容哈希与引用重写
跨格式转码可选:PNG/JPEG → WebP/AVIF,安全改名与全量引用替换
Node 构建期真实压缩(sharp),浏览器端支持 WASM(并带 Canvas 兜底)
感知缓存与体积:仅在更小时替换,缓存避免重复压缩
开发者体验友好:一套插件,最小配置;提供可运行的集成测试
📦 Install | 安装
# npm
npm install @fe-fast/rusty-pic
# pnpm
pnpm add @fe-fast/rusty-pic
# yarn
yarn add @fe-fast/rusty-pic⚙️ Vite Usage | Vite 使用
Default behavior: format='auto', transcode=false → keep original extensions (png stays png) and compress; references are auto-rewritten to hashed outputs.
默认行为:format='auto' 且 transcode=false → 保持原扩展名,仅同格式压缩;引用会自动重写到带哈希的产物。
Enable WebP transcode:
import { defineConfig } from 'vite';
import { rustyPic } from '@fe-fast/rusty-pic/vite';
export default defineConfig({
plugins: [
rustyPic({
format: 'webp', // target format
transcode: true, // allow cross-format rename
quality: 80, // 1-100
// optional
resize: { maxWidth: 1920, maxHeight: 1080, fit: 'inside' },
cache: { enabled: true },
dev: { enabled: false },
build: { enabled: true },
verbose: true
})
]
});Enable AVIF transcode:
rustyPic({ format: 'avif', transcode: true, quality: 70 })🔧 Webpack Usage | Webpack 使用
Add the plugin and ensure images are treated as assets:
import RustyPicWebpackPlugin from '@fe-fast/rusty-pic/webpack';
export default {
mode: 'production',
module: {
rules: [
{ test: /\.(png|jpe?g|webp|avif)$/i, type: 'asset/resource' }
]
},
output: {
assetModuleFilename: 'assets/[name].[contenthash:8][ext]'
},
plugins: [
new RustyPicWebpackPlugin({
// default keeps original ext (no transcode)
// set webp/avif to transcode and auto-rewrite references
format: 'webp',
quality: 80,
verbose: true
})
]
};Notes | 说明:
- Webpack 分支下,设置 format!='auto' 即表示允许跨格式转码(例如 'webp'/'avif')。插件会安全地改名并替换文本资产中的引用。
- 若你只想同格式压缩但不改扩展名,设置 format:'auto' 即可。
🧠 Defaults & Options | 默认与选项
- format: 'auto'(默认) → 同扩展名压缩;不变更后缀
- transcode: false(默认) → 仅当设为 true 并 format≠原扩展名时才跨格式
- quality: 80(默认)
- resize: { maxWidth?, maxHeight?, fit? }(Vite/Webpack 同)
- cache.enabled: true(默认)
- dev.enabled: false(默认)
- build.enabled: true(默认)
🖼️ AVIF Transcode | AVIF 转码
Why AVIF? Generally higher compression efficiency than WebP at similar perceptual quality. Recommended quality range: 45–75 (start with 70). AVIF decoding is well supported on modern browsers.
为什么选择 AVIF?通常在相近主观质量下,AVIF 的压缩率高于 WebP。建议质量范围:45–75(推荐 70 起步)。现代浏览器支持良好。
Enable in Vite:
rustyPic({ format: 'avif', transcode: true, quality: 70 })Enable in Webpack:
new RustyPicWebpackPlugin({ format: 'avif', quality: 70 })Compatibility tip: for older browsers, provide fallbacks via or server-side negotiation.
兼容性提示:对旧浏览器可通过 多源或服务端协商提供回退格式。
Example HTML pattern:
<picture>
<source type="image/avif" srcset="/assets/sample.avif" />
<source type="image/webp" srcset="/assets/sample.webp" />
<img src="/assets/sample.png" alt="image" />
</picture>📊 Example Size Comparison | 示例体积对比
Below numbers are measured on the sample image in this repo (public/卡片.png) with default settings (WebP q=80, AVIF q=70). Actual results vary by image content.
下表为本仓库示例图(public/卡片.png)在默认设置下的测量结果(WebP q=80,AVIF q=70),实际结果会因图片内容而异。
| Format | Size | Reduction | |-------:|-----:|----------:| | PNG (original) | 3.83 MB | – | | WebP | 226.49 KB | 94.4% | | AVIF | 225.39 KB | 94.4% |
🛠️ Runtime Backends | 运行后端
Node builds: sharp is used to perform real compression (jpeg/webp/avif/png). This ensures stable, fast build-time optimization and large size reductions.
Browser/WASM: the library exposes a WASM path (with Canvas fallback) for browser-side usage; this is independent from the build pipeline integration.
Node 构建:采用 sharp 实现真实压缩,稳定高效,体积下降显著。
浏览器/WASM:库在浏览器侧可走 WASM(带 Canvas 兜底),与构建期集成相互独立。
🧪 Integration Tests | 集成测试
We ship runnable integration tests (generated into tests/.tmp) to verify both pipelines:
- Vite:
pnpm run test:int:vite - Webpack:
pnpm run test:int:webpack
项目内提供可运行的集成测试(生成到 tests/.tmp)以验证两套管线:
- Vite:
pnpm run test:int:vite - Webpack:
pnpm run test:int:webpack
📚 Programmatic API | 编程接口
Compress a single file (browser example):
import { rustyPic } from '@fe-fast/rusty-pic';
const file = document.querySelector('input[type="file"]').files[0];
const result = await rustyPic.compress(file, { format: 'webp', quality: 80 });
console.log('ratio', result.compressionRatio.toFixed(1), '%');Batch compress:
const files = Array.from(document.querySelector('input[type="file"]').files);
const results = await rustyPic.compressBatch(files, { format: 'auto', quality: 85 }, (p) => {
console.log(`progress ${p.completed}/${p.total}`);
});Smart compress:
const r1 = await rustyPic.smartCompress(file); // auto params
const r2 = await rustyPic.smartCompress(file, 100e3); // target 100 KBType signatures (simplified):
interface CompressionOptions {
format?: 'webp' | 'jpeg' | 'png' | 'avif' | 'auto';
quality?: number; // 1-100
resize?: { width?: number; height?: number; fit?: 'cover' | 'contain' | 'fill' | 'inside' | 'outside' };
optimize?: { colors?: boolean; progressive?: boolean; lossless?: boolean };
}🧰 CLI (optional) | 可选 CLI
npm install -g @fe-fast/rusty-pic
rusty-pic compress input.jpg -q 80 -f webpCLI 为扩展能力,推荐优先采用 Vite/Webpack 构建集成以获得自动哈希与引用重写。
❓ FAQ
- Q: Will hashed filenames and references be correct after compression/transcode?
- A: Yes. The plugins operate within the bundler pipeline. Final filenames are content-hashed after compression, and references in JS/CSS/HTML are auto-updated.
- Q: Is WebP/AVIF default?
- A: No. Default is format='auto' and transcode=false (no rename). Enable transcode + set target format to produce WebP/AVIF.
- Q: Any browser compatibility notes for AVIF?
- A: AVIF requires modern browsers. Consider with multiple sources or server-side negotiation for older browsers.
🏗️ Development | 开发
pnpm install
pnpm run dev
pnpm run buildRequirements | 环境
- Node.js 18+
- (for WASM dev) Rust 1.70+ and wasm-pack
📄 License | 许可证
MIT
If this project helps you, please consider giving it a ⭐. 如果这个项目对你有帮助,欢迎点亮一个 ⭐!
