vite-plugin-cus-svg-icon
v0.1.0
Published
A lightweight Vite plugin for generating CSS icons from local SVG files only.
Maintainers
Readme
vite-plugin-svg-icon
一个轻量的 Vite 插件,只处理本地 SVG 图标,并尽量对齐 UnoCSS preset-icons 的使用方式与输出风格。
特性
- 仅处理本地 SVG,不依赖 UnoCSS
- 支持 UnoCSS 风格的
prefix、collections、FileSystemIconLoader、addCurrentFill - 内部已集成
@iconify/utils,无需在业务项目中额外单独安装和导入 - 默认类名前缀为
i-,支持自定义和多前缀 - 支持
safelist - 支持
extraProperties - 支持
scale、unit - 支持
mode: 'mask' | 'bg' | 'auto' - 支持 SVG 大小阈值控制,默认超过
10KB不注入 CSS,并输出警告 - 开发环境按 Vite 已加载模块增量扫描
- 构建阶段按配置范围全量扫描源码文本,不做 AST 解析
安装
npm install vite-plugin-svg-icon使用方式
import { defineConfig } from "vite";
import { svgIconPlugin } from "vite-plugin-svg-icon";
export default defineConfig({
plugins: [
svgIconPlugin({
// 必填:定义本地图标集合
collections: {
// 简洁写法:仅配置 path 即可
svg: {
path: "src/assets/icons",
},
// 目录级 safelist,适合动态拼接类名的目录
svgDy: {
path: "src/assets/icons-dynamic",
safelist: true,
},
},
}),
],
});在应用入口引入虚拟样式:
import "virtual:svg-icon.css";然后在模板或字符串中直接使用类名:
<span class="i-svg:home"></span>
<span class="i-svg:user-add"></span>
<span class="i-svgDy:logo"></span>
<span class="i-svgDy:rainbow"></span>
<span class="i-svgDy:rainbow?mask"></span>如果图标目录下存在 home.svg 与 user/add.svg,就会分别生成对应的 CSS。
本地 Collections
推荐简洁的 collection 对象写法:
import { svgIconPlugin } from "vite-plugin-svg-icon";
svgIconPlugin({
collections: {
svg: {
path: "src/assets/icons",
},
svgDy: {
path: "src/assets/icons-dynamic",
safelist: true,
},
},
});path:本地图标目录transform/fn:可选 SVG 处理函数autoFillCurrentColor:默认true,会自动在根<svg>上补fill="currentColor",若已有fill则保持不变safelist: true:自动保留该目录下所有图标,适合动态图标目录
也支持与 UnoCSS 接近的写法:
import {
FileSystemIconLoader,
addCurrentFill,
svgIconPlugin,
} from "vite-plugin-svg-icon";
svgIconPlugin({
collections: {
svg: FileSystemIconLoader("src/assets/icons", addCurrentFill),
svgDy: FileSystemIconLoader("src/assets/icons-dynamic", addCurrentFill),
},
});FileSystemIconLoader(dir, transform?):从本地目录懒加载 SVGaddCurrentFill(svg):给未声明fill的根<svg>注入fill="currentColor",适合单色图标- 目录中的
user/add.svg会映射为user-add
Demo
仓库根目录提供了一个基于最新 create-vite 生成的 demo 项目,用于真实验证插件行为:
cd demo
npm install
npm run dev如果你希望直接在仓库根目录执行完整验证,可以运行:
npm run verify这个命令会自动完成:
- 插件源码类型检查
- 插件单元测试
- 插件构建
demo构建验证demo开发服务器启动与虚拟 CSS 内容校验- 超过
10KB的 SVG 警告校验
配置项
interface SvgIconPluginOptions {
collections: Record<string, IconCollection>; // 必填:图标集合定义
prefix?: string | string[]; // 类名前缀,默认 'i-'
virtualModuleId?: string; // 虚拟 CSS 模块 ID,默认 'virtual:svg-icon.css'
scale?: number; // 图标尺寸缩放,默认 1
unit?: string; // 尺寸单位,默认 'em'
mode?: "mask" | "bg" | "auto"; // 默认渲染模式,默认 'auto'
maxSvgSize?: number; // SVG 大小上限(字节),默认 10 * 1024
contentInclude?: string[]; // 构建期扫描包含范围(glob)
contentExclude?: string[]; // 构建期扫描排除范围(glob)
safelist?: string[]; // 顶层保留类名(仍然有效)
extraProperties?: Record<string, string>; // 追加到所有图标规则的公共 CSS
}其中 collections 支持三种形式:
collections: {
svg: FileSystemIconLoader('src/icons', addCurrentFill),
svgDy: {
path: 'src/icons-dynamic',
safelist: true,
},
inline: {
home: '<svg viewBox="0 0 24 24"><path fill="currentColor" d="..." /></svg>',
},
}scale
- 类型:
number - 默认值:
1 - 含义:按当前字体大小
1em缩放图标 - 输出方式:直接作用于生成 CSS 的
width和height,不会额外引入尺寸变量
mode
mask:单色图标,使用mask/-webkit-maskbg:背景图模式,保留 SVG 原始颜色auto:默认值;检测到多色、渐变、pattern、image 等复杂着色时自动退化为背景图模式
extraProperties
与 UnoCSS 一样,可以给所有图标附加公共 CSS 属性,例如:
extraProperties: {
display: 'inline-block',
'vertical-align': 'middle',
}扫描策略
- 开发环境:在
transform/transformIndexHtml中扫描当前被 Vite 处理的源码文本,只更新受影响文件的图标集合 - 生产构建:在虚拟 CSS 模块加载时,对
contentInclude范围进行并发全量扫描 - 提取方式:直接把源码当纯文本处理,通过前缀和 collection 解析候选类名,不解析 AST
- 兼容类似
hover:i-svg:home、dark:i-svgDy:bell?bg的变体写法 - 对
safelist: true的文件系统 collection,插件会直接基于目录索引生成保留项,不需要用户手写readdirSync() - 开发环境会监听文件系统 collection 目录中的 SVG 新增、删除与修改,并自动刷新虚拟 CSS
性能设计
- 增量扫描:开发环境只处理当前被 Vite 触达或变更的源码文件,不在启动时扫描整个项目
- 轻量指纹:源码变更判断使用内容指纹而不是热路径上的
fs.stat(),这不仅在超大项目里有意义,在中小项目的高频 HMR 场景下同样能减少系统调用 - 快速失败:源码文本在进入正则提取前,会先检查是否包含任一图标前缀,避免大量无关文件进入完整扫描
- 并发去重:文件系统 collection 使用
refreshPromise合并并发刷新;单个图标加载也会做 in-flight 去重,避免重复读取同一个 SVG - 原子替换:collection 刷新时先构建新索引,再一次性替换旧索引,避免并发读取时看到
clear()后的中间态 - 增量 usage 索引:源码图标使用关系按文件差量维护,虚拟 CSS 重建时直接消费当前活跃 usage,而不是每次重新合并全部扫描结果
生成样式
生成结果参考 UnoCSS 的图标输出结构:
.i-svg\:home {
--svg-c-icon: url("data:image/svg+xml;utf8,...");
}
.i-svg\:home {
-webkit-mask: var(--svg-c-icon) no-repeat;
mask: var(--svg-c-icon) no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
background-color: currentColor;
color: inherit;
width: 1em;
height: 1em;
}限制
- 当前只处理本地 collections,不处理第三方图标集下载
- 嵌套目录会被展开为连字符,例如
user/add.svg -> i-svg:user-add auto模式采用启发式判断多色 SVG,极少数边缘 SVG 仍建议手动使用?mask/?bg
