@meng-xi/vite-plugin 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README-en.md +42 -16
  2. package/README.md +55 -29
  3. package/dist/common/concurrency/index.cjs +1 -0
  4. package/dist/common/concurrency/index.d.cts +26 -0
  5. package/dist/common/concurrency/index.d.mts +26 -0
  6. package/dist/common/concurrency/index.d.ts +26 -0
  7. package/dist/common/concurrency/index.mjs +1 -0
  8. package/dist/common/format/index.cjs +1 -1
  9. package/dist/common/format/index.d.cts +19 -1
  10. package/dist/common/format/index.d.mts +19 -1
  11. package/dist/common/format/index.d.ts +19 -1
  12. package/dist/common/format/index.mjs +1 -1
  13. package/dist/common/fs/index.cjs +1 -1
  14. package/dist/common/fs/index.d.cts +19 -1
  15. package/dist/common/fs/index.d.mts +19 -1
  16. package/dist/common/fs/index.d.ts +19 -1
  17. package/dist/common/fs/index.mjs +1 -1
  18. package/dist/common/index.cjs +1 -1
  19. package/dist/common/index.d.cts +4 -2
  20. package/dist/common/index.d.mts +4 -2
  21. package/dist/common/index.d.ts +4 -2
  22. package/dist/common/index.mjs +1 -1
  23. package/dist/common/path/index.cjs +1 -0
  24. package/dist/common/path/index.d.cts +103 -0
  25. package/dist/common/path/index.d.mts +103 -0
  26. package/dist/common/path/index.d.ts +103 -0
  27. package/dist/common/path/index.mjs +1 -0
  28. package/dist/index.cjs +1 -1
  29. package/dist/index.d.cts +6 -2
  30. package/dist/index.d.mts +6 -2
  31. package/dist/index.d.ts +6 -2
  32. package/dist/index.mjs +1 -1
  33. package/dist/plugins/assetManifest/index.cjs +1 -0
  34. package/dist/plugins/assetManifest/index.d.cts +162 -0
  35. package/dist/plugins/assetManifest/index.d.mts +162 -0
  36. package/dist/plugins/assetManifest/index.d.ts +162 -0
  37. package/dist/plugins/assetManifest/index.mjs +1 -0
  38. package/dist/plugins/autoImport/index.cjs +13 -13
  39. package/dist/plugins/autoImport/index.mjs +8 -8
  40. package/dist/plugins/bundleAnalyzer/index.cjs +1 -1
  41. package/dist/plugins/bundleAnalyzer/index.mjs +2 -2
  42. package/dist/plugins/compressAssets/index.cjs +1 -1
  43. package/dist/plugins/compressAssets/index.mjs +1 -1
  44. package/dist/plugins/copyFile/index.cjs +1 -1
  45. package/dist/plugins/copyFile/index.mjs +1 -1
  46. package/dist/plugins/envGuard/index.cjs +1 -1
  47. package/dist/plugins/envGuard/index.mjs +1 -1
  48. package/dist/plugins/faviconManager/index.cjs +1 -1
  49. package/dist/plugins/faviconManager/index.mjs +1 -1
  50. package/dist/plugins/generateRouter/index.cjs +3 -3
  51. package/dist/plugins/generateRouter/index.mjs +1 -1
  52. package/dist/plugins/generateVersion/index.cjs +1 -1
  53. package/dist/plugins/generateVersion/index.mjs +1 -1
  54. package/dist/plugins/htmlInject/index.cjs +7 -7
  55. package/dist/plugins/htmlInject/index.mjs +2 -2
  56. package/dist/plugins/imageOptimizer/index.cjs +5 -0
  57. package/dist/plugins/imageOptimizer/index.d.cts +242 -0
  58. package/dist/plugins/imageOptimizer/index.d.mts +242 -0
  59. package/dist/plugins/imageOptimizer/index.d.ts +242 -0
  60. package/dist/plugins/imageOptimizer/index.mjs +5 -0
  61. package/dist/plugins/index.cjs +1 -1
  62. package/dist/plugins/index.d.cts +2 -0
  63. package/dist/plugins/index.d.mts +2 -0
  64. package/dist/plugins/index.d.ts +2 -0
  65. package/dist/plugins/index.mjs +1 -1
  66. package/package.json +25 -1
@@ -0,0 +1,242 @@
1
+ import { BasePluginOptions, PluginFactory } from '../../factory/index.js';
2
+ import 'vite';
3
+ import '../../shared/vite-plugin.B8FuZce1.js';
4
+ import '../../shared/vite-plugin.DRRlWY8P.js';
5
+
6
+ /**
7
+ * 支持的图片格式类型
8
+ *
9
+ * @description 插件支持的所有图片格式:
10
+ * - `jpeg`: JPEG/JPG 格式
11
+ * - `png`: PNG 格式
12
+ * - `webp`: WebP 格式
13
+ * - `avif`: AVIF 格式
14
+ * - `gif`: GIF 格式
15
+ * - `tiff`: TIFF 格式
16
+ * - `svg`: SVG 矢量格式
17
+ */
18
+ type ImageFormat = 'jpeg' | 'png' | 'webp' | 'avif' | 'gif' | 'tiff' | 'svg';
19
+ /**
20
+ * 格式转换映射配置
21
+ *
22
+ * @description 定义从源格式到目标格式的转换规则。
23
+ * 键为源格式,值为目标格式。仅配置需要转换的格式。
24
+ *
25
+ * @example
26
+ * ```typescript
27
+ * const convertMap: ConvertMapping = {
28
+ * png: 'webp', // PNG → WebP
29
+ * jpeg: 'avif' // JPEG → AVIF
30
+ * }
31
+ * ```
32
+ */
33
+ type ConvertMapping = Partial<Record<ImageFormat, ImageFormat>>;
34
+ /**
35
+ * 单个图片格式的优化配置
36
+ *
37
+ * @interface FormatQualityOptions
38
+ * @description 针对特定图片格式的压缩质量参数。
39
+ * 不同格式使用不同的质量衡量标准。
40
+ */
41
+ interface FormatQualityOptions {
42
+ /** JPEG 质量,范围 1-100,默认 80 */
43
+ jpeg?: number;
44
+ /** PNG 压缩级别,范围 1-9(仅 palette-based),默认 6 */
45
+ png?: number;
46
+ /** WebP 质量,范围 1-100,默认 75 */
47
+ webp?: number;
48
+ /** AVIF 质量,范围 1-100,默认 50 */
49
+ avif?: number;
50
+ /** GIF 优化选项:是否尝试调色板优化,默认 true */
51
+ gif?: boolean;
52
+ /** TIFF 压缩选项:压缩算法,默认 'deflate' */
53
+ tiff?: 'none' | 'lzw' | 'deflate' | 'packbits';
54
+ }
55
+ /**
56
+ * SVGO 单个插件配置
57
+ *
58
+ * @interface SvgoPlugin
59
+ * @description SVGO 插件配置项,name 为插件名称,其余为插件参数。
60
+ */
61
+ interface SvgoPlugin {
62
+ /** SVGO 插件名称 */
63
+ name: string;
64
+ /** 插件参数 */
65
+ [key: string]: unknown;
66
+ }
67
+ /**
68
+ * SVG 优化配置
69
+ *
70
+ * @interface SvgoOptions
71
+ * @description 传递给 SVGO 的插件配置,与 SVGO 官方配置格式一致。
72
+ * 每项为 SVGO 插件名称及激活状态。
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * const svgo: SvgoOptions = {
77
+ * plugins: [
78
+ * { name: 'removeViewBox', active: false },
79
+ * { name: 'removeEmptyContainers', active: true }
80
+ * ]
81
+ * }
82
+ * ```
83
+ */
84
+ interface SvgoOptions {
85
+ /** SVGO 插件列表 */
86
+ plugins?: SvgoPlugin[];
87
+ /** 是否启用 SVGO 多进程优化(仅当 SVG 文件较多时建议开启) */
88
+ multipass?: boolean;
89
+ }
90
+ /**
91
+ * 单个文件的优化统计信息
92
+ *
93
+ * @interface ImageOptimizeStats
94
+ * @description 记录单个图片文件经过优化后的详细统计数据
95
+ */
96
+ interface ImageOptimizeStats {
97
+ /** 原始文件路径 */
98
+ file: string;
99
+ /** 相对于输出目录的相对路径 */
100
+ relativePath: string;
101
+ /** 原始文件大小(字节) */
102
+ originalSize: number;
103
+ /** 优化后文件大小(字节) */
104
+ optimizedSize: number;
105
+ /** 压缩率百分比(0-100),如 65.2 表示体积减少 65.2% */
106
+ ratio: number;
107
+ /** 源图片格式 */
108
+ sourceFormat: ImageFormat;
109
+ /** 输出图片格式(与 sourceFormat 相同表示仅压缩,不同表示格式转换) */
110
+ outputFormat: ImageFormat;
111
+ /** 是否发生了格式转换 */
112
+ converted: boolean;
113
+ /** 优化耗时(毫秒) */
114
+ duration: number;
115
+ }
116
+ /**
117
+ * 优化操作的汇总统计信息
118
+ *
119
+ * @interface ImageOptimizeSummary
120
+ * @description 包含整个优化操作的总体统计数据,用于报告生成和日志输出
121
+ */
122
+ interface ImageOptimizeSummary {
123
+ /** 优化的文件总数 */
124
+ totalFiles: number;
125
+ /** 跳过的文件数量 */
126
+ skippedFiles: number;
127
+ /** 失败的文件数量 */
128
+ failedFiles: number;
129
+ /** 所有文件的原始大小总和(字节) */
130
+ totalOriginalSize: number;
131
+ /** 所有文件的优化后大小总和(字节) */
132
+ totalOptimizedSize: number;
133
+ /** 总体压缩率百分比 */
134
+ totalRatio: number;
135
+ /** 按格式分组的统计 */
136
+ byFormat: Record<string, {
137
+ count: number;
138
+ originalSize: number;
139
+ optimizedSize: number;
140
+ ratio: number;
141
+ }>;
142
+ /** 格式转换统计:转换的文件数量 */
143
+ convertedFiles: number;
144
+ /** 优化操作总耗时(毫秒) */
145
+ executionTime: number;
146
+ /** 每个文件的详细优化统计 */
147
+ stats: ImageOptimizeStats[];
148
+ }
149
+ /**
150
+ * 图片优化插件的配置选项
151
+ *
152
+ * @interface ImageOptimizerOptions
153
+ * @extends {BasePluginOptions}
154
+ *
155
+ * @example
156
+ * ```typescript
157
+ * imageOptimizer({
158
+ * quality: { jpeg: 80, webp: 75, avif: 50 },
159
+ * convertToWebp: { png: true, jpeg: true },
160
+ * convertToAvif: { png: true },
161
+ * svgo: { plugins: [{ name: 'removeViewBox', active: false }] },
162
+ * keepOriginal: true,
163
+ * parallelLimit: 5,
164
+ * reportOutput: 'image-optimize-report.json'
165
+ * })
166
+ * ```
167
+ */
168
+ interface ImageOptimizerOptions extends BasePluginOptions {
169
+ /** 各格式的压缩质量参数 */
170
+ quality?: FormatQualityOptions;
171
+ /** 是否将指定格式转换为 WebP,值为需要转换的源格式映射 */
172
+ convertToWebp?: Partial<Record<'jpeg' | 'png' | 'gif' | 'tiff', boolean>>;
173
+ /** 是否将指定格式转换为 AVIF,值为需要转换的源格式映射 */
174
+ convertToAvif?: Partial<Record<'jpeg' | 'png' | 'gif' | 'tiff', boolean>>;
175
+ /** 自定义格式转换映射,优先级高于 convertToWebp/convertToAvif */
176
+ convertMapping?: ConvertMapping;
177
+ /** SVG 优化配置 */
178
+ svgo?: SvgoOptions;
179
+ /** 需要优化的文件扩展名列表 */
180
+ includeExtensions?: string[];
181
+ /** 需要排除的路径前缀列表 */
182
+ excludePaths?: string[];
183
+ /** 最小优化阈值(字节),小于此大小的文件将被跳过 */
184
+ threshold?: number;
185
+ /** 是否保留原始文件(格式转换时有效,仅压缩时原文件始终被覆盖) */
186
+ keepOriginal?: boolean;
187
+ /** 压缩报告输出路径,设为 false 则不生成报告 */
188
+ reportOutput?: string | false;
189
+ /** 并发优化的最大文件数 */
190
+ parallelLimit?: number;
191
+ /** 单个图片最大像素数,超过此值的图片将被缩放(0 表示不限制) */
192
+ maxPixels?: number;
193
+ }
194
+
195
+ /**
196
+ * 创建图片优化插件
197
+ *
198
+ * @function imageOptimizer
199
+ * @param {Partial<ImageOptimizerOptions>} [options] - 插件配置选项
200
+ * @returns {Plugin} Vite 插件实例
201
+ *
202
+ * @description 在 Vite 构建完成后自动优化输出目录中的图片文件,
203
+ * 支持多格式压缩、格式转换、并发处理、压缩报告生成等功能。
204
+ * 使用 sharp 处理位图格式,svgo 处理 SVG 格式。
205
+ *
206
+ * @example
207
+ * ```typescript
208
+ * // 基本使用:仅压缩
209
+ * imageOptimizer({
210
+ * quality: { jpeg: 80, png: 6, webp: 75 },
211
+ * reportOutput: 'image-optimize-report.json'
212
+ * })
213
+ *
214
+ * // 格式转换:PNG/JPEG → WebP
215
+ * imageOptimizer({
216
+ * convertToWebp: { png: true, jpeg: true },
217
+ * keepOriginal: true,
218
+ * quality: { webp: 75 }
219
+ * })
220
+ *
221
+ * // 自定义转换映射
222
+ * imageOptimizer({
223
+ * convertMapping: { png: 'avif', jpeg: 'webp' },
224
+ * quality: { avif: 50, webp: 75 }
225
+ * })
226
+ *
227
+ * // SVG 优化
228
+ * imageOptimizer({
229
+ * svgo: {
230
+ * plugins: [
231
+ * { name: 'removeViewBox', active: false },
232
+ * { name: 'removeEmptyContainers', active: true }
233
+ * ],
234
+ * multipass: true
235
+ * }
236
+ * })
237
+ * ```
238
+ */
239
+ declare const imageOptimizer: PluginFactory<ImageOptimizerOptions, ImageOptimizerOptions>;
240
+
241
+ export { imageOptimizer };
242
+ export type { ConvertMapping, FormatQualityOptions, ImageFormat, ImageOptimizeStats, ImageOptimizeSummary, ImageOptimizerOptions, SvgoOptions, SvgoPlugin };
@@ -0,0 +1,5 @@
1
+ import{createPluginFactory as A,BasePlugin as B}from"../../factory/index.mjs";import{promises as c}from"node:fs";import y from"node:path";import{scanDirectory as x,resolveReportPath as O,writeJsonReport as k}from"../../common/fs/index.mjs";import{normalizePath as R,isPathExcluded as j}from"../../common/path/index.mjs";import{calcRatio as h,formatFileSize as g}from"../../common/format/index.mjs";import{runWithConcurrency as D}from"../../common/concurrency/index.mjs";import"../../logger/index.mjs";import"../../shared/vite-plugin.DcExl6jd.mjs";import"fs";import"path";const T={".jpg":"jpeg",".jpeg":"jpeg",".png":"png",".webp":"webp",".avif":"avif",".gif":"gif",".tiff":"tiff",".tif":"tiff",".svg":"svg"};function z(e){return T[e]??null}function V(e){return{jpeg:".jpg",png:".png",webp:".webp",avif:".avif",gif:".gif",tiff:".tiff",svg:".svg"}[e]}function I(e,u,t,i){return!(!z(u)||t<i.threshold||i.includeExtensions.length>0&&!i.includeExtensions.includes(u)||j(e,i.excludePaths))}async function G(e,u){return(await x(e,{filter:(t,i,r)=>{const o=y.relative(e,t);return I(o,i,r,u)}})).map(t=>{const i=R(y.relative(e,t.filePath)),r=z(t.extension);return{filePath:t.filePath,relativePath:i,size:t.size,ext:t.extension,format:r}})}let m=null,v=!1;async function E(){if(m)return m;if(v)throw new Error("sharp \u6A21\u5757\u4E0D\u53EF\u7528\uFF0C\u8BF7\u5B89\u88C5: npm install sharp");v=!0;try{const e=await import("sharp");return m=e.default||e,m}catch{throw new Error(`sharp \u6A21\u5757\u52A0\u8F7D\u5931\u8D25\u3002\u56FE\u7247\u4F18\u5316\u63D2\u4EF6\u9700\u8981 sharp \u4F5C\u4E3A\u4F9D\u8D56\u3002
2
+ \u8BF7\u8FD0\u884C: npm install sharp
3
+ sharp \u662F\u53EF\u9009\u4F9D\u8D56\uFF0C\u5982\u4E0D\u9700\u8981\u56FE\u7247\u4F18\u5316\u529F\u80FD\u53EF\u5FFD\u7565\u6B64\u9519\u8BEF\u3002`)}}let d=null,C=!1;async function S(){if(d)return d;if(C)throw new Error("svgo \u6A21\u5757\u4E0D\u53EF\u7528\uFF0C\u8BF7\u5B89\u88C5: npm install svgo");C=!0;try{const e=await import("svgo");return d=e.default||e,d}catch{throw new Error(`svgo \u6A21\u5757\u52A0\u8F7D\u5931\u8D25\u3002SVG \u4F18\u5316\u9700\u8981 svgo \u4F5C\u4E3A\u4F9D\u8D56\u3002
4
+ \u8BF7\u8FD0\u884C: npm install svgo
5
+ \u5982\u4E0D\u9700\u8981 SVG \u4F18\u5316\u529F\u80FD\u53EF\u5FFD\u7565\u6B64\u9519\u8BEF\u3002`)}}function M(e,u){const t={jpeg:80,png:6,webp:75,avif:50,gif:!0,tiff:"deflate"};return u[e]??t[e]}function $(e,u){const t=M(e,u);switch(e){case"jpeg":return{quality:t,mozjpeg:!0};case"png":return{palette:!0,compressionLevel:t};case"webp":return{quality:t,effort:4};case"avif":return{quality:t,effort:4};case"gif":return{effort:7,colours:t===!0?void 0:t};case"tiff":return{compression:t};default:return{}}}async function q(e,u,t,i){const r=Date.now(),o=await E(),p=(await c.stat(e)).size;let l=o(e,{limitInputPixels:i>0?i:void 0});l=l.rotate();const a=$(u,t);l=l.toFormat(u,a),await l.toFile(e+".tmp");const s=(await c.stat(e+".tmp")).size;if(s<p)try{await c.rename(e+".tmp",e)}catch{try{await c.unlink(e+".tmp")}catch{}throw new Error(`\u538B\u7F29\u5931\u8D25: \u65E0\u6CD5\u5199\u5165\u8F93\u51FA\u6587\u4EF6 ${e}`)}else await c.unlink(e+".tmp");const n=Date.now()-r,F=s<p?s:p;return{file:e,relativePath:"",originalSize:p,optimizedSize:F,ratio:h(p,F),sourceFormat:u,outputFormat:u,converted:!1,duration:n}}async function L(e,u,t,i,r,o){const p=Date.now(),l=await E(),a=(await c.stat(e)).size;let s=l(e,{limitInputPixels:r>0?r:void 0});s=s.rotate();const n=$(t,i);s=s.toFormat(t,n);const F=V(t),f=e.replace(/\.[^.]+$/,F);await s.toFile(f+".tmp");const w=(await c.stat(f+".tmp")).size;try{await c.rename(f+".tmp",f)}catch{try{await c.unlink(f+".tmp")}catch{}throw new Error(`\u683C\u5F0F\u8F6C\u6362\u5931\u8D25: \u65E0\u6CD5\u5199\u5165\u8F93\u51FA\u6587\u4EF6 ${f}`)}if(!o&&f!==e)try{await c.unlink(e)}catch{}const b=Date.now()-p;return{file:o?f:e,relativePath:"",originalSize:a,optimizedSize:w,ratio:h(a,w),sourceFormat:u,outputFormat:t,converted:!0,duration:b}}async function W(e,u){const t=Date.now(),{optimize:i}=await S(),r=(await c.stat(e)).size,o=await c.readFile(e,"utf-8"),p=i(o,{path:e,multipass:u.multipass??!1,plugins:u.plugins??[]}),l=Buffer.byteLength(p.data,"utf-8");l<r&&await c.writeFile(e,p.data,"utf-8");const a=l<r?l:r,s=Date.now()-t;return{file:e,relativePath:"",originalSize:r,optimizedSize:a,ratio:h(r,a),sourceFormat:"svg",outputFormat:"svg",converted:!1,duration:s}}async function J(){if(m)return!0;if(v)return!1;try{return await E(),!0}catch{return!1}}async function N(){if(d)return!0;if(C)return!1;try{return await S(),!0}catch{return!1}}function P(e){const u={};if(e.convertToWebp)for(const[t,i]of Object.entries(e.convertToWebp))i&&t!=="svg"&&t!=="webp"&&t!=="avif"&&(u[t]="webp");if(e.convertToAvif)for(const[t,i]of Object.entries(e.convertToAvif))i&&t!=="svg"&&t!=="webp"&&t!=="avif"&&(u[t]="avif");return e.convertMapping&&Object.assign(u,e.convertMapping),u}function H(e,u){return u[e]??e}function U(e,u){return e in u}function K(e){const u=[];for(const[t,i]of Object.entries(e))t===i&&u.push(`\u6E90\u683C\u5F0F\u548C\u76EE\u6807\u683C\u5F0F\u4E0D\u80FD\u76F8\u540C: ${t}`),i==="svg"&&u.push(`\u4E0D\u652F\u6301\u5C06 ${t} \u8F6C\u6362\u4E3A svg \u683C\u5F0F`),t==="svg"&&u.push(`\u4E0D\u652F\u6301\u5C06 svg \u8F6C\u6362\u4E3A ${i} \u683C\u5F0F\uFF0CSVG \u5E94\u4F7F\u7528 svgo \u5355\u72EC\u4F18\u5316`);return u}function Q(e,u,t,i){const r=e.reduce((s,n)=>s+n.originalSize,0),o=e.reduce((s,n)=>s+n.optimizedSize,0),p=h(r,o),l=e.filter(s=>s.converted).length,a={};for(const s of e){const n=s.outputFormat;a[n]||(a[n]={count:0,originalSize:0,optimizedSize:0,ratio:0}),a[n].count++,a[n].originalSize+=s.originalSize,a[n].optimizedSize+=s.optimizedSize}for(const s of Object.values(a))s.ratio=h(s.originalSize,s.optimizedSize);return{totalFiles:e.length,skippedFiles:u,failedFiles:t,totalOriginalSize:r,totalOptimizedSize:o,totalRatio:p,byFormat:a,convertedFiles:l,executionTime:i,stats:e}}async function X(e,u,t){const i=O(e,u);if(!i)return;const r={timestamp:new Date().toISOString(),summary:{totalFiles:t.totalFiles,skippedFiles:t.skippedFiles,failedFiles:t.failedFiles,totalOriginalSize:t.totalOriginalSize,totalOptimizedSize:t.totalOptimizedSize,totalRatio:t.totalRatio,convertedFiles:t.convertedFiles,executionTime:t.executionTime},byFormat:t.byFormat,files:t.stats.map(o=>({file:o.file,relativePath:o.relativePath,originalSize:o.originalSize,optimizedSize:o.optimizedSize,ratio:o.ratio,sourceFormat:o.sourceFormat,outputFormat:o.outputFormat,converted:o.converted,duration:o.duration}))};await k(i,r)}class Y extends B{allStats=[];summary=null;skippedCount=0;failedCount=0;sharpReady=!1;svgoReady=!1;dependencyChecked=!1;convertMapping={};getDefaultOptions(){return{quality:{jpeg:80,png:6,webp:75,avif:50,gif:!0,tiff:"deflate"},convertToWebp:{},convertToAvif:{},convertMapping:{},svgo:{plugins:[],multipass:!1},includeExtensions:[".jpg",".jpeg",".png",".webp",".avif",".gif",".tiff",".tif",".svg"],excludePaths:[],threshold:0,keepOriginal:!0,reportOutput:"image-optimize-report.json",parallelLimit:5,maxPixels:0}}validateOptions(){this.validator.field("threshold").number().minValue(0).field("keepOriginal").boolean().field("includeExtensions").array().field("excludePaths").array().field("reportOutput").custom(i=>i===!1||typeof i=="string","reportOutput \u5FC5\u987B\u4E3A false \u6216\u5B57\u7B26\u4E32\u8DEF\u5F84").field("parallelLimit").number().minValue(1).maxValue(50).field("maxPixels").number().minValue(0).validate();const u=P(this.options),t=K(u);if(t.length>0)throw new Error(`\u56FE\u7247\u4F18\u5316\u914D\u7F6E\u9519\u8BEF: ${t.join("; ")}`)}getPluginName(){return"image-optimizer"}getEnforce(){return"post"}addPluginHooks(u){u.writeBundle=async()=>{await this.safeExecute(()=>this.optimizeAllImages(),"\u4F18\u5316\u56FE\u7247\u8D44\u6E90")}}onConfigResolved(u){super.onConfigResolved(u),this.convertMapping=P(this.options)}async checkDependencies(){this.sharpReady=await J(),this.svgoReady=await N(),this.sharpReady||this.logger.warn("sharp \u6A21\u5757\u4E0D\u53EF\u7528\uFF0C\u4F4D\u56FE\u683C\u5F0F\uFF08JPEG/PNG/WebP/AVIF/GIF/TIFF\uFF09\u4F18\u5316\u5C06\u8DF3\u8FC7\u3002\u8BF7\u5B89\u88C5: npm install sharp"),this.svgoReady||this.logger.warn("svgo \u6A21\u5757\u4E0D\u53EF\u7528\uFF0CSVG \u4F18\u5316\u5C06\u8DF3\u8FC7\u3002\u8BF7\u5B89\u88C5: npm install svgo"),!this.sharpReady&&!this.svgoReady&&this.logger.warn("sharp \u548C svgo \u5747\u4E0D\u53EF\u7528\uFF0C\u56FE\u7247\u4F18\u5316\u63D2\u4EF6\u5C06\u4E0D\u6267\u884C\u4EFB\u4F55\u64CD\u4F5C")}async optimizeAllImages(){if(!this.viteConfig)return;if(this.dependencyChecked||(await this.checkDependencies(),this.dependencyChecked=!0),!this.sharpReady&&!this.svgoReady){this.logger.warn("\u4F9D\u8D56\u4E0D\u53EF\u7528\uFF0C\u8DF3\u8FC7\u56FE\u7247\u4F18\u5316");return}const u=this.viteConfig.build.outDir,t=Date.now();this.logger.info(`\u5F00\u59CB\u626B\u63CF\u56FE\u7247\u6587\u4EF6: ${u}`);const i=await G(u,this.options);if(i.length===0){this.logger.info("\u672A\u627E\u5230\u9700\u8981\u4F18\u5316\u7684\u56FE\u7247\u6587\u4EF6");return}const r=i.filter(l=>l.format==="svg"),o=i.filter(l=>l.format!=="svg");if(this.logger.info(`\u53D1\u73B0 ${i.length} \u4E2A\u5F85\u4F18\u5316\u56FE\u7247 (\u4F4D\u56FE: ${o.length}, SVG: ${r.length})`),this.allStats=[],this.skippedCount=0,this.failedCount=0,o.length>0&&this.sharpReady){const l=await D(o,async a=>this.processBitmap({...a,format:a.format}),this.options.parallelLimit);for(const a of l)a.skipped?this.skippedCount++:a.error?(this.failedCount++,this.logger.warn(`\u4F18\u5316\u5931\u8D25: ${a.error}`)):a.stat&&this.allStats.push(a.stat)}else o.length>0&&!this.sharpReady&&(this.skippedCount+=o.length,this.logger.info(`\u8DF3\u8FC7 ${o.length} \u4E2A\u4F4D\u56FE\u6587\u4EF6\uFF08sharp \u4E0D\u53EF\u7528\uFF09`));if(r.length>0&&this.svgoReady){const l=await D(r,async a=>this.processSvg(a),this.options.parallelLimit);for(const a of l)a.skipped?this.skippedCount++:a.error?(this.failedCount++,this.logger.warn(`SVG \u4F18\u5316\u5931\u8D25: ${a.error}`)):a.stat&&this.allStats.push(a.stat)}else r.length>0&&!this.svgoReady&&(this.skippedCount+=r.length,this.logger.info(`\u8DF3\u8FC7 ${r.length} \u4E2A SVG \u6587\u4EF6\uFF08svgo \u4E0D\u53EF\u7528\uFF09`));const p=Date.now()-t;this.summary=Q(this.allStats,this.skippedCount,this.failedCount,p),this.options.reportOutput&&(await X(u,this.options.reportOutput,this.summary),this.logger.info(`\u4F18\u5316\u62A5\u544A\u5DF2\u751F\u6210: ${this.options.reportOutput}`)),this.logSummary()}async processBitmap(u){try{const t=H(u.format,this.convertMapping);let i;return U(u.format,this.convertMapping)?i=await L(u.filePath,u.format,t,this.options.quality,this.options.maxPixels,this.options.keepOriginal):i=await q(u.filePath,u.format,this.options.quality,this.options.maxPixels),i.relativePath=u.relativePath,{stat:i}}catch(t){const i=t instanceof Error?t.message:String(t);return{error:`${u.relativePath}: ${i}`}}}async processSvg(u){try{const t=await W(u.filePath,this.options.svgo);return t.relativePath=u.relativePath,{stat:t}}catch(t){const i=t instanceof Error?t.message:String(t);return{error:`${u.relativePath}: ${i}`}}}logSummary(){if(!this.summary)return;const{totalFiles:u,skippedFiles:t,failedFiles:i,totalOriginalSize:r,totalOptimizedSize:o,totalRatio:p,convertedFiles:l,executionTime:a}=this.summary;this.logger.success(`\u56FE\u7247\u4F18\u5316\u5B8C\u6210: ${u} \u4E2A\u6587\u4EF6\u5DF2\u4F18\u5316`+(t>0?`\uFF0C${t} \u4E2A\u8DF3\u8FC7`:"")+(i>0?`\uFF0C${i} \u4E2A\u5931\u8D25`:""),`\u539F\u59CB\u4F53\u79EF: ${g(r)} \u2192 \u4F18\u5316\u540E: ${g(o)}\uFF0C\u538B\u7F29\u7387: ${p}%`+(l>0?`\uFF0C\u683C\u5F0F\u8F6C\u6362: ${l} \u4E2A`:"")+`\uFF0C\u8017\u65F6: ${a}ms`);for(const[n,F]of Object.entries(this.summary.byFormat))this.logger.info(` ${n.toUpperCase().padEnd(5)} ${F.count} \u4E2A\u6587\u4EF6\uFF0C${g(F.originalSize)} \u2192 ${g(F.optimizedSize)}\uFF0C\u538B\u7F29\u7387: ${F.ratio}%`);const s=[...this.allStats].sort((n,F)=>F.ratio-n.ratio).slice(0,5);if(s.length>0){this.logger.info("\u538B\u7F29\u7387 Top 5:");for(const n of s){const F=n.converted?` (${n.sourceFormat}\u2192${n.outputFormat})`:"";this.logger.info(` ${n.ratio}% ${g(n.originalSize)} \u2192 ${g(n.optimizedSize)}${F} ${n.relativePath}`)}}}getStats(){return[...this.allStats]}getSummary(){return this.summary}}const Z=A(Y);export{Z as imageOptimizer};
@@ -1 +1 @@
1
- "use strict";const plugins_autoImport_index=require("./autoImport/index.cjs"),plugins_buildProgress_index=require("./buildProgress/index.cjs"),plugins_bundleAnalyzer_index=require("./bundleAnalyzer/index.cjs"),plugins_compressAssets_index=require("./compressAssets/index.cjs"),plugins_copyFile_index=require("./copyFile/index.cjs"),plugins_envGuard_index=require("./envGuard/index.cjs"),plugins_faviconManager_index=require("./faviconManager/index.cjs"),plugins_generateRouter_index=require("./generateRouter/index.cjs"),plugins_generateVersion_index=require("./generateVersion/index.cjs"),plugins_htmlInject_index=require("./htmlInject/index.cjs"),plugins_loadingManager_index=require("./loadingManager/index.cjs"),plugins_versionUpdateChecker_index=require("./versionUpdateChecker/index.cjs");require("../factory/index.cjs"),require("../logger/index.cjs"),require("../shared/vite-plugin.Bcg6RW2N.cjs"),require("node:fs"),require("node:path"),require("../common/fs/index.cjs"),require("fs"),require("path"),require("../common/ui/index.cjs"),require("node:zlib"),require("node:util"),require("../common/format/index.cjs"),require("node:stream/promises"),require("../common/html/index.cjs"),require("../shared/vite-plugin.CcvHfrL8.cjs"),require("crypto"),require("../common/script/index.cjs"),require("../common/validation/index.cjs"),exports.autoImport=plugins_autoImport_index.autoImport,exports.buildProgress=plugins_buildProgress_index.buildProgress,exports.bundleAnalyzer=plugins_bundleAnalyzer_index.bundleAnalyzer,exports.compressAssets=plugins_compressAssets_index.compressAssets,exports.copyFile=plugins_copyFile_index.copyFile,exports.envGuard=plugins_envGuard_index.envGuard,exports.faviconManager=plugins_faviconManager_index.faviconManager,exports.generateRouter=plugins_generateRouter_index.generateRouter,exports.generateVersion=plugins_generateVersion_index.generateVersion,exports.htmlInject=plugins_htmlInject_index.htmlInject,exports.loadingManager=plugins_loadingManager_index.loadingManager,exports.versionUpdateChecker=plugins_versionUpdateChecker_index.versionUpdateChecker;
1
+ "use strict";const plugins_assetManifest_index=require("./assetManifest/index.cjs"),plugins_autoImport_index=require("./autoImport/index.cjs"),plugins_buildProgress_index=require("./buildProgress/index.cjs"),plugins_bundleAnalyzer_index=require("./bundleAnalyzer/index.cjs"),plugins_compressAssets_index=require("./compressAssets/index.cjs"),plugins_copyFile_index=require("./copyFile/index.cjs"),plugins_envGuard_index=require("./envGuard/index.cjs"),plugins_faviconManager_index=require("./faviconManager/index.cjs"),plugins_generateRouter_index=require("./generateRouter/index.cjs"),plugins_generateVersion_index=require("./generateVersion/index.cjs"),plugins_htmlInject_index=require("./htmlInject/index.cjs"),plugins_imageOptimizer_index=require("./imageOptimizer/index.cjs"),plugins_loadingManager_index=require("./loadingManager/index.cjs"),plugins_versionUpdateChecker_index=require("./versionUpdateChecker/index.cjs");require("node:path"),require("node:fs"),require("../factory/index.cjs"),require("../logger/index.cjs"),require("../shared/vite-plugin.Bcg6RW2N.cjs"),require("../common/fs/index.cjs"),require("fs"),require("path"),require("../common/concurrency/index.cjs"),require("../common/path/index.cjs"),require("../common/html/index.cjs"),require("../shared/vite-plugin.CcvHfrL8.cjs"),require("../common/validation/index.cjs"),require("../common/ui/index.cjs"),require("node:zlib"),require("node:util"),require("../common/format/index.cjs"),require("node:stream/promises"),require("crypto"),require("../common/script/index.cjs"),exports.assetManifest=plugins_assetManifest_index.assetManifest,exports.autoImport=plugins_autoImport_index.autoImport,exports.buildProgress=plugins_buildProgress_index.buildProgress,exports.bundleAnalyzer=plugins_bundleAnalyzer_index.bundleAnalyzer,exports.compressAssets=plugins_compressAssets_index.compressAssets,exports.copyFile=plugins_copyFile_index.copyFile,exports.envGuard=plugins_envGuard_index.envGuard,exports.faviconManager=plugins_faviconManager_index.faviconManager,exports.generateRouter=plugins_generateRouter_index.generateRouter,exports.generateVersion=plugins_generateVersion_index.generateVersion,exports.htmlInject=plugins_htmlInject_index.htmlInject,exports.imageOptimizer=plugins_imageOptimizer_index.imageOptimizer,exports.loadingManager=plugins_loadingManager_index.loadingManager,exports.versionUpdateChecker=plugins_versionUpdateChecker_index.versionUpdateChecker;
@@ -1,3 +1,4 @@
1
+ export { AssetGroup, AssetManifestOptions, AssetManifestResult, AssetMap, CustomFormatter, ManifestOutputFormat, WebpackEntryAsset, WebpackManifestOutput, assetManifest } from './assetManifest/index.cjs';
1
2
  export { AutoImportOptions, ImportMapping, ResolvedImport, ScannedModule, TransformResult, autoImport } from './autoImport/index.cjs';
2
3
  export { BuildPhase, BuildProgressOptions, ProgressFormat, ProgressTheme, buildProgress } from './buildProgress/index.cjs';
3
4
  export { BundleAnalysisResult, BundleAnalyzerOptions, BundleOutputFormat, ChunkStats, ComparisonDiff, FileTypeDistribution, ModuleStats, SizeWarning, bundleAnalyzer } from './bundleAnalyzer/index.cjs';
@@ -8,6 +9,7 @@ export { FaviconManagerOptions, Icon, faviconManager } from './faviconManager/in
8
9
  export { GenerateRouterOptions, NameStrategy, OutputFormat, RouteConfig, RouteMeta, UniAppPageConfig, UniAppPagesJson, UniAppTabBarConfig, generateRouter } from './generateRouter/index.cjs';
9
10
  export { GenerateVersionOptions, OutputType, VersionFormat, VersionInfo, generateVersion } from './generateVersion/index.cjs';
10
11
  export { HtmlInjectOptions, InjectRule, InjectionLogEntry, htmlInject } from './htmlInject/index.cjs';
12
+ export { ConvertMapping, FormatQualityOptions, ImageFormat, ImageOptimizeStats, ImageOptimizeSummary, ImageOptimizerOptions, SvgoOptions, SvgoPlugin, imageOptimizer } from './imageOptimizer/index.cjs';
11
13
  export { AutoBindMode, AutoHideOn, DebounceHide, DelayShow, LoadingCallbacks, LoadingManager, LoadingManagerOptions, LoadingPosition, LoadingStyle, MinDisplayTime, RequestFilter, SpinnerType, TransitionConfig, loadingManager } from './loadingManager/index.cjs';
12
14
  export { PromptStyle, VersionSource, VersionUpdateCheckerOptions, versionUpdateChecker } from './versionUpdateChecker/index.cjs';
13
15
  import '../factory/index.cjs';
@@ -1,3 +1,4 @@
1
+ export { AssetGroup, AssetManifestOptions, AssetManifestResult, AssetMap, CustomFormatter, ManifestOutputFormat, WebpackEntryAsset, WebpackManifestOutput, assetManifest } from './assetManifest/index.mjs';
1
2
  export { AutoImportOptions, ImportMapping, ResolvedImport, ScannedModule, TransformResult, autoImport } from './autoImport/index.mjs';
2
3
  export { BuildPhase, BuildProgressOptions, ProgressFormat, ProgressTheme, buildProgress } from './buildProgress/index.mjs';
3
4
  export { BundleAnalysisResult, BundleAnalyzerOptions, BundleOutputFormat, ChunkStats, ComparisonDiff, FileTypeDistribution, ModuleStats, SizeWarning, bundleAnalyzer } from './bundleAnalyzer/index.mjs';
@@ -8,6 +9,7 @@ export { FaviconManagerOptions, Icon, faviconManager } from './faviconManager/in
8
9
  export { GenerateRouterOptions, NameStrategy, OutputFormat, RouteConfig, RouteMeta, UniAppPageConfig, UniAppPagesJson, UniAppTabBarConfig, generateRouter } from './generateRouter/index.mjs';
9
10
  export { GenerateVersionOptions, OutputType, VersionFormat, VersionInfo, generateVersion } from './generateVersion/index.mjs';
10
11
  export { HtmlInjectOptions, InjectRule, InjectionLogEntry, htmlInject } from './htmlInject/index.mjs';
12
+ export { ConvertMapping, FormatQualityOptions, ImageFormat, ImageOptimizeStats, ImageOptimizeSummary, ImageOptimizerOptions, SvgoOptions, SvgoPlugin, imageOptimizer } from './imageOptimizer/index.mjs';
11
13
  export { AutoBindMode, AutoHideOn, DebounceHide, DelayShow, LoadingCallbacks, LoadingManager, LoadingManagerOptions, LoadingPosition, LoadingStyle, MinDisplayTime, RequestFilter, SpinnerType, TransitionConfig, loadingManager } from './loadingManager/index.mjs';
12
14
  export { PromptStyle, VersionSource, VersionUpdateCheckerOptions, versionUpdateChecker } from './versionUpdateChecker/index.mjs';
13
15
  import '../factory/index.mjs';
@@ -1,3 +1,4 @@
1
+ export { AssetGroup, AssetManifestOptions, AssetManifestResult, AssetMap, CustomFormatter, ManifestOutputFormat, WebpackEntryAsset, WebpackManifestOutput, assetManifest } from './assetManifest/index.js';
1
2
  export { AutoImportOptions, ImportMapping, ResolvedImport, ScannedModule, TransformResult, autoImport } from './autoImport/index.js';
2
3
  export { BuildPhase, BuildProgressOptions, ProgressFormat, ProgressTheme, buildProgress } from './buildProgress/index.js';
3
4
  export { BundleAnalysisResult, BundleAnalyzerOptions, BundleOutputFormat, ChunkStats, ComparisonDiff, FileTypeDistribution, ModuleStats, SizeWarning, bundleAnalyzer } from './bundleAnalyzer/index.js';
@@ -8,6 +9,7 @@ export { FaviconManagerOptions, Icon, faviconManager } from './faviconManager/in
8
9
  export { GenerateRouterOptions, NameStrategy, OutputFormat, RouteConfig, RouteMeta, UniAppPageConfig, UniAppPagesJson, UniAppTabBarConfig, generateRouter } from './generateRouter/index.js';
9
10
  export { GenerateVersionOptions, OutputType, VersionFormat, VersionInfo, generateVersion } from './generateVersion/index.js';
10
11
  export { HtmlInjectOptions, InjectRule, InjectionLogEntry, htmlInject } from './htmlInject/index.js';
12
+ export { ConvertMapping, FormatQualityOptions, ImageFormat, ImageOptimizeStats, ImageOptimizeSummary, ImageOptimizerOptions, SvgoOptions, SvgoPlugin, imageOptimizer } from './imageOptimizer/index.js';
11
13
  export { AutoBindMode, AutoHideOn, DebounceHide, DelayShow, LoadingCallbacks, LoadingManager, LoadingManagerOptions, LoadingPosition, LoadingStyle, MinDisplayTime, RequestFilter, SpinnerType, TransitionConfig, loadingManager } from './loadingManager/index.js';
12
14
  export { PromptStyle, VersionSource, VersionUpdateCheckerOptions, versionUpdateChecker } from './versionUpdateChecker/index.js';
13
15
  import '../factory/index.js';
@@ -1 +1 @@
1
- export{autoImport}from"./autoImport/index.mjs";export{buildProgress}from"./buildProgress/index.mjs";export{bundleAnalyzer}from"./bundleAnalyzer/index.mjs";export{compressAssets}from"./compressAssets/index.mjs";export{copyFile}from"./copyFile/index.mjs";export{envGuard}from"./envGuard/index.mjs";export{faviconManager}from"./faviconManager/index.mjs";export{generateRouter}from"./generateRouter/index.mjs";export{generateVersion}from"./generateVersion/index.mjs";export{htmlInject}from"./htmlInject/index.mjs";export{loadingManager}from"./loadingManager/index.mjs";export{versionUpdateChecker}from"./versionUpdateChecker/index.mjs";import"../factory/index.mjs";import"../logger/index.mjs";import"../shared/vite-plugin.DcExl6jd.mjs";import"node:fs";import"node:path";import"../common/fs/index.mjs";import"fs";import"path";import"../common/ui/index.mjs";import"node:zlib";import"node:util";import"../common/format/index.mjs";import"node:stream/promises";import"../common/html/index.mjs";import"../shared/vite-plugin.CuXEJAWX.mjs";import"crypto";import"../common/script/index.mjs";import"../common/validation/index.mjs";
1
+ export{assetManifest}from"./assetManifest/index.mjs";export{autoImport}from"./autoImport/index.mjs";export{buildProgress}from"./buildProgress/index.mjs";export{bundleAnalyzer}from"./bundleAnalyzer/index.mjs";export{compressAssets}from"./compressAssets/index.mjs";export{copyFile}from"./copyFile/index.mjs";export{envGuard}from"./envGuard/index.mjs";export{faviconManager}from"./faviconManager/index.mjs";export{generateRouter}from"./generateRouter/index.mjs";export{generateVersion}from"./generateVersion/index.mjs";export{htmlInject}from"./htmlInject/index.mjs";export{imageOptimizer}from"./imageOptimizer/index.mjs";export{loadingManager}from"./loadingManager/index.mjs";export{versionUpdateChecker}from"./versionUpdateChecker/index.mjs";import"node:path";import"node:fs";import"../factory/index.mjs";import"../logger/index.mjs";import"../shared/vite-plugin.DcExl6jd.mjs";import"../common/fs/index.mjs";import"fs";import"path";import"../common/concurrency/index.mjs";import"../common/path/index.mjs";import"../common/html/index.mjs";import"../shared/vite-plugin.CuXEJAWX.mjs";import"../common/validation/index.mjs";import"../common/ui/index.mjs";import"node:zlib";import"node:util";import"../common/format/index.mjs";import"node:stream/promises";import"crypto";import"../common/script/index.mjs";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@meng-xi/vite-plugin",
3
3
  "type": "module",
4
- "version": "0.1.6",
4
+ "version": "0.1.8",
5
5
  "private": false,
6
6
  "description": "一个为 Vite 提供实用插件的工具包,同时也是一个完整的插件开发框架",
7
7
  "keywords": [
@@ -25,6 +25,11 @@
25
25
  "import": "./dist/common/index.mjs",
26
26
  "types": "./dist/common/index.d.ts"
27
27
  },
28
+ "./common/concurrency": {
29
+ "require": "./dist/common/concurrency/index.cjs",
30
+ "import": "./dist/common/concurrency/index.mjs",
31
+ "types": "./dist/common/concurrency/index.d.ts"
32
+ },
28
33
  "./common/format": {
29
34
  "require": "./dist/common/format/index.cjs",
30
35
  "import": "./dist/common/format/index.mjs",
@@ -40,6 +45,11 @@
40
45
  "import": "./dist/common/html/index.mjs",
41
46
  "types": "./dist/common/html/index.d.ts"
42
47
  },
48
+ "./common/path": {
49
+ "require": "./dist/common/path/index.cjs",
50
+ "import": "./dist/common/path/index.mjs",
51
+ "types": "./dist/common/path/index.d.ts"
52
+ },
43
53
  "./common/script": {
44
54
  "require": "./dist/common/script/index.cjs",
45
55
  "import": "./dist/common/script/index.mjs",
@@ -70,6 +80,11 @@
70
80
  "import": "./dist/plugins/index.mjs",
71
81
  "types": "./dist/plugins/index.d.ts"
72
82
  },
83
+ "./plugins/asset-manifest": {
84
+ "require": "./dist/plugins/assetManifest/index.cjs",
85
+ "import": "./dist/plugins/assetManifest/index.mjs",
86
+ "types": "./dist/plugins/assetManifest/index.d.ts"
87
+ },
73
88
  "./plugins/auto-import": {
74
89
  "require": "./dist/plugins/autoImport/index.cjs",
75
90
  "import": "./dist/plugins/autoImport/index.mjs",
@@ -120,6 +135,11 @@
120
135
  "import": "./dist/plugins/htmlInject/index.mjs",
121
136
  "types": "./dist/plugins/htmlInject/index.d.ts"
122
137
  },
138
+ "./plugins/image-optimizer": {
139
+ "require": "./dist/plugins/imageOptimizer/index.cjs",
140
+ "import": "./dist/plugins/imageOptimizer/index.mjs",
141
+ "types": "./dist/plugins/imageOptimizer/index.d.ts"
142
+ },
123
143
  "./plugins/loading-manager": {
124
144
  "require": "./dist/plugins/loadingManager/index.cjs",
125
145
  "import": "./dist/plugins/loadingManager/index.mjs",
@@ -144,6 +164,10 @@
144
164
  "peerDependencies": {
145
165
  "vite": ">=5.0.0 <8.0.0"
146
166
  },
167
+ "optionalDependencies": {
168
+ "sharp": "^0.33.0",
169
+ "svgo": "^3.3.0"
170
+ },
147
171
  "devDependencies": {
148
172
  "@types/node": "^22.0.0",
149
173
  "tsx": "^4.22.3",