# rsbuild-plugin-sharp **Repository Path**: bit-xiaoyu/rsbuild-plugin-sharp ## Basic Information - **Project Name**: rsbuild-plugin-sharp - **Description**: 基于 Sharp 的高性能 Rsbuild 图像优化插件 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-08-14 - **Last Updated**: 2025-10-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # rsbuild-plugin-sharp 🚀 基于 Sharp 的高性能 Rsbuild 图像优化插件 ## 特性 - ⚡ **高性能**: 基于 Sharp,比其他图像处理库快 4-5 倍 - 🗜️ **智能压缩**: 支持 JPEG、PNG、WebP、AVIF 格式的智能压缩 - 🔄 **格式转换**: 自动转换为现代图像格式(WebP、AVIF) - 🧠 **可配置回退**: 压缩/转换的最小收益阈值可配置(`fallback.minCompressionRatio`) - 🔁 **替换策略**: `convertPolicy: 'smaller'|'always'` 控制 replace 模式是否无条件替换 - 📱 **响应式图片**: 自动生成多尺寸的响应式图片 - 🎛️ **灵活配置**: 丰富的配置选项,满足各种需求 - 📊 **详细统计**: 提供压缩比例和性能统计信息 ## 安装 ```bash npm install rsbuild-plugin-sharp # 或 pnpm add rsbuild-plugin-sharp # 或 yarn add rsbuild-plugin-sharp ``` ## 使用 ### 基础用法 ```javascript // rsbuild.config.mjs import { defineConfig } from '@rsbuild/core'; import { pluginVue2 } from '@rsbuild/plugin-vue2'; import { pluginSharp } from 'rsbuild-plugin-sharp'; export default defineConfig({ plugins: [ pluginVue2(), pluginSharp({ // 基础配置(也可直接用 compress) quality: { jpeg: 85, png: 90, webp: 80 }, // 过滤:避免小图被跳过 filter: { minSize: 0 }, // 回退门槛:压缩/转换小于该收益将回退(默认 0.02 即 2%) fallback: { minCompressionRatio: 0.02 } }) ] }); ``` ### 高级配置 ```javascript pluginSharp({ // 图片质量配置 quality: { jpeg: 85, png: 90, webp: 80, avif: 75 }, // 详细压缩配置 compress: { jpeg: { quality: 85, progressive: true, mozjpeg: true }, png: { quality: 90, compressionLevel: 8, palette: false }, webp: { quality: 80, effort: 6, lossless: false } }, // 格式转换 // 新写法:直接指定目标格式,并可限制来源类型与产出模式 convert: 'webp', // 或 'avif' convertFrom: ['jpeg', 'jpg'], // 仅对这些来源格式执行转换(默认 ['jpeg','jpg','png']) // 产出模式: // - sidecar(默认):保留原图并额外生成 webp/avif // - replace:仅产出转换结果(等价于 deleteOriginal: true) convertMode: 'sidecar', // 或 'replace' // 简写等价:deleteOriginal: true 等价于 convertMode: 'replace' // deleteOriginal: true, // 替换策略(仅 replace 有效): // - 'smaller'(默认):仅当目标比基准更小时替换 // - 'always':无条件替换为目标格式 convertPolicy: 'smaller', // 回退与收益阈值(压缩与转换共用)。设为 0 表示只要更小就采用 fallback: { minCompressionRatio: 0.02 }, // 响应式图片 responsive: { sizes: [400, 800, 1200], // 生成的尺寸 formats: ['webp', 'jpeg'], // 输出格式 generateSrcset: true // 生成 srcset }, // 文件过滤 filter: { minSize: 1024, // 最小文件大小 (1KB),若需全量处理建议设 0 maxSize: 5 * 1024 * 1024, // 最大文件大小 (5MB) include: ['.jpg', '.png', '.webp'], // 包含的扩展名 exclude: ['.gif'], // 排除的扩展名 includePaths: ['/assets/images/'], // 包含的路径 excludePaths: ['/assets/icons/'] // 排除的路径 }, // 输出配置 output: { dir: 'optimized', // 输出目录 filename: '[name].[hash][ext]', // 文件名模板 keepOriginal: false // 是否保留原文件 }, // 性能配置 performance: { concurrency: 4, // 并发处理数量 cache: true, // 启用缓存 cacheDir: '.sharp-cache' // 缓存目录 }, // 调试模式 debug: true }) ``` ## 配置选项 ### quality 图片质量快捷配置(各格式的默认质量)。 - 支持字段:`jpeg` | `png` | `webp` | `avif` - 作用:作为该格式的默认质量,当 `compress..quality` 未显式设置时生效。 - 示例:`quality: { jpeg: 85, png: 80 }` ### compress 精细压缩配置,优先级高于 `quality`。 - `compress.jpeg` - `quality?: number` JPEG 质量,数值越小压缩越强(有损)。 - `progressive?: boolean` 是否生成渐进式 JPEG(默认 true)。 - `mozjpeg?: boolean` 是否启用 mozjpeg(默认 true)。 - `compress.png` - `palette?: boolean` 是否启用调色板量化(开启后 `quality` 生效,通常能显著减小体积)。 - `quality?: number` 量化质量(建议 70–85)。 - `compressionLevel?: number` zlib 压缩等级 0–9(默认 8/9,数值越高越小但更慢)。 - `adaptiveFiltering?: boolean` 是否启用自适应过滤(可进一步减小体积)。 说明与注意事项: - 当 `palette: true` 时,`quality` 才会生效;`palette: false` 时会忽略 `quality`,以避免传入 Sharp 不支持的参数组合。 - 我们仅向 Sharp 传入已定义的字段,避免无效参数导致的错误(如 “Invalid argument”)。 - 推荐配置示例:`{ palette: true, quality: 80, compressionLevel: 9, adaptiveFiltering: true }`。 - `compress.webp` - `quality?: number` WebP 质量。 - `effort?: number` 压缩努力值 0–6/9(越大越小但更慢)。 - `lossless?: boolean` 是否使用无损 WebP。 - `compress.avif` - `quality?: number` AVIF 质量。 - `effort?: number` 压缩努力值。 说明:当前实现侧重于在 Loader 中按“原始格式”压缩(jpeg/png/webp 路径已实现)。如果目标格式未实现处理,则回退为原样输出。 ### convert / convertFrom / convertMode / deleteOriginal 格式转换配置。 - `convert: 'webp' | 'avif'` 指定目标格式(新写法)。 - `convertFrom?: ('png'|'jpeg'|'jpg')[]` 限制来源格式,默认 `['jpeg','jpg','png']`。 - `convertMode?: 'sidecar' | 'replace'` - `sidecar`:保留原图并额外生成 webp/avif(默认)。 - `replace`:只产出转换后的图片,不保留原图。 - `deleteOriginal?: boolean` 等价于 `convertMode: 'replace'`(便捷写法)。 向后兼容:仍支持旧写法 `convert: { toWebP?: boolean; toAVIF?: boolean; fallback?: boolean }`。 ### convertPolicy 控制在 `convertMode: 'replace'` 时的替换条件。 - `'smaller'`(默认):仅当目标格式文件体积比“基准”更小且超过阈值时才替换。 - `'always'`:无条件用目标格式替换,不再比较体积(慎用,可能放大体积)。 基准说明:基于 Loader 内部已获得的“更小者”作为比较基准(原图 vs 压缩后的原格式)。 ### fallback 压缩/转换的最小收益阈值与回退策略。 - `minCompressionRatio?: number` 默认 `0.02`(2%)。 - 压缩:若压缩收益小于该阈值则回退为原图。 - 转换:与“基准”(原图或压缩后)比较,若收益小于该阈值,则 replace 不替换、sidecar 不发射。 ### responsive 响应式图片配置(计划/可选)。 - `sizes?: number[]` 需要生成的宽度列表 - `formats?: ('jpeg'|'png'|'webp'|'avif')[]` 输出格式列表 - `generateSrcset?: boolean` 是否生成 srcset 说明:该功能在早期设计中规划,当前最简 Loader 路径未启用生成多尺寸产物;如需此能力,建议后续版本或在构建阶段额外产出资源并配合模板使用。 ### filter 文件过滤配置。 - `maxSize?: number` 最大处理体积(字节)。 - `include?: string[]` 仅处理的文件扩展名(如 ['.jpg','.png'])。 - `exclude?: string[]` 排除的文件扩展名。 - `includePaths?: (string|RegExp)[]` 仅处理的路径模式。 - `excludePaths?: (string|RegExp)[]` 排除的路径模式。 当前 Loader 内已实现:`minSize` 与 `include` 基于扩展名/体积的过滤;其他匹配可视需要扩展。 ### output 输出产物配置(规划项)。 - `dir?: string` 输出目录 - `filename?: string` 文件名模板 - `keepOriginal?: boolean` 是否保留原文件 说明:当前最简实现由 Rspack 资源模块接管产物输出与命名,`output` 配置暂未启用。 ### performance 性能与缓存(规划项)。 - `concurrency?: number` 并发处理数量 - `cache?: boolean` 是否启用缓存 - `cacheDir?: string` 缓存目录 说明:当前最简 Loader 实现未启用内置缓存;建议依赖构建缓存或后续版本提供。 ### debug 调试模式开关。 - `debug?: boolean` 为 true 时输出详细处理日志(处理前后大小、跳过原因等)。 ## 行为说明(重要) - **仅生产环境启用**:建议在 `rsbuild.config.mjs` 中用 `env === 'production'` 条件启用插件,开发环境不做压缩以提升速度。 - **保持原格式**:默认不做格式转换(`convert` 未设置时),按原格式进行压缩。 - **回退门槛可配**:压缩与转换均受 `fallback.minCompressionRatio` 约束(默认 2%)。 - **替换条件**:`convertMode: 'replace'` 下,受 `convertPolicy` 控制: - `'smaller'`:仅当目标比“基准”(原图或压缩后更小者)更小且收益达标才替换。 - `'always'`:总是替换。 - **过滤规则**:可通过 `filter.minSize` 与 `filter.include` 控制处理范围,减少不必要的处理开销。 - **压缩失败安全回退**:在内部处理过程中,如压缩出现异常,会自动回退到输出原图,保证构建稳定性。 > 提示:如果你发现“没有压缩/没有转 webp”,优先检查三点: > 1) 是否命中 Loader 规则(可能被更早的图片规则抢先匹配); > 2) `filter.minSize` 是否过大导致跳过; > 3) `fallback.minCompressionRatio` 是否过高导致回退;必要时将其设为 0 并观察日志。 ### 可选:构建后压缩(覆盖更多输出) 对于未经过 Loader 的产物(例如某些外部拷贝的资源),可以在构建后使用可选脚本进行再次压缩: ```bash # 压缩 dist 目录下的 jpg/jpeg/png node scripts/compress-images.js ``` 该脚本: - 直接遍历 `dist/` 并覆盖写回,覆盖范围更广; - 使用更激进的默认参数(例如 JPEG 质量 75、PNG `compressionLevel: 9`),无回退保护; - 建议仅在对画质和覆盖范围有强需求时使用,可按需调整脚本内参数。 ## 使用示例 ### Vue 项目中使用 ```vue ``` ### 与其他插件配合 ```javascript // 替换现有的图像压缩插件 export default defineConfig({ plugins: [ pluginVue2(), // 注释掉原有的图像压缩插件 // pluginImageCompress(), // 使用 Sharp 插件 pluginSharp({ filter: { minSize: 0 }, compress: { jpeg: { quality: 85, progressive: true, mozjpeg: true }, png: { quality: 90, compressionLevel: 8, palette: false }, webp: { quality: 80, effort: 6, lossless: false } }, convert: 'webp', convertFrom: ['jpeg','jpg','png'], deleteOriginal: true, // replace 模式 convertPolicy: 'smaller', // 或 'always' fallback: { minCompressionRatio: 0 }, debug: true }) ] }); ## 本地测试与集成 - 本地打包安装(推荐,最接近发布态): ```bash npm run build && npm pack npm i /绝对路径/rsbuild-plugin-sharp-.tgz ``` - 或使用 npm link:在插件仓库 `npm link`,在项目仓库 `npm link rsbuild-plugin-sharp`。 - 如果图片仍未被处理: - 确保图片通过源码被引用(import/CSS url/HTML 由相关 loader 处理)。 - 如存在其他图片规则,请调整顺序使本插件的 rule 优先匹配(必要时将其放前面)。 ``` ## 性能对比 | 插件 | 处理时间 | 压缩比例 | 支持格式 | |------|----------|----------|----------| | @rsbuild/plugin-image-compress | 100% | 60% | JPEG, PNG | | rsbuild-plugin-sharp | 25% | 75% | JPEG, PNG, WebP, AVIF | ## 开发 ```bash # 克隆项目 git clone https://github.com/yourusername/rsbuild-plugin-sharp.git # 安装依赖 npm install # 构建 npm run build # 测试 npm test # 开发模式 npm run dev ``` ## 贡献 欢迎提交 Issue 和 Pull Request! ## 许可证 MIT License ## 更新日志 ### 0.1.0 - 初始版本 - 支持基础图像压缩 - 支持格式转换 - 支持响应式图片生成 ## 发布前检查(清单) - [x] 测试通过:`npm test` 全部通过(15/15)。 - [x] 构建通过:`npm run build` 正常,`dist/` 产物包含 `index.js`、`index.cjs`、`loader.mjs`、类型声明等。 - [x] 打包检查:`npm pack --dry-run` 结果正常,仅包含 `dist/`、`README.md`、`package.json`。 - [x] 输出干净:测试文件未进入 `dist/`(`tsconfig.json` 已排除 `**/*.test.*` 与 `__tests__/`)。 - [x] 冗余文件清理:移除 `src/loader.js`、`test.js`。 - [x] 包导出:`package.json` 中 `exports` 同时支持 ESM/CJS;`types` 指向 `dist/index.d.ts`;`peerDependencies` 要求 `@rsbuild/core >=1.0.0`;`engines.node >=16`;`dependencies` 包含 `sharp`。