install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/TerminalSkills/skills/svgo" ~/.claude/skills/comeonoliver-skillshub-svgo && rm -rf "$T"
manifest:
skills/TerminalSkills/skills/svgo/SKILL.mdsource content
SVGO
SVG Optimizer. Removes editor metadata, collapses groups, shortens paths, and minifies without visual changes.
Setup
# Install SVGO as a CLI tool and Node.js library. npm install -D svgo
CLI Usage
# Optimize a single SVG file and overwrite it. npx svgo input.svg -o output.svg # Optimize all SVGs in a directory recursively. npx svgo -r -f ./icons --output ./icons-optimized # Show optimization stats without writing. npx svgo input.svg --pretty --indent 2 -o -
Programmatic API
// src/svg/optimize.ts — Optimize SVG strings programmatically with custom config. import { optimize, Config } from "svgo"; const config: Config = { multipass: true, plugins: [ "preset-default", "removeDimensions", { name: "sortAttrs", params: { xmlnsOrder: "alphabetical" }, }, ], }; export function optimizeSvg(svgString: string): string { const result = optimize(svgString, config); return result.data; }
Custom Plugin Configuration
// svgo.config.js — Project-level SVGO config. Disable plugins that break // specific SVGs (e.g., keep viewBox, don't merge paths in icons). /** @type {import('svgo').Config} */ module.exports = { multipass: true, plugins: [ { name: "preset-default", params: { overrides: { removeViewBox: false, // keep viewBox for responsive scaling mergePaths: false, // don't merge — breaks some icon animations convertShapeToPath: false, // keep semantic shapes (rect, circle) }, }, }, "removeXMLNS", // remove xmlns for inline SVG use "removeDimensions", // remove width/height, rely on viewBox "sortAttrs", "removeStyleElement", ], };
Batch Processing
// src/svg/batch.ts — Optimize all SVGs in a directory and report savings. import { optimize } from "svgo"; import fs from "fs"; import path from "path"; export async function optimizeDirectory(inputDir: string, outputDir: string) { const files = fs.readdirSync(inputDir).filter((f) => f.endsWith(".svg")); let totalBefore = 0; let totalAfter = 0; fs.mkdirSync(outputDir, { recursive: true }); for (const file of files) { const input = fs.readFileSync(path.join(inputDir, file), "utf-8"); const result = optimize(input, { multipass: true, plugins: ["preset-default"] }); totalBefore += input.length; totalAfter += result.data.length; fs.writeFileSync(path.join(outputDir, file), result.data); } const savings = ((1 - totalAfter / totalBefore) * 100).toFixed(1); console.log(`Optimized ${files.length} files. Saved ${savings}%`); }
Writing a Custom Plugin
// src/svg/custom-plugin.ts — SVGO custom plugin that adds a class attribute // to all <path> elements for CSS styling. import type { CustomPlugin } from "svgo"; export const addPathClass: CustomPlugin = { name: "addPathClass", fn: () => ({ element: { enter: (node) => { if (node.name === "path") { node.attributes.class = "icon-path"; } }, }, }), }; // Usage: optimize(svg, { plugins: [addPathClass] })
Build Integration
// vite.config.ts — Use vite-plugin-svgo to optimize SVGs at build time. // SVGs imported as components are automatically optimized. import { defineConfig } from "vite"; import svgo from "vite-plugin-svgo"; export default defineConfig({ plugins: [ svgo({ multipass: true, plugins: [ { name: "preset-default", params: { overrides: { removeViewBox: false } } }, "removeDimensions", ], }), ], });