@meng-xi/vite-plugin 0.1.7 → 0.1.9

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 (59) hide show
  1. package/README-en.md +43 -17
  2. package/README.md +56 -30
  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 +3 -2
  20. package/dist/common/index.d.mts +3 -2
  21. package/dist/common/index.d.ts +3 -2
  22. package/dist/common/index.mjs +1 -1
  23. package/dist/index.cjs +1 -1
  24. package/dist/index.d.cts +5 -3
  25. package/dist/index.d.mts +5 -3
  26. package/dist/index.d.ts +5 -3
  27. package/dist/index.mjs +1 -1
  28. package/dist/plugins/assetManifest/index.cjs +1 -1
  29. package/dist/plugins/assetManifest/index.mjs +1 -1
  30. package/dist/plugins/autoImport/index.cjs +13 -13
  31. package/dist/plugins/autoImport/index.mjs +8 -8
  32. package/dist/plugins/bundleAnalyzer/index.cjs +1 -1
  33. package/dist/plugins/bundleAnalyzer/index.mjs +1 -1
  34. package/dist/plugins/compressAssets/index.cjs +1 -1
  35. package/dist/plugins/compressAssets/index.mjs +1 -1
  36. package/dist/plugins/copyFile/index.cjs +1 -1
  37. package/dist/plugins/copyFile/index.mjs +1 -1
  38. package/dist/plugins/envGuard/index.cjs +5 -5
  39. package/dist/plugins/envGuard/index.mjs +8 -8
  40. package/dist/plugins/faviconManager/index.cjs +1 -1
  41. package/dist/plugins/faviconManager/index.mjs +1 -1
  42. package/dist/plugins/generateRouter/index.cjs +62 -5
  43. package/dist/plugins/generateRouter/index.d.cts +29 -1
  44. package/dist/plugins/generateRouter/index.d.mts +29 -1
  45. package/dist/plugins/generateRouter/index.d.ts +29 -1
  46. package/dist/plugins/generateRouter/index.mjs +62 -5
  47. package/dist/plugins/generateVersion/index.cjs +1 -1
  48. package/dist/plugins/generateVersion/index.mjs +1 -1
  49. package/dist/plugins/imageOptimizer/index.cjs +5 -0
  50. package/dist/plugins/imageOptimizer/index.d.cts +242 -0
  51. package/dist/plugins/imageOptimizer/index.d.mts +242 -0
  52. package/dist/plugins/imageOptimizer/index.d.ts +242 -0
  53. package/dist/plugins/imageOptimizer/index.mjs +5 -0
  54. package/dist/plugins/index.cjs +1 -1
  55. package/dist/plugins/index.d.cts +2 -1
  56. package/dist/plugins/index.d.mts +2 -1
  57. package/dist/plugins/index.d.ts +2 -1
  58. package/dist/plugins/index.mjs +1 -1
  59. package/package.json +15 -1
@@ -3,6 +3,30 @@ import 'vite';
3
3
  import '../../shared/vite-plugin.B8FuZce1.js';
4
4
  import '../../shared/vite-plugin.DRRlWY8P.js';
5
5
 
6
+ /**
7
+ * 导航动画类型
8
+ *
9
+ * 用于 uni.navigateTo / uni.navigateBack 的 animationType 参数,
10
+ * 仅 App 端生效,其他平台自动忽略。
11
+ *
12
+ * 显示动画(navigateTo):slide-in-right / slide-in-left / slide-in-top / slide-in-bottom / pop-in / fade-in / zoom-out / zoom-fade-out / none / auto
13
+ * 关闭动画(navigateBack):slide-out-right / slide-out-left / slide-out-top / slide-out-bottom / pop-out / fade-out / zoom-in / zoom-fade-in / none / auto
14
+ *
15
+ * @see https://en.uniapp.dcloud.io/api/router.html#animation
16
+ */
17
+ type UniAnimationType = 'auto' | 'none' | 'slide-in-right' | 'slide-in-left' | 'slide-in-top' | 'slide-in-bottom' | 'slide-out-right' | 'slide-out-left' | 'slide-out-top' | 'slide-out-bottom' | 'fade-in' | 'fade-out' | 'zoom-out' | 'zoom-in' | 'zoom-fade-out' | 'zoom-fade-in' | 'pop-in' | 'pop-out';
18
+ /**
19
+ * 导航动画配置
20
+ *
21
+ * 仅 App 端生效,其他平台自动忽略。
22
+ * 优先级:push/replace 调用时传入 > meta.animation > uni 默认值
23
+ */
24
+ interface NavigationAnimation {
25
+ /** 窗口动画类型 */
26
+ type: UniAnimationType;
27
+ /** 动画持续时间(ms),默认 300 */
28
+ duration?: number;
29
+ }
6
30
  /**
7
31
  * 路由元信息
8
32
  *
@@ -17,6 +41,8 @@ interface RouteMeta {
17
41
  isTab?: boolean;
18
42
  /** 是否需要登录才能访问 */
19
43
  requireAuth?: boolean;
44
+ /** 默认导航动画(仅 App 端生效),可被 push/replace 时的 animation 参数覆盖 */
45
+ animation?: NavigationAnimation;
20
46
  /** 自定义扩展字段 */
21
47
  [key: string]: unknown;
22
48
  }
@@ -33,6 +59,8 @@ interface RouteConfig {
33
59
  name?: string;
34
60
  /** 路由元信息 */
35
61
  meta?: RouteMeta;
62
+ /** 用户自定义扩展属性(如 beforeEnter、component 等) */
63
+ [key: string]: unknown;
36
64
  }
37
65
  /**
38
66
  * uni-app pages.json 中的页面配置项
@@ -292,4 +320,4 @@ interface GenerateRouterOptions extends BasePluginOptions {
292
320
  declare const generateRouter: PluginFactory<GenerateRouterOptions, GenerateRouterOptions>;
293
321
 
294
322
  export { generateRouter };
295
- export type { GenerateRouterOptions, NameStrategy, OutputFormat, RouteConfig, RouteMeta, UniAppPageConfig, UniAppPagesJson, UniAppTabBarConfig };
323
+ export type { GenerateRouterOptions, NameStrategy, NavigationAnimation, OutputFormat, RouteConfig, RouteMeta, UniAnimationType, UniAppPageConfig, UniAppPagesJson, UniAppTabBarConfig };
@@ -1,5 +1,55 @@
1
- import{createPluginFactory as l,BasePlugin as F}from"../../factory/index.mjs";import{writeFileContent as p,shouldUpdateFileContent as m}from"../../common/fs/index.mjs";import{resolve as n}from"path";import{existsSync as i,promises as c,watch as f}from"fs";import"../../logger/index.mjs";import"../../shared/vite-plugin.DcExl6jd.mjs";function g(r,t=/[/-]/){return r.replace(/^\/+/,"").split(t).filter(Boolean).map((e,u)=>u===0?e.toLowerCase():e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()).join("")}function E(r,t=/[/-]/){return r.replace(/^\/+/,"").split(t).filter(Boolean).map(e=>e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()).join("")}function D(r){return r.replace(/\/\/.*$/gm,"").replace(/\/\*[\s\S]*?\*\//g,"")}function C(r,t){return typeof t=="string"?"string":typeof t=="boolean"?t?"true":"false":typeof t=="number"?"number":"unknown"}function d(r){const t=Object.entries(r);return t.length===0?"{}":`{ ${t.map(([e,u])=>`${e}: ${C(e,u)}`).join("; ")} }`}function y(r,t="@meng-xi/uni-router"){const e=[];e.push(`import '${t}'`),e.push(""),e.push(`declare module '${t}' {`),e.push(" interface RouteNameMap {");for(const u of r){const s=u.name||u.path;u.meta?.title&&e.push(` /** ${u.meta.title} */`);const a=u.meta?d(u.meta):"{}";e.push(` ${s}: { path: '${u.path}'; meta: ${a} }`)}return e.push(" }"),e.push("}"),e.join(`
2
- `)}class w extends F{projectRoot=process.cwd();tabBarPages=new Set;watcher=null;getDefaultOptions(){return{pagesJsonPath:"src/pages.json",outputPath:"src/router.config.ts",outputFormat:"ts",nameStrategy:"camelCase",includeSubPackages:!0,watch:!0,exportTypes:!0,preserveRouteChanges:!0,metaMapping:{navigationBarTitleText:"title",requireAuth:"requireAuth"},dts:!1}}validateOptions(){if(this.validator.field("pagesJsonPath").string().field("outputPath").string().field("outputFormat").enum(["ts","js"]).field("nameStrategy").enum(["path","camelCase","pascalCase","custom"]).validate(),this.options.nameStrategy==="custom"&&!this.options.customNameGenerator)throw new Error("\u5F53 nameStrategy \u4E3A custom \u65F6\uFF0C\u5FC5\u987B\u63D0\u4F9B customNameGenerator")}getPluginName(){return"generate-router"}generateRouteName(t){switch(this.options.nameStrategy){case"path":return t.replace(/\//g,"_").replace(/^_/,"");case"camelCase":return g(t);case"pascalCase":return E(t);case"custom":return this.options.customNameGenerator(t);default:return g(t)}}extractMeta(t,e){const u={},s=t.style||{},a=this.options.metaMapping||{};for(const[o,h]of Object.entries(a))s[o]!==void 0&&(u[h]=s[o]);return this.tabBarPages.has(e)&&(u.isTab=!0),u}parsePageToRoute(t,e=""){const u=e?`/${e}/${t.path}`:`/${t.path}`,s=this.generateRouteName(u),a=this.extractMeta(t,u.replace(/^\//,"")),o={path:u,name:s};return Object.keys(a).length>0&&(o.meta=a),o}parsePagesJson(t){const e=[];if(!t.pages||!Array.isArray(t.pages)||t.pages.length===0)return this.logger.warn("pages.json \u4E2D\u6CA1\u6709\u6709\u6548\u7684\u9875\u9762\u914D\u7F6E"),e;if(this.tabBarPages.clear(),t.tabBar?.list)for(const u of t.tabBar.list)this.tabBarPages.add(u.pagePath);for(const u of t.pages)e.push(this.parsePageToRoute(u));if(this.options.includeSubPackages&&t.subPackages){for(const u of t.subPackages)if(u.pages&&Array.isArray(u.pages))for(const s of u.pages)e.push(this.parsePageToRoute(s,u.root))}return e}generateTypeDefinitions(){return!this.options.exportTypes||this.options.outputFormat==="js"?"":`
1
+ import{createPluginFactory as b,BasePlugin as A}from"../../factory/index.mjs";import{writeFileContent as d,shouldUpdateFileContent as y}from"../../common/fs/index.mjs";import{resolve as h}from"path";import{existsSync as f,promises as E,watch as B}from"fs";import"../../logger/index.mjs";import"../../shared/vite-plugin.DcExl6jd.mjs";import"../../common/concurrency/index.mjs";function D(t,e=/[/-]/){return t.replace(/^\/+/,"").split(e).filter(Boolean).map((u,o)=>o===0?u.toLowerCase():u.charAt(0).toUpperCase()+u.slice(1).toLowerCase()).join("")}function $(t,e=/[/-]/){return t.replace(/^\/+/,"").split(e).filter(Boolean).map(u=>u.charAt(0).toUpperCase()+u.slice(1).toLowerCase()).join("")}function x(t){return t.replace(/\/\/.*$/gm,"").replace(/\/\*[\s\S]*?\*\//g,"")}function w(t,e){return typeof e=="string"?"string":typeof e=="boolean"?e?"true":"false":typeof e=="number"?"number":"unknown"}function j(t){const e=Object.entries(t);return e.length===0?"{}":`{ ${e.map(([u,o])=>`${u}: ${w(u,o)}`).join("; ")} }`}function R(t,e="@meng-xi/uni-router"){const u=[];u.push(`import '${e}'`),u.push(""),u.push(`declare module '${e}' {`),u.push(" interface RouteNameMap {");for(const o of t){const n=o.name||o.path;o.meta?.title&&u.push(` /** ${o.meta.title} */`);const r=o.meta?j(o.meta):"{}";u.push(` ${n}: { path: '${o.path}'; meta: ${r} }`)}return u.push(" }"),u.push("}"),u.join(`
2
+ `)}function P(t){return JSON.stringify(t,null," ").replace(/"(\w+)":/g,"$1:").replace(/: "([^"]+)"/g,": '$1'")}function F(t){return t===null?"null":t===void 0?"undefined":typeof t=="string"?`'${t.replace(/\\/g,"\\\\").replace(/'/g,"\\'")}'`:typeof t=="number"||typeof t=="boolean"?String(t):Array.isArray(t)?"["+t.map(e=>F(e)).join(", ")+"]":typeof t=="object"?`{ ${Object.entries(t).map(([e,u])=>`${e}: ${F(u)}`).join(", ")} }`:String(t)}function O(t){const e=[];let u=0,o=-1,n=!1,r="";for(let s=0;s<t.length;s++){const c=t[s];if(n){c===r&&t[s-1]!=="\\"&&(n=!1);continue}if(c==="/"&&s+1<t.length&&t[s+1]==="/"){const p=t.indexOf(`
3
+ `,s);s=p===-1?t.length-1:p-1;continue}if(c==="/"&&s+1<t.length&&t[s+1]==="*"){const p=t.indexOf("*/",s+2);s=p===-1?t.length-1:p+1;continue}if(c==='"'||c==="'"||c==="`"){n=!0,r=c;continue}c==="{"?(u===0&&(o=s),u++):c==="}"&&(u--,u===0&&o>=0&&(e.push(t.substring(o,s+1)),o=-1))}return e}function m(t,e,u){const o=new RegExp(`(\\b${e}\\s*:\\s*)`),n=t.match(o);if(!n||n.index===void 0){const i=t.lastIndexOf("}"),a=t.substring(0,i),g=a.lastIndexOf(`
4
+ `),C=`
5
+ ${g>=0?a.substring(g+1).match(/^(\s*)/)?.[1]??" ":" "}${e}: ${u},`;return t.substring(0,i)+C+`
6
+ `+t.substring(i)}const r=n.index+n[0].length;let s=0,c=!1,p="",l=r;for(let i=r;i<t.length;i++){const a=t[i];if(c){a===p&&t[i-1]!=="\\"&&(c=!1);continue}if(a==="/"&&i+1<t.length&&t[i+1]==="/"){const g=t.indexOf(`
7
+ `,i);i=g===-1?t.length-1:g-1;continue}if(a==="/"&&i+1<t.length&&t[i+1]==="*"){const g=t.indexOf("*/",i+2);i=g===-1?t.length-1:g+1;continue}if(a==='"'||a==="'"||a==="`"){c=!0,p=a;continue}if(a==="{"||a==="["||a==="(")s++;else if(a==="}"||a==="]"||a===")")if(s>0)s--;else{l=i;break}else if(s===0&&a===","){l=i;break}}return t.substring(0,n.index)+`${e}: ${u}`+t.substring(l)}function v(t,e){const u=new RegExp(`,?\\s*\\b${e}\\s*:\\s*`),o=t.match(u);if(!o||o.index===void 0)return t;const n=o.index,r=n+o[0].length;let s=0,c=!1,p="",l=r;for(let i=r;i<t.length;i++){const a=t[i];if(c){a===p&&t[i-1]!=="\\"&&(c=!1);continue}if(a==="/"&&i+1<t.length&&t[i+1]==="/"){const g=t.indexOf(`
8
+ `,i);i=g===-1?t.length-1:g-1;continue}if(a==="/"&&i+1<t.length&&t[i+1]==="*"){const g=t.indexOf("*/",i+2);i=g===-1?t.length-1:g+1;continue}if(a==='"'||a==="'"||a==="`"){c=!0,p=a;continue}if(a==="{"||a==="["||a==="("){s++;continue}if(a==="}"||a==="]"||a===")"){if(s>0){s--;continue}l=i;break}if(s===0&&a===","){l=i;break}}if(o[0].startsWith(","))return t.substring(0,n)+t.substring(l);{let i=l;return t[i]===","&&i++,t.substring(0,n)+t.substring(i)}}function k(t){const e=new Map,u=t.match(/export const routes[^=]*=\s*(\[[\s\S]*?\](?=\s*\n|\s*$|\s*\/\/))/);if(!u)return e;const o=O(u[1]);for(const n of o){const r=n.match(/path:\s*['"]([^'"]*)['"]/);r&&e.set(r[1],n.trim())}return e}function S(t){const e=new Map,u=t.match(/export const routes[^=]*=\s*(\[[\s\S]*?\](?=\s*\n|\s*$|\s*\/\/))/);if(!u)return e;try{let o=u[1].replace(/(\w+)(?=\s*:)/g,'"$1"').replace(/'([^']*)'/g,'"$1"').replace(/,\s*([\]\}])/g,"$1");const n=JSON.parse(o);for(const r of n)r.path&&e.set(r.path,r)}catch{}return e}class T extends A{projectRoot=process.cwd();tabBarPages=new Set;watcher=null;getDefaultOptions(){return{pagesJsonPath:"src/pages.json",outputPath:"src/router.config.ts",outputFormat:"ts",nameStrategy:"camelCase",includeSubPackages:!0,watch:!0,exportTypes:!0,preserveRouteChanges:!0,metaMapping:{navigationBarTitleText:"title",requireAuth:"requireAuth"},dts:!1}}validateOptions(){if(this.validator.field("pagesJsonPath").string().field("outputPath").string().field("outputFormat").enum(["ts","js"]).field("nameStrategy").enum(["path","camelCase","pascalCase","custom"]).validate(),this.options.nameStrategy==="custom"&&!this.options.customNameGenerator)throw new Error("\u5F53 nameStrategy \u4E3A custom \u65F6\uFF0C\u5FC5\u987B\u63D0\u4F9B customNameGenerator")}getPluginName(){return"generate-router"}generateRouteName(e){switch(this.options.nameStrategy){case"path":return e.replace(/\//g,"_").replace(/^_/,"");case"camelCase":return D(e);case"pascalCase":return $(e);case"custom":return this.options.customNameGenerator(e);default:return D(e)}}extractMeta(e,u){const o={},n=e.style||{},r=this.options.metaMapping||{};for(const[s,c]of Object.entries(r))n[s]!==void 0&&(o[c]=n[s]);return this.tabBarPages.has(u)&&(o.isTab=!0),o}parsePageToRoute(e,u=""){const o=u?`/${u}/${e.path}`:`/${e.path}`,n=this.generateRouteName(o),r=this.extractMeta(e,o.replace(/^\//,"")),s={path:o,name:n};return Object.keys(r).length>0&&(s.meta=r),s}parsePagesJson(e){const u=[];if(!e.pages||!Array.isArray(e.pages)||e.pages.length===0)return this.logger.warn("pages.json \u4E2D\u6CA1\u6709\u6709\u6548\u7684\u9875\u9762\u914D\u7F6E"),u;if(this.tabBarPages.clear(),e.tabBar?.list)for(const o of e.tabBar.list)this.tabBarPages.add(o.pagePath);for(const o of e.pages)u.push(this.parsePageToRoute(o));if(this.options.includeSubPackages&&e.subPackages){for(const o of e.subPackages)if(o.pages&&Array.isArray(o.pages))for(const n of o.pages)u.push(this.parsePageToRoute(n,o.root))}return u}generateTypeDefinitions(){return!this.options.exportTypes||this.options.outputFormat==="js"?"":`
9
+ /**
10
+ * \u5BFC\u822A\u52A8\u753B\u7C7B\u578B
11
+ *
12
+ * \u7528\u4E8E uni.navigateTo / uni.navigateBack \u7684 animationType \u53C2\u6570\uFF0C
13
+ * \u4EC5 App \u7AEF\u751F\u6548\uFF0C\u5176\u4ED6\u5E73\u53F0\u81EA\u52A8\u5FFD\u7565\u3002
14
+ *
15
+ * \u663E\u793A\u52A8\u753B\uFF08navigateTo\uFF09\uFF1Aslide-in-right / slide-in-left / slide-in-top / slide-in-bottom / pop-in / fade-in / zoom-out / zoom-fade-out / none / auto
16
+ * \u5173\u95ED\u52A8\u753B\uFF08navigateBack\uFF09\uFF1Aslide-out-right / slide-out-left / slide-out-top / slide-out-bottom / pop-out / fade-out / zoom-in / zoom-fade-in / none / auto
17
+ *
18
+ * @see https://en.uniapp.dcloud.io/api/router.html#animation
19
+ */
20
+ export type UniAnimationType =
21
+ | 'auto'
22
+ | 'none'
23
+ | 'slide-in-right'
24
+ | 'slide-in-left'
25
+ | 'slide-in-top'
26
+ | 'slide-in-bottom'
27
+ | 'slide-out-right'
28
+ | 'slide-out-left'
29
+ | 'slide-out-top'
30
+ | 'slide-out-bottom'
31
+ | 'fade-in'
32
+ | 'fade-out'
33
+ | 'zoom-out'
34
+ | 'zoom-in'
35
+ | 'zoom-fade-out'
36
+ | 'zoom-fade-in'
37
+ | 'pop-in'
38
+ | 'pop-out'
39
+
40
+ /**
41
+ * \u5BFC\u822A\u52A8\u753B\u914D\u7F6E
42
+ *
43
+ * \u4EC5 App \u7AEF\u751F\u6548\uFF0C\u5176\u4ED6\u5E73\u53F0\u81EA\u52A8\u5FFD\u7565\u3002
44
+ * \u4F18\u5148\u7EA7\uFF1Apush/replace \u8C03\u7528\u65F6\u4F20\u5165 > meta.animation > uni \u9ED8\u8BA4\u503C
45
+ */
46
+ export interface NavigationAnimation {
47
+ /** \u7A97\u53E3\u52A8\u753B\u7C7B\u578B */
48
+ type: UniAnimationType
49
+ /** \u52A8\u753B\u6301\u7EED\u65F6\u95F4\uFF08ms\uFF09\uFF0C\u9ED8\u8BA4 300 */
50
+ duration?: number
51
+ }
52
+
3
53
  /**
4
54
  * \u8DEF\u7531\u5143\u4FE1\u606F
5
55
  */
@@ -10,6 +60,8 @@ export interface RouteMeta {
10
60
  isTab?: boolean
11
61
  /** \u662F\u5426\u9700\u8981\u767B\u5F55 */
12
62
  requireAuth?: boolean
63
+ /** \u9ED8\u8BA4\u5BFC\u822A\u52A8\u753B\uFF08\u4EC5 App \u7AEF\u751F\u6548\uFF09\uFF0C\u53EF\u88AB push/replace \u65F6\u7684 animation \u53C2\u6570\u8986\u76D6 */
64
+ animation?: NavigationAnimation
13
65
  /** \u81EA\u5B9A\u4E49\u6269\u5C55\u5B57\u6BB5 */
14
66
  [key: string]: unknown
15
67
  }
@@ -25,12 +77,17 @@ export interface RouteConfig {
25
77
  /** \u8DEF\u7531\u5143\u4FE1\u606F */
26
78
  meta?: RouteMeta
27
79
  }
28
- `}generateFileContent(t){const e=this.generateTypeDefinitions(),u=this.options.outputFormat==="ts",s=JSON.stringify(t,null," ").replace(/"(\w+)":/g,"$1:").replace(/: "([^"]+)"/g,": '$1'");return`${e}
80
+ `}generateFileContent(e,u){const o=this.generateTypeDefinitions(),n=this.options.outputFormat==="ts"?": RouteConfig[]":"",r=e.map(s=>{const c=u?.get(s.path);if(c){let p=c;if(p=m(p,"path",`'${s.path}'`),s.name!==void 0&&(p=m(p,"name",`'${s.name}'`)),s.meta&&Object.keys(s.meta).length>0){const l=F(s.meta);p=m(p,"meta",l)}else s.meta&&Object.keys(s.meta).length===0&&(p=v(p,"meta"));return p}return P(s)}).map(s=>" "+s.split(`
81
+ `).join(`
82
+ `)).join(`,
83
+ `);return`${o}
29
84
  /**
30
85
  * \u8DEF\u7531\u914D\u7F6E\u5217\u8868
31
86
  * @description \u7531 pages.json \u81EA\u52A8\u751F\u6210
32
87
  */
33
- export const routes${u?": RouteConfig[]":""} = ${s}
88
+ export const routes${n} = [
89
+ ${r}
90
+ ]
34
91
 
35
92
  export default routes
36
- `}async readPagesJson(){const t=n(this.projectRoot,this.options.pagesJsonPath);if(!i(t))return this.logger.warn(`pages.json \u6587\u4EF6\u4E0D\u5B58\u5728: ${t}`),null;try{const e=await c.readFile(t,"utf-8"),u=D(e);return JSON.parse(u)}catch(e){return this.logger.error(`\u89E3\u6790 pages.json \u5931\u8D25: ${e.message}`),null}}extractExistingRoutes(t){const e=new Map,u=t.match(/export const routes[^=]*=\s*(\[[\s\S]*?\](?=\s*\n|\s*$|\s*\/\/))/);if(!u)return e;try{let s=u[1].replace(/(\w+)(?=\s*:)/g,'"$1"').replace(/'([^']*)'/g,'"$1"').replace(/,\s*([\]\}])/g,"$1");const a=JSON.parse(s);for(const o of a)o.path&&e.set(o.path,o)}catch{this.logger.warn("\u89E3\u6790\u73B0\u6709 routes \u914D\u7F6E\u5931\u8D25\uFF0C\u5C06\u5B8C\u5168\u91CD\u65B0\u751F\u6210")}return e}mergeRoutes(t,e){return t.map(u=>{const s=e.get(u.path);if(!s)return u;const a={};return u.meta&&Object.assign(a,u.meta),s.meta&&Object.assign(a,s.meta),{...s,path:u.path,meta:Object.keys(a).length>0?a:void 0}})}async generateRouterConfig(){const t=await this.readPagesJson();if(!t)return;let e=this.parsePagesJson(t);const u=n(this.projectRoot,this.options.outputPath);if(this.options.preserveRouteChanges&&i(u))try{const a=await c.readFile(u,"utf-8"),o=this.extractExistingRoutes(a);o.size>0&&(e=this.mergeRoutes(e,o),this.logger.info("\u5DF2\u5408\u5E76\u7528\u6237\u5BF9\u8DEF\u7531\u914D\u7F6E\u7684\u4FEE\u6539"))}catch{}const s=this.generateFileContent(e);await p(u,s),this.logger.success(`\u8DEF\u7531\u914D\u7F6E\u6587\u4EF6\u5DF2\u751F\u6210: ${u}`),this.logger.info(`\u5171\u751F\u6210 ${e.length} \u6761\u8DEF\u7531\u914D\u7F6E`),await this.generateDtsFile(e)}async generateDtsFile(t){if(!this.options.dts)return;const e=n(this.projectRoot,typeof this.options.dts=="string"?this.options.dts:"src/router.d.ts"),u=y(t);m(e,u)&&(await p(e,u),this.logger.success(`\u8DEF\u7531\u7C7B\u578B\u58F0\u660E\u6587\u4EF6\u5DF2\u751F\u6210: ${e}`))}startWatching(){if(!this.options.watch)return;const t=n(this.projectRoot,this.options.pagesJsonPath);i(t)&&(this.watcher=f(t,async e=>{e==="change"&&(this.logger.info("\u68C0\u6D4B\u5230 pages.json \u53D8\u5316\uFF0C\u91CD\u65B0\u751F\u6210\u8DEF\u7531\u914D\u7F6E..."),await this.safeExecute(()=>this.generateRouterConfig(),"\u91CD\u65B0\u751F\u6210\u8DEF\u7531\u914D\u7F6E"))}),this.logger.info(`\u6B63\u5728\u76D1\u542C pages.json \u53D8\u5316: ${t}`))}stopWatching(){this.watcher&&(this.watcher.close(),this.watcher=null)}addPluginHooks(t){t.configResolved=async e=>{this.projectRoot=e.root,await this.safeExecute(()=>this.generateRouterConfig(),"\u751F\u6210\u8DEF\u7531\u914D\u7F6E"),e.command==="serve"&&this.startWatching()}}destroy(){super.destroy(),this.stopWatching()}}const B=l(w);export{B as generateRouter};
93
+ `}async readPagesJson(){const e=h(this.projectRoot,this.options.pagesJsonPath);if(!f(e))return this.logger.warn(`pages.json \u6587\u4EF6\u4E0D\u5B58\u5728: ${e}`),null;try{const u=await E.readFile(e,"utf-8"),o=x(u);return JSON.parse(o)}catch(u){return this.logger.error(`\u89E3\u6790 pages.json \u5931\u8D25: ${u.message}`),null}}mergeRoutes(e,u){return e.map(o=>{const n=u.get(o.path);if(!n)return o;const r={};return o.meta&&Object.assign(r,o.meta),n.meta&&Object.assign(r,n.meta),{...n,path:o.path,meta:Object.keys(r).length>0?r:void 0}})}async generateRouterConfig(){const e=await this.readPagesJson();if(!e)return;let u=this.parsePagesJson(e),o;const n=h(this.projectRoot,this.options.outputPath);if(this.options.preserveRouteChanges&&f(n))try{const s=await E.readFile(n,"utf-8"),c=S(s);o=k(s),c.size>0&&(u=this.mergeRoutes(u,c),this.logger.info("\u5DF2\u5408\u5E76\u7528\u6237\u5BF9\u8DEF\u7531\u914D\u7F6E\u7684\u4FEE\u6539"))}catch{}const r=this.generateFileContent(u,o);await d(n,r),this.logger.success(`\u8DEF\u7531\u914D\u7F6E\u6587\u4EF6\u5DF2\u751F\u6210: ${n}`),this.logger.info(`\u5171\u751F\u6210 ${u.length} \u6761\u8DEF\u7531\u914D\u7F6E`),await this.generateDtsFile(u)}async generateDtsFile(e){if(!this.options.dts)return;const u=h(this.projectRoot,typeof this.options.dts=="string"?this.options.dts:"src/router.d.ts"),o=R(e);y(u,o)&&(await d(u,o),this.logger.success(`\u8DEF\u7531\u7C7B\u578B\u58F0\u660E\u6587\u4EF6\u5DF2\u751F\u6210: ${u}`))}startWatching(){if(!this.options.watch)return;const e=h(this.projectRoot,this.options.pagesJsonPath);f(e)&&(this.watcher=B(e,async u=>{u==="change"&&(this.logger.info("\u68C0\u6D4B\u5230 pages.json \u53D8\u5316\uFF0C\u91CD\u65B0\u751F\u6210\u8DEF\u7531\u914D\u7F6E..."),await this.safeExecute(()=>this.generateRouterConfig(),"\u91CD\u65B0\u751F\u6210\u8DEF\u7531\u914D\u7F6E"))}),this.logger.info(`\u6B63\u5728\u76D1\u542C pages.json \u53D8\u5316: ${e}`))}stopWatching(){this.watcher&&(this.watcher.close(),this.watcher=null)}addPluginHooks(e){e.configResolved=async u=>{this.projectRoot=u.root,await this.safeExecute(()=>this.generateRouterConfig(),"\u751F\u6210\u8DEF\u7531\u914D\u7F6E"),u.command==="serve"&&this.startWatching()}}destroy(){super.destroy(),this.stopWatching()}}const J=b(T);export{J as generateRouter};
@@ -1 +1 @@
1
- "use strict";const factory_index=require("../../factory/index.cjs"),crypto=require("crypto"),common_format_index=require("../../common/format/index.cjs"),common_fs_index=require("../../common/fs/index.cjs"),u=require("path");require("../../logger/index.cjs"),require("../../shared/vite-plugin.Bcg6RW2N.cjs"),require("fs");function generateRandomHash(o=8){const e=Math.max(1,Math.min(64,o));return crypto.randomBytes(Math.ceil(e/2)).toString("hex").slice(0,e)}function parseTemplate(o,e){let t=o;for(const[i,s]of Object.entries(e))t=t.replace(new RegExp(`\\{${i}\\}`,"g"),s);return t}class f extends factory_index.BasePlugin{version="";buildTime=new Date;getDefaultOptions(){return{format:"timestamp",semverBase:"1.0.0",outputType:"file",outputFile:"version.json",defineName:"__APP_VERSION__",hashLength:8,prefix:"",suffix:""}}validateOptions(){if(this.validator.field("format").enum(["timestamp","date","datetime","semver","hash","custom"]).field("outputType").enum(["file","define","both"]).field("hashLength").number().minValue(1).maxValue(32).validate(),this.options.format==="custom"&&!this.options.customFormat)throw new Error("\u5F53 format \u4E3A custom \u65F6\uFF0C\u5FC5\u987B\u63D0\u4F9B customFormat")}getPluginName(){return"generate-version"}generateVersion(){const e=common_format_index.getDateFormatParams(this.buildTime),t=generateRandomHash(this.options.hashLength);let i;switch(this.options.format){case"timestamp":i=`${e.YYYY}${e.MM}${e.DD}${e.HH}${e.mm}${e.ss}`;break;case"date":i=`${e.YYYY}.${e.MM}.${e.DD}`;break;case"datetime":i=`${e.YYYY}.${e.MM}.${e.DD}.${e.HH}${e.mm}${e.ss}`;break;case"semver":i=this.options.semverBase||"1.0.0";break;case"hash":i=t;break;case"custom":i=this.parseCustomFormat({...e,hash:t});break;default:i=e.timestamp}const s=this.options.prefix||"",n=this.options.suffix||"";return`${s}${i}${n}`}parseCustomFormat(e){const t={...e};if(this.options.semverBase){const[i,s,n]=this.options.semverBase.split(".");t.major=i||"1",t.minor=s||"0",t.patch=n||"0"}return parseTemplate(this.options.customFormat||"",t)}generateVersionInfo(){return{version:this.version,buildTime:this.buildTime.toISOString(),timestamp:this.buildTime.getTime(),format:this.options.format,...this.options.extra}}async writeVersionFile(e){const t=u.join(e,this.options.outputFile||"version.json"),i=this.generateVersionInfo();await common_fs_index.writeFileContent(t,JSON.stringify(i,null,2)),this.logger.success(`\u7248\u672C\u6587\u4EF6\u5DF2\u751F\u6210: ${t}`)}addPluginHooks(e){e.configResolved=()=>{this.buildTime=new Date,this.version=this.generateVersion(),this.logger.info(`\u751F\u6210\u7248\u672C\u53F7: ${this.version}`)},(this.options.outputType==="define"||this.options.outputType==="both")&&(e.config=()=>{this.version||(this.buildTime=new Date,this.version=this.generateVersion());const t=this.options.defineName||"__APP_VERSION__";return this.logger.info(`\u6CE8\u5165\u5168\u5C40\u53D8\u91CF: ${t} = "${this.version}"`),{define:{[t]:JSON.stringify(this.version),[`${t}_INFO`]:JSON.stringify(this.generateVersionInfo())}}}),(this.options.outputType==="file"||this.options.outputType==="both")&&(e.writeBundle=async()=>{this.viteConfig&&await this.safeExecute(async()=>{const t=this.viteConfig.build.outDir;await this.writeVersionFile(t)},"\u5199\u5165\u7248\u672C\u6587\u4EF6")})}}const generateVersion=factory_index.createPluginFactory(f);exports.generateVersion=generateVersion;
1
+ "use strict";const factory_index=require("../../factory/index.cjs"),crypto=require("crypto"),common_format_index=require("../../common/format/index.cjs"),common_fs_index=require("../../common/fs/index.cjs"),o=require("path");require("../../logger/index.cjs"),require("../../shared/vite-plugin.Bcg6RW2N.cjs"),require("fs"),require("../../common/concurrency/index.cjs");function generateRandomHash(i=8){const s=Math.max(1,Math.min(64,i));return crypto.randomBytes(Math.ceil(s/2)).toString("hex").slice(0,s)}function parseTemplate(i,s){let e=i;for(const[n,a]of Object.entries(s))e=e.replace(new RegExp(`\\{${n}\\}`,"g"),a);return e}function generateVersionString(i){const{format:s,buildTime:e,hashLength:n,semverBase:a,customFormat:u,prefix:m,suffix:c}=i,t=common_format_index.getDateFormatParams(e),h=generateRandomHash(n);let r;switch(s){case"timestamp":r=`${t.YYYY}${t.MM}${t.DD}${t.HH}${t.mm}${t.ss}`;break;case"date":r=`${t.YYYY}.${t.MM}.${t.DD}`;break;case"datetime":r=`${t.YYYY}.${t.MM}.${t.DD}.${t.HH}${t.mm}${t.ss}`;break;case"semver":r=a||"1.0.0";break;case"hash":r=h;break;case"custom":r=parseCustomFormat(u||"",{...t,hash:h},a);break;default:r=t.timestamp}return`${m||""}${r}${c||""}`}function parseCustomFormat(i,s,e){const n={...s};if(e){const[a,u,m]=e.split(".");n.major=a||"1",n.minor=u||"0",n.patch=m||"0"}return parseTemplate(i,n)}function generateVersionInfoObject(i){return{version:i.version,buildTime:i.buildTime.toISOString(),timestamp:i.buildTime.getTime(),format:i.format,...i.extra}}class p extends factory_index.BasePlugin{version="";buildTime=new Date;getDefaultOptions(){return{format:"timestamp",semverBase:"1.0.0",outputType:"file",outputFile:"version.json",defineName:"__APP_VERSION__",hashLength:8,prefix:"",suffix:""}}validateOptions(){if(this.validator.field("format").enum(["timestamp","date","datetime","semver","hash","custom"]).field("outputType").enum(["file","define","both"]).field("hashLength").number().minValue(1).maxValue(32).validate(),this.options.format==="custom"&&!this.options.customFormat)throw new Error("\u5F53 format \u4E3A custom \u65F6\uFF0C\u5FC5\u987B\u63D0\u4F9B customFormat")}getPluginName(){return"generate-version"}generateVersion(){return generateVersionString({format:this.options.format,buildTime:this.buildTime,hashLength:this.options.hashLength||8,semverBase:this.options.semverBase,customFormat:this.options.customFormat,prefix:this.options.prefix,suffix:this.options.suffix})}generateVersionInfo(){return generateVersionInfoObject({version:this.version,buildTime:this.buildTime,format:this.options.format,extra:this.options.extra})}async writeVersionFile(s){const e=o.join(s,this.options.outputFile||"version.json"),n=this.generateVersionInfo();await common_fs_index.writeFileContent(e,JSON.stringify(n,null,2)),this.logger.success(`\u7248\u672C\u6587\u4EF6\u5DF2\u751F\u6210: ${e}`)}addPluginHooks(s){s.configResolved=()=>{this.buildTime=new Date,this.version=this.generateVersion(),this.logger.info(`\u751F\u6210\u7248\u672C\u53F7: ${this.version}`)},(this.options.outputType==="define"||this.options.outputType==="both")&&(s.config=()=>{this.version||(this.buildTime=new Date,this.version=this.generateVersion());const e=this.options.defineName||"__APP_VERSION__";return this.logger.info(`\u6CE8\u5165\u5168\u5C40\u53D8\u91CF: ${e} = "${this.version}"`),{define:{[e]:JSON.stringify(this.version),[`${e}_INFO`]:JSON.stringify(this.generateVersionInfo())}}}),(this.options.outputType==="file"||this.options.outputType==="both")&&(s.writeBundle=async()=>{this.viteConfig&&await this.safeExecute(async()=>{const e=this.viteConfig.build.outDir;await this.writeVersionFile(e)},"\u5199\u5165\u7248\u672C\u6587\u4EF6")})}}const generateVersion=factory_index.createPluginFactory(p);exports.generateVersion=generateVersion;
@@ -1 +1 @@
1
- import{createPluginFactory as r,BasePlugin as a}from"../../factory/index.mjs";import{randomBytes as u}from"crypto";import{getDateFormatParams as m}from"../../common/format/index.mjs";import{writeFileContent as h}from"../../common/fs/index.mjs";import{join as p}from"path";import"../../logger/index.mjs";import"../../shared/vite-plugin.DcExl6jd.mjs";import"fs";function f(o=8){const t=Math.max(1,Math.min(64,o));return u(Math.ceil(t/2)).toString("hex").slice(0,t)}function l(o,t){let e=o;for(const[i,s]of Object.entries(t))e=e.replace(new RegExp(`\\{${i}\\}`,"g"),s);return e}class c extends a{version="";buildTime=new Date;getDefaultOptions(){return{format:"timestamp",semverBase:"1.0.0",outputType:"file",outputFile:"version.json",defineName:"__APP_VERSION__",hashLength:8,prefix:"",suffix:""}}validateOptions(){if(this.validator.field("format").enum(["timestamp","date","datetime","semver","hash","custom"]).field("outputType").enum(["file","define","both"]).field("hashLength").number().minValue(1).maxValue(32).validate(),this.options.format==="custom"&&!this.options.customFormat)throw new Error("\u5F53 format \u4E3A custom \u65F6\uFF0C\u5FC5\u987B\u63D0\u4F9B customFormat")}getPluginName(){return"generate-version"}generateVersion(){const t=m(this.buildTime),e=f(this.options.hashLength);let i;switch(this.options.format){case"timestamp":i=`${t.YYYY}${t.MM}${t.DD}${t.HH}${t.mm}${t.ss}`;break;case"date":i=`${t.YYYY}.${t.MM}.${t.DD}`;break;case"datetime":i=`${t.YYYY}.${t.MM}.${t.DD}.${t.HH}${t.mm}${t.ss}`;break;case"semver":i=this.options.semverBase||"1.0.0";break;case"hash":i=e;break;case"custom":i=this.parseCustomFormat({...t,hash:e});break;default:i=t.timestamp}const s=this.options.prefix||"",n=this.options.suffix||"";return`${s}${i}${n}`}parseCustomFormat(t){const e={...t};if(this.options.semverBase){const[i,s,n]=this.options.semverBase.split(".");e.major=i||"1",e.minor=s||"0",e.patch=n||"0"}return l(this.options.customFormat||"",e)}generateVersionInfo(){return{version:this.version,buildTime:this.buildTime.toISOString(),timestamp:this.buildTime.getTime(),format:this.options.format,...this.options.extra}}async writeVersionFile(t){const e=p(t,this.options.outputFile||"version.json"),i=this.generateVersionInfo();await h(e,JSON.stringify(i,null,2)),this.logger.success(`\u7248\u672C\u6587\u4EF6\u5DF2\u751F\u6210: ${e}`)}addPluginHooks(t){t.configResolved=()=>{this.buildTime=new Date,this.version=this.generateVersion(),this.logger.info(`\u751F\u6210\u7248\u672C\u53F7: ${this.version}`)},(this.options.outputType==="define"||this.options.outputType==="both")&&(t.config=()=>{this.version||(this.buildTime=new Date,this.version=this.generateVersion());const e=this.options.defineName||"__APP_VERSION__";return this.logger.info(`\u6CE8\u5165\u5168\u5C40\u53D8\u91CF: ${e} = "${this.version}"`),{define:{[e]:JSON.stringify(this.version),[`${e}_INFO`]:JSON.stringify(this.generateVersionInfo())}}}),(this.options.outputType==="file"||this.options.outputType==="both")&&(t.writeBundle=async()=>{this.viteConfig&&await this.safeExecute(async()=>{const e=this.viteConfig.build.outDir;await this.writeVersionFile(e)},"\u5199\u5165\u7248\u672C\u6587\u4EF6")})}}const g=r(c);export{g as generateVersion};
1
+ import{createPluginFactory as f,BasePlugin as p}from"../../factory/index.mjs";import{randomBytes as l}from"crypto";import{getDateFormatParams as c}from"../../common/format/index.mjs";import{writeFileContent as g}from"../../common/fs/index.mjs";import{join as d}from"path";import"../../logger/index.mjs";import"../../shared/vite-plugin.DcExl6jd.mjs";import"fs";import"../../common/concurrency/index.mjs";function F(i=8){const s=Math.max(1,Math.min(64,i));return l(Math.ceil(s/2)).toString("hex").slice(0,s)}function v(i,s){let e=i;for(const[o,n]of Object.entries(s))e=e.replace(new RegExp(`\\{${o}\\}`,"g"),n);return e}function b(i){const{format:s,buildTime:e,hashLength:o,semverBase:n,customFormat:a,prefix:u,suffix:h}=i,t=c(e),m=F(o);let r;switch(s){case"timestamp":r=`${t.YYYY}${t.MM}${t.DD}${t.HH}${t.mm}${t.ss}`;break;case"date":r=`${t.YYYY}.${t.MM}.${t.DD}`;break;case"datetime":r=`${t.YYYY}.${t.MM}.${t.DD}.${t.HH}${t.mm}${t.ss}`;break;case"semver":r=n||"1.0.0";break;case"hash":r=m;break;case"custom":r=$(a||"",{...t,hash:m},n);break;default:r=t.timestamp}return`${u||""}${r}${h||""}`}function $(i,s,e){const o={...s};if(e){const[n,a,u]=e.split(".");o.major=n||"1",o.minor=a||"0",o.patch=u||"0"}return v(i,o)}function T(i){return{version:i.version,buildTime:i.buildTime.toISOString(),timestamp:i.buildTime.getTime(),format:i.format,...i.extra}}class x extends p{version="";buildTime=new Date;getDefaultOptions(){return{format:"timestamp",semverBase:"1.0.0",outputType:"file",outputFile:"version.json",defineName:"__APP_VERSION__",hashLength:8,prefix:"",suffix:""}}validateOptions(){if(this.validator.field("format").enum(["timestamp","date","datetime","semver","hash","custom"]).field("outputType").enum(["file","define","both"]).field("hashLength").number().minValue(1).maxValue(32).validate(),this.options.format==="custom"&&!this.options.customFormat)throw new Error("\u5F53 format \u4E3A custom \u65F6\uFF0C\u5FC5\u987B\u63D0\u4F9B customFormat")}getPluginName(){return"generate-version"}generateVersion(){return b({format:this.options.format,buildTime:this.buildTime,hashLength:this.options.hashLength||8,semverBase:this.options.semverBase,customFormat:this.options.customFormat,prefix:this.options.prefix,suffix:this.options.suffix})}generateVersionInfo(){return T({version:this.version,buildTime:this.buildTime,format:this.options.format,extra:this.options.extra})}async writeVersionFile(s){const e=d(s,this.options.outputFile||"version.json"),o=this.generateVersionInfo();await g(e,JSON.stringify(o,null,2)),this.logger.success(`\u7248\u672C\u6587\u4EF6\u5DF2\u751F\u6210: ${e}`)}addPluginHooks(s){s.configResolved=()=>{this.buildTime=new Date,this.version=this.generateVersion(),this.logger.info(`\u751F\u6210\u7248\u672C\u53F7: ${this.version}`)},(this.options.outputType==="define"||this.options.outputType==="both")&&(s.config=()=>{this.version||(this.buildTime=new Date,this.version=this.generateVersion());const e=this.options.defineName||"__APP_VERSION__";return this.logger.info(`\u6CE8\u5165\u5168\u5C40\u53D8\u91CF: ${e} = "${this.version}"`),{define:{[e]:JSON.stringify(this.version),[`${e}_INFO`]:JSON.stringify(this.generateVersionInfo())}}}),(this.options.outputType==="file"||this.options.outputType==="both")&&(s.writeBundle=async()=>{this.viteConfig&&await this.safeExecute(async()=>{const e=this.viteConfig.build.outDir;await this.writeVersionFile(e)},"\u5199\u5165\u7248\u672C\u6587\u4EF6")})}}const D=f(x);export{D as generateVersion};
@@ -0,0 +1,5 @@
1
+ "use strict";const factory_index=require("../../factory/index.cjs"),u=require("node:fs"),l$2=require("node:path"),common_fs_index=require("../../common/fs/index.cjs"),common_path_index=require("../../common/path/index.cjs"),common_format_index=require("../../common/format/index.cjs"),common_concurrency_index=require("../../common/concurrency/index.cjs");require("../../logger/index.cjs"),require("../../shared/vite-plugin.Bcg6RW2N.cjs"),require("fs"),require("path");function _interopDefaultCompat(e){return e&&typeof e=="object"&&"default"in e?e.default:e}const l__default=_interopDefaultCompat(l$2),l$1={".jpg":"jpeg",".jpeg":"jpeg",".png":"png",".webp":"webp",".avif":"avif",".gif":"gif",".tiff":"tiff",".tif":"tiff",".svg":"svg"};function getFormatByExtension(e){return l$1[e]??null}function getOutputExtension(e){return{jpeg:".jpg",png:".png",webp:".webp",avif:".avif",gif:".gif",tiff:".tiff",svg:".svg"}[e]}function shouldOptimizeFile(e,i,t,o){return!(!getFormatByExtension(i)||t<o.threshold||o.includeExtensions.length>0&&!o.includeExtensions.includes(i)||common_path_index.isPathExcluded(e,o.excludePaths))}async function scanImageFiles(e,i){return(await common_fs_index.scanDirectory(e,{filter:(t,o,s)=>{const a=l__default.relative(e,t);return shouldOptimizeFile(a,o,s,i)}})).map(t=>{const o=common_path_index.normalizePath(l__default.relative(e,t.filePath)),s=getFormatByExtension(t.extension);return{filePath:t.filePath,relativePath:o,size:t.size,ext:t.extension,format:s}})}let l=null,w$1=!1;async function z(){if(l)return l;if(w$1)throw new Error("sharp \u6A21\u5757\u4E0D\u53EF\u7528\uFF0C\u8BF7\u5B89\u88C5: npm install sharp");w$1=!0;try{const e=await import("sharp");return l=e.default||e,l}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 g=null,d=!1;async function S(){if(g)return g;if(d)throw new Error("svgo \u6A21\u5757\u4E0D\u53EF\u7528\uFF0C\u8BF7\u5B89\u88C5: npm install svgo");d=!0;try{const e=await import("svgo");return g=e.default||e,g}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 E(e,i){const t={jpeg:80,png:6,webp:75,avif:50,gif:!0,tiff:"deflate"};return i[e]??t[e]}function b(e,i){const t=E(e,i);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 compressImage(e,i,t,o){const s=Date.now(),a=await z(),F=(await u.promises.stat(e)).size;let p=a(e,{limitInputPixels:o>0?o:void 0});p=p.rotate();const r=b(i,t);p=p.toFormat(i,r),await p.toFile(e+".tmp");const n=(await u.promises.stat(e+".tmp")).size;if(n<F)try{await u.promises.rename(e+".tmp",e)}catch{try{await u.promises.unlink(e+".tmp")}catch{}throw new Error(`\u538B\u7F29\u5931\u8D25: \u65E0\u6CD5\u5199\u5165\u8F93\u51FA\u6587\u4EF6 ${e}`)}else await u.promises.unlink(e+".tmp");const c=Date.now()-s,f=n<F?n:F;return{file:e,relativePath:"",originalSize:F,optimizedSize:f,ratio:common_format_index.calcRatio(F,f),sourceFormat:i,outputFormat:i,converted:!1,duration:c}}async function convertImage(e,i,t,o,s,a){const F=Date.now(),p=await z(),r=(await u.promises.stat(e)).size;let n=p(e,{limitInputPixels:s>0?s:void 0});n=n.rotate();const c=b(t,o);n=n.toFormat(t,c);const f=getOutputExtension(t),m=e.replace(/\.[^.]+$/,f);await n.toFile(m+".tmp");const h=(await u.promises.stat(m+".tmp")).size;try{await u.promises.rename(m+".tmp",m)}catch{try{await u.promises.unlink(m+".tmp")}catch{}throw new Error(`\u683C\u5F0F\u8F6C\u6362\u5931\u8D25: \u65E0\u6CD5\u5199\u5165\u8F93\u51FA\u6587\u4EF6 ${m}`)}if(!a&&m!==e)try{await u.promises.unlink(e)}catch{}const v=Date.now()-F;return{file:a?m:e,relativePath:"",originalSize:r,optimizedSize:h,ratio:common_format_index.calcRatio(r,h),sourceFormat:i,outputFormat:t,converted:!0,duration:v}}async function optimizeSvg(e,i){const t=Date.now(),{optimize:o}=await S(),s=(await u.promises.stat(e)).size,a=await u.promises.readFile(e,"utf-8"),F=o(a,{path:e,multipass:i.multipass??!1,plugins:i.plugins??[]}),p=Buffer.byteLength(F.data,"utf-8");p<s&&await u.promises.writeFile(e,F.data,"utf-8");const r=p<s?p:s,n=Date.now()-t;return{file:e,relativePath:"",originalSize:s,optimizedSize:r,ratio:common_format_index.calcRatio(s,r),sourceFormat:"svg",outputFormat:"svg",converted:!1,duration:n}}async function isSharpAvailable(){if(l)return!0;if(w$1)return!1;try{return await z(),!0}catch{return!1}}async function isSvgoAvailable(){if(g)return!0;if(d)return!1;try{return await S(),!0}catch{return!1}}function resolveConvertMapping(e){const i={};if(e.convertToWebp)for(const[t,o]of Object.entries(e.convertToWebp))o&&t!=="svg"&&t!=="webp"&&t!=="avif"&&(i[t]="webp");if(e.convertToAvif)for(const[t,o]of Object.entries(e.convertToAvif))o&&t!=="svg"&&t!=="webp"&&t!=="avif"&&(i[t]="avif");return e.convertMapping&&Object.assign(i,e.convertMapping),i}function getTargetFormat(e,i){return i[e]??e}function needsConversion(e,i){return e in i}function validateConvertMapping(e){const i=[];for(const[t,o]of Object.entries(e))t===o&&i.push(`\u6E90\u683C\u5F0F\u548C\u76EE\u6807\u683C\u5F0F\u4E0D\u80FD\u76F8\u540C: ${t}`),o==="svg"&&i.push(`\u4E0D\u652F\u6301\u5C06 ${t} \u8F6C\u6362\u4E3A svg \u683C\u5F0F`),t==="svg"&&i.push(`\u4E0D\u652F\u6301\u5C06 svg \u8F6C\u6362\u4E3A ${o} \u683C\u5F0F\uFF0CSVG \u5E94\u4F7F\u7528 svgo \u5355\u72EC\u4F18\u5316`);return i}function buildSummary(e,i,t,o){const s=e.reduce((n,c)=>n+c.originalSize,0),a=e.reduce((n,c)=>n+c.optimizedSize,0),F=common_format_index.calcRatio(s,a),p=e.filter(n=>n.converted).length,r={};for(const n of e){const c=n.outputFormat;r[c]||(r[c]={count:0,originalSize:0,optimizedSize:0,ratio:0}),r[c].count++,r[c].originalSize+=n.originalSize,r[c].optimizedSize+=n.optimizedSize}for(const n of Object.values(r))n.ratio=common_format_index.calcRatio(n.originalSize,n.optimizedSize);return{totalFiles:e.length,skippedFiles:i,failedFiles:t,totalOriginalSize:s,totalOptimizedSize:a,totalRatio:F,byFormat:r,convertedFiles:p,executionTime:o,stats:e}}async function writeReport(e,i,t){const o=common_fs_index.resolveReportPath(e,i);if(!o)return;const s={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(a=>({file:a.file,relativePath:a.relativePath,originalSize:a.originalSize,optimizedSize:a.optimizedSize,ratio:a.ratio,sourceFormat:a.sourceFormat,outputFormat:a.outputFormat,converted:a.converted,duration:a.duration}))};await common_fs_index.writeJsonReport(o,s)}class w extends factory_index.BasePlugin{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(o=>o===!1||typeof o=="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 i=resolveConvertMapping(this.options),t=validateConvertMapping(i);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(i){i.writeBundle=async()=>{await this.safeExecute(()=>this.optimizeAllImages(),"\u4F18\u5316\u56FE\u7247\u8D44\u6E90")}}onConfigResolved(i){super.onConfigResolved(i),this.convertMapping=resolveConvertMapping(this.options)}async checkDependencies(){this.sharpReady=await isSharpAvailable(),this.svgoReady=await isSvgoAvailable(),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 i=this.viteConfig.build.outDir,t=Date.now();this.logger.info(`\u5F00\u59CB\u626B\u63CF\u56FE\u7247\u6587\u4EF6: ${i}`);const o=await scanImageFiles(i,this.options);if(o.length===0){this.logger.info("\u672A\u627E\u5230\u9700\u8981\u4F18\u5316\u7684\u56FE\u7247\u6587\u4EF6");return}const s=o.filter(p=>p.format==="svg"),a=o.filter(p=>p.format!=="svg");if(this.logger.info(`\u53D1\u73B0 ${o.length} \u4E2A\u5F85\u4F18\u5316\u56FE\u7247 (\u4F4D\u56FE: ${a.length}, SVG: ${s.length})`),this.allStats=[],this.skippedCount=0,this.failedCount=0,a.length>0&&this.sharpReady){const p=await common_concurrency_index.runWithConcurrency(a,async r=>this.processBitmap({...r,format:r.format}),this.options.parallelLimit);for(const r of p)r.skipped?this.skippedCount++:r.error?(this.failedCount++,this.logger.warn(`\u4F18\u5316\u5931\u8D25: ${r.error}`)):r.stat&&this.allStats.push(r.stat)}else a.length>0&&!this.sharpReady&&(this.skippedCount+=a.length,this.logger.info(`\u8DF3\u8FC7 ${a.length} \u4E2A\u4F4D\u56FE\u6587\u4EF6\uFF08sharp \u4E0D\u53EF\u7528\uFF09`));if(s.length>0&&this.svgoReady){const p=await common_concurrency_index.runWithConcurrency(s,async r=>this.processSvg(r),this.options.parallelLimit);for(const r of p)r.skipped?this.skippedCount++:r.error?(this.failedCount++,this.logger.warn(`SVG \u4F18\u5316\u5931\u8D25: ${r.error}`)):r.stat&&this.allStats.push(r.stat)}else s.length>0&&!this.svgoReady&&(this.skippedCount+=s.length,this.logger.info(`\u8DF3\u8FC7 ${s.length} \u4E2A SVG \u6587\u4EF6\uFF08svgo \u4E0D\u53EF\u7528\uFF09`));const F=Date.now()-t;this.summary=buildSummary(this.allStats,this.skippedCount,this.failedCount,F),this.options.reportOutput&&(await writeReport(i,this.options.reportOutput,this.summary),this.logger.info(`\u4F18\u5316\u62A5\u544A\u5DF2\u751F\u6210: ${this.options.reportOutput}`)),this.logSummary()}async processBitmap(i){try{const t=getTargetFormat(i.format,this.convertMapping);let o;return needsConversion(i.format,this.convertMapping)?o=await convertImage(i.filePath,i.format,t,this.options.quality,this.options.maxPixels,this.options.keepOriginal):o=await compressImage(i.filePath,i.format,this.options.quality,this.options.maxPixels),o.relativePath=i.relativePath,{stat:o}}catch(t){const o=t instanceof Error?t.message:String(t);return{error:`${i.relativePath}: ${o}`}}}async processSvg(i){try{const t=await optimizeSvg(i.filePath,this.options.svgo);return t.relativePath=i.relativePath,{stat:t}}catch(t){const o=t instanceof Error?t.message:String(t);return{error:`${i.relativePath}: ${o}`}}}logSummary(){if(!this.summary)return;const{totalFiles:i,skippedFiles:t,failedFiles:o,totalOriginalSize:s,totalOptimizedSize:a,totalRatio:F,convertedFiles:p,executionTime:r}=this.summary;this.logger.success(`\u56FE\u7247\u4F18\u5316\u5B8C\u6210: ${i} \u4E2A\u6587\u4EF6\u5DF2\u4F18\u5316`+(t>0?`\uFF0C${t} \u4E2A\u8DF3\u8FC7`:"")+(o>0?`\uFF0C${o} \u4E2A\u5931\u8D25`:""),`\u539F\u59CB\u4F53\u79EF: ${common_format_index.formatFileSize(s)} \u2192 \u4F18\u5316\u540E: ${common_format_index.formatFileSize(a)}\uFF0C\u538B\u7F29\u7387: ${F}%`+(p>0?`\uFF0C\u683C\u5F0F\u8F6C\u6362: ${p} \u4E2A`:"")+`\uFF0C\u8017\u65F6: ${r}ms`);for(const[c,f]of Object.entries(this.summary.byFormat))this.logger.info(` ${c.toUpperCase().padEnd(5)} ${f.count} \u4E2A\u6587\u4EF6\uFF0C${common_format_index.formatFileSize(f.originalSize)} \u2192 ${common_format_index.formatFileSize(f.optimizedSize)}\uFF0C\u538B\u7F29\u7387: ${f.ratio}%`);const n=[...this.allStats].sort((c,f)=>f.ratio-c.ratio).slice(0,5);if(n.length>0){this.logger.info("\u538B\u7F29\u7387 Top 5:");for(const c of n){const f=c.converted?` (${c.sourceFormat}\u2192${c.outputFormat})`:"";this.logger.info(` ${c.ratio}% ${common_format_index.formatFileSize(c.originalSize)} \u2192 ${common_format_index.formatFileSize(c.optimizedSize)}${f} ${c.relativePath}`)}}}getStats(){return[...this.allStats]}getSummary(){return this.summary}}const imageOptimizer=factory_index.createPluginFactory(w);exports.imageOptimizer=imageOptimizer;
@@ -0,0 +1,242 @@
1
+ import { BasePluginOptions, PluginFactory } from '../../factory/index.cjs';
2
+ import 'vite';
3
+ import '../../shared/vite-plugin.B8FuZce1.cjs';
4
+ import '../../shared/vite-plugin.DRRlWY8P.cjs';
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 };