From 0725eecd41ec86e279cd4ec95a5cab3549a7d476 Mon Sep 17 00:00:00 2001 From: denis0001-dev Date: Tue, 18 Nov 2025 22:18:43 +0300 Subject: [PATCH] Add SVG optimization --- frontend/plugins/optimizeSvg.ts | 67 +++++++++++++++++++++++++++++++++ frontend/vite.config.ts | 2 + package.json | 1 + 3 files changed, 70 insertions(+) create mode 100644 frontend/plugins/optimizeSvg.ts diff --git a/frontend/plugins/optimizeSvg.ts b/frontend/plugins/optimizeSvg.ts new file mode 100644 index 0000000..9b1d120 --- /dev/null +++ b/frontend/plugins/optimizeSvg.ts @@ -0,0 +1,67 @@ +import type { Plugin } from 'vite'; +import { optimize } from 'svgo'; + +export interface OptimizeSvgOptions { + /** + * Whether to enable SVG optimization + * @default true + */ + enabled?: boolean; +} + +const svgoConfig: Parameters[1] = { + multipass: true, + plugins: [ + { + name: 'preset-default', + params: { + overrides: { + // Keep IDs if they might be referenced (minify instead of remove) + cleanupIds: { + remove: false, + minify: true + } + } + } + } + ] +}; + +/** + * Optimizes SVG files during build by: + * - Minifying SVG code + * - Removing metadata and comments + * - Removing unnecessary attributes + * - Optimizing paths and shapes + */ +export function optimizeSvg(options?: OptimizeSvgOptions): Plugin { + const enabled = options?.enabled !== false; + + return { + name: 'optimize-svg', + apply: 'build', + enforce: 'post', + async generateBundle(options, bundle) { + if (!enabled) return; + + // Optimize SVGs in the bundle + for (const [fileName, chunk] of Object.entries(bundle)) { + if (fileName.endsWith('.svg') && chunk.type === 'asset') { + try { + const svgContent = typeof chunk.source === 'string' + ? chunk.source + : Buffer.from(chunk.source).toString('utf-8'); + + const result = optimize(svgContent, svgoConfig); + + if (result.data && result.data !== svgContent) { + chunk.source = result.data; + } + } catch (error) { + console.warn(`Failed to optimize SVG ${fileName}:`, error); + } + } + } + } + }; +} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index ab5318a..719e614 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -7,6 +7,7 @@ import path from "path"; import { visualizer } from 'rollup-plugin-visualizer'; import sassDts from 'vite-plugin-sass-dts'; import { optimizeCssModules } from './plugins/optimizeCssModules'; +import { optimizeSvg } from './plugins/optimizeSvg'; const currentDir = path.resolve(__dirname); const outDir = process.env.VITE_ELECTRON ? `${currentDir}/build/electron` : `${currentDir}/build/normal`; @@ -21,6 +22,7 @@ const plugins: PluginOption[] = [ enabledMode: ['development', 'production'] }), optimizeCssModules(), + optimizeSvg(), createHtmlPlugin({ minify: { collapseWhitespace: true, diff --git a/package.json b/package.json index d59d2b4..db5d7ce 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "postcss": "^8.5.6", "rollup-plugin-visualizer": "^6.0.4", "sass-embedded": "^1.93.0", + "svgo": "^4.0.0", "terser": "^5.44.0", "typescript": "~5.9.2", "vite": "^7.1.6",