svgConvert.ts 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import fs from 'fs';
  2. import { SVG, cleanupSVG, parseColors, /*runSVGO,*/ isEmptyColor } from '@iconify/tools';
  3. import { Plugin } from 'vite';
  4. interface Options {
  5. singleColorIconDir?: string;
  6. multiColorIconDir?: string;
  7. }
  8. export default function svgConvert(options: Options = {}): Plugin {
  9. const {
  10. singleColorIconDir = 'src/assets/iconify/single-color',
  11. multiColorIconDir = 'src/assets/iconify/multi-color',
  12. } = options;
  13. return {
  14. name: 'vite-plugin-svg-convert',
  15. async transform(_, id) {
  16. // 只处理 SVG 文件
  17. if (!id.endsWith('.svg')) return null;
  18. // 检查是否是目标目录下的文件
  19. const isSingleColor = id.includes(singleColorIconDir);
  20. const isMultiColor = id.includes(multiColorIconDir);
  21. if (!isSingleColor && !isMultiColor) return null;
  22. // 读取 SVG 文件内容
  23. const svgContent = await fs.promises.readFile(id, 'utf-8');
  24. // 检查是否包含 image 标签
  25. if (svgContent.includes('<image')) {
  26. // 如果是多色图标且包含 image 标签,直接返回原始内容
  27. if (isMultiColor) {
  28. const viewBox = svgContent.match(/viewBox="([^"]+)"/)?.[1] || '0 0 1 1';
  29. const [, , width, height] = viewBox.split(' ').map(Number);
  30. // 提取 SVG 标签内的内容
  31. const innerContent = svgContent.replace(/<svg[^>]*>([\s\S]*)<\/svg>/i, '$1');
  32. return {
  33. code: `export default {width: ${width}, height: ${height}, body: ${JSON.stringify(innerContent)}}`,
  34. };
  35. }
  36. }
  37. // 创建 SVG 实例
  38. const svg = new SVG(svgContent);
  39. // 清理 SVG
  40. await cleanupSVG(svg);
  41. // 根据目录类型选择不同的处理方式
  42. if (isSingleColor) {
  43. // 单色图标处理
  44. parseColors(svg, {
  45. defaultColor: 'currentColor',
  46. callback: (_, colorStr, color) => {
  47. return !color || isEmptyColor(color) ? colorStr : 'currentColor';
  48. },
  49. });
  50. }
  51. // 获取优化后的 SVG 内容
  52. const width = svg.viewBox.width;
  53. const height = svg.viewBox.height;
  54. // const aspectRatio = height / width;
  55. // const newWidth = '1rem';
  56. // const newHeight = `${aspectRatio}rem`;
  57. // // 运行 SVGO 优化
  58. // await runSVGO(svg, {
  59. // plugins: [
  60. // {
  61. // name: 'removeAttrs',
  62. // params: {
  63. // attrs: ['width', 'height'],
  64. // },
  65. // },
  66. // {
  67. // name: 'addAttributesToSVGElement',
  68. // params: {
  69. // attributes: [{ width: newWidth }, { height: newHeight }],
  70. // },
  71. // },
  72. // ],
  73. // });
  74. // 获取优化后的 SVG 内容
  75. const optimizedSvg = svg.toMinifiedString();
  76. // 提取 SVG 标签内的内容
  77. const innerContent = optimizedSvg.replace(/<svg[^>]*>([\s\S]*)<\/svg>/i, '$1');
  78. // 返回转换后的代码
  79. return {
  80. code: `export default {width: ${width}, height: ${height}, body: ${JSON.stringify(innerContent)}}`,
  81. };
  82. },
  83. };
  84. }