还在为 SVG 烦恼?我写了个 CLI 工具,一键打包,性能拉满!(已开源)
作者:[King-GD]
GitHub: github.com/King-GD/svg...
哈喽,各位掘友们好!作为一名前端开发者,和 SVG
打交道是家常便饭。它轻量、可缩放、还能用 CSS 控制样式,简直是图标方案的完美选择。但随着项目越来越大,SVG
图标一多,管理和使用上的"痛点"也随之而来。
最近,我就被这些痛点折磨得不轻,索性一怒之下,自己动手写了个 CLI 工具来彻底解决它们。没想到,从一个几十行的脚本开始,我最终把它打磨成了一个可以发布到 NPM 的完整开源项目:svg-quick。
今天,我想和大家分享的,不仅仅是这个工具,更是从一个想法到一个开源产品的完整心路历程。
🤔 我们究竟在烦恼 SVG 的什么?
在使用 SVG 图标时,你是否也遇到过这些问题?
- 性能问题 :如果每个图标都作为独立的
.svg
文件请求,上百个图标就会导致上百个 HTTP 请求,这对性能是灾难性的。 - 打包效率 :在大型项目中,Webpack/Vite 每次构建都要实时去处理成百上千个 SVG 文件(比如用
svgr
转换),这会明显拖慢本就"弥足珍贵"的构建速度。 - 最终体积:将 SVG 作为 React/Vue 组件直接导入,每个图标都会被包裹一层组件的额外代码,积少成多,最终产物体积会悄悄膨胀。
- 灵活性差 :有时候我想在
<img>
里用,有时候想在 CSSbackground
里用,有时候又想给 ECharts 这类图表库用。不同的场景需要不同格式的图标,来回转换非常繁琐。
这些问题,每一个都像一根小刺,扎在日常开发的幸福感上。
💡 解决方案的进化之路
V1.0: 一个满足自己的脚本
一切始于一个简单的 Node.js 脚本。思路很直接:
- 扫描一个指定文件夹里的所有
.svg
文件。 - 读取每个文件的内容。
- 用
svgo
压缩优化。 - 把所有优化后的 SVG 字符串,塞到一个 JS 对象里。
- 最后生成一个
index.js
文件,导出这个大对象和几个辅助函数。
这个脚本解决了"多文件请求"和"重复优化"的问题,让我可以很方便地在项目里使用。但它的问题也很明显:路径硬编码、无法复用、每次换项目都得复制粘贴改代码。
V2.0: 走向 CLI 工具
为了让这个脚本能在任何项目中开箱即用,我决定把它改造成一个真正的命令行工具。
我引入了 yargs
来解析命令行参数,核心命令很快就成型了:
bash
svg-quick --input ./icons --output ./dist
这比之前的脚本强大多了!我可以指定任意的输入和输出目录,它变成了一个可复用的工具。我当时觉得已经很完美了,直到我遇到了现代前端工程化的"灵魂拷问"------ Tree-shaking。
V3.0: 拥抱 Tree-shaking 和专业化
我意识到,之前把所有图标都打包到一个大对象里的做法,有一个致命缺陷:
javascript
// 之前产物的核心
export const icons = {
user: '<svg>...',
setting: '<svg>...',
// ... 500 个图标
};
当我在代码里只 import
并使用 user
图标时,打包工具(Webpack/Vite)无法判断 icons
对象里其他 499 个图标是无用的,最终会导致所有图标都被打包进产物!
这绝对不能忍!于是,我重构了整个工具的输出结构。
新的产物变成了这样:
javascript
// Tree-shakeable 的产物
export const user = '<svg>...</svg>';
export const setting = '<svg>...</svg>';
// ... 每个图标都是一个独立的 const 导出
这样一来,import { user } from '...';
就能让打包工具精确地"摇掉"所有未使用的图标,完美实现了按需打包。
同时,我还增加了更多专业化的功能:
- 多种输出模式 (
--mode
) : 用户可以选择只生成按需打包的版本 (treeshakeable
),或者只生成全量版本 (full
),甚至两者都要 (all
)。 - 类型定义 : 自动生成
.d.ts
文件,在 TypeScript 项目中提供完美的类型提示和自动补全。 - 代码美化 : 内置
Prettier
,确保生成的代码风格统一且美观。
至此,svg-quick
已经从一个自用的"小作坊"脚本,进化成了一个功能完备、设计考究的"正规军"。
🚀 正式介绍:svg-quick
现在,你可以通过 npx
轻松使用它,无需安装:
bash
npx svg-quick --input <源目录> --output <目标目录> --mode <输出模式>
它能为你带来什么?
- ⚡️ 极致性能: 预构建模式,提升构建速度,减小产物体积。
- 🌳 完美按需打包: 确保最终产物只包含你用到的图标。
- ✨ 高度灵活性: 多种输出模式,满足任何使用场景。
- 💻 优秀的开发体验: 统一的 API 和完整的 TypeScript 支持。
- 🔧 强大的优化 : 内置
svgo
,自动压缩优化。
产物使用示例
当使用推荐的 treeshakeable
模式生成产物后,你可以这样优雅地使用:
javascript
// 在你的 React / Vue / Svelte 组件中
import { user, arrowLeft } from '../generated-icons';
// 'user' 和 'arrowLeft' 都是优化后的 SVG 字符串
// 你可以轻松地封装成自己的 <Icon> 组件
// React 示例:
const Icon = ({ svgString, ...props }) => (
<span
{...props}
dangerouslySetInnerHTML={{ __html: svgString }}
/>
);
const App = () => (
<div>
<Icon svgString={user} style={{ color: 'blue' }} />
<Icon svgString={arrowLeft} style={{ color: 'red' }} />
</div>
);
🌟 写在最后
从一个解决自己痛点的小脚本,到一个功能完善并发布到 NPM 的开源工具,这个过程让我收获良多。最大的感悟是,"轮子"不一定要惊天动地,能解决一个真实、具体、哪怕很小的问题,它就是有价值的。
svg-quick
现在已经非常稳定,如果你也曾为 SVG 的管理而烦恼,不妨试一试它。
如果你觉得这个小工具对你有帮助,欢迎给我的 GitHub 仓库点个 Star 🌟!如果你有任何想法或建议,也非常欢迎提 Issue 或 PR。
感谢阅读!
项目链接
- GitHub (求 Star ⭐) : github.com/King-GD/svg...
- NPM : www.npmjs.com/package/svg...