🚀 作者主页: 有来技术
🔥 开源项目: youlai-mall ︱vue3-element-admin︱youlai-boot︱vue-uniapp-template
🌺 仓库主页: GitCode︱ Gitee ︱ Github
💖 欢迎点赞 👍 收藏 ⭐评论 📝 如有错误敬请纠正!
目录
- 📝 前言背景
- 🔍 问题分析:插件停止维护,依赖过时
- 🛠️ 解决方案:使用 `@unocss/preset-icons`
- 1️⃣ 安装依赖
- 2️⃣ 配置 `uno.config.ts`
- 3️⃣ 使用图标
- 🏆 总结
📝 前言背景
在此之前,开源项目 vue3-element-admin 使用 vite-plugin-svg-icons 管理和加载从iconfont 等网站下载到本地 SVG 图标。但由于该插件 已停止维护,部分依赖逐渐过时,可能影响未来兼容性,因此需要迁移到更稳定的方案。
🔍 问题分析:插件停止维护,依赖过时
在项目中执行 pnpm install
时,我们发现控制台出现了以下 废弃依赖警告:
WARN 10 deprecated subdependencies found: fstream@1.0.12, glob@7.2.3, inflight@1.0.6, lodash.isequal@4.5.0, resolve-url@0.2.1, rimraf@2.7.1, source-map-resolve@0.5.3, source-map-url@0.4.1, stable@0.1.8, urix@0.1.0
通过 pnpm why urix
追踪依赖来源,发现 这些过时依赖属于 vite-plugin-svg-icons
,而 vite-plugin-svg-icons
最近一次更新是在 2022 年 1 月 29 日,其被维护的概率很小。
为了确保长期稳定性,决定 用 @unocss/preset-icons
替代 vite-plugin-svg-icons
。
🛠️ 解决方案:使用 @unocss/preset-icons
@unocss/preset-icons
是 UnoCSS 提供的图标预设,支持从 本地和在线图标库 加载图标。它相比 vite-plugin-svg-icons
具有以下优势:
- 无需额外安装,
unocss
自带@unocss/preset-icons
,减少额外依赖; - 直接支持
Iconify
图标集,可以同时使用 本地 SVG 和在线图标; - 按需加载,无需手动导入,减少构建体积。
官方文档:https://unocss.nodejs.cn/presets/icons
1️⃣ 安装依赖
使用 FileSystemIconLoader
从文件系统加载本地 SVG 图标,需要安装 @iconify/utils
作为开发依赖:
pnpm add -D @iconify/utils
⚠️ 注意:@unocss/preset-icons
已包含在 unocss
中,无需单独安装。
2️⃣ 配置 uno.config.ts
在 vue3-element-admin 项目中,应在 uno.config.ts
配置,而非 vite.config.ts
。
完整配置如下:
import { defineConfig, presetUno } from "unocss";
import presetIcons from "@unocss/preset-icons";
import { FileSystemIconLoader } from "@iconify/utils/lib/loader/node-loaders";
import fs from "fs";
// 本地 SVG 图标存放目录
const iconsDir = "./src/assets/icons";
// 读取本地 SVG 目录,自动生成 `safelist`
const generateSafeList = () => {
try {
return fs
.readdirSync(iconsDir)
.filter((file) => file.endsWith(".svg"))
.map((file) => `i-svg:${file.replace(".svg", "")}`);
} catch (error) {
console.error("无法读取图标目录:", error);
return [];
}
};
export default defineConfig({
presets: [
presetIcons({
// 设置全局图标默认属性
extraProperties: {
width: "1em",
height: "1em",
display: "inline-block",
},
// 注册本地 SVG 图标集合
collections: {
// svg 是图标集合名称,使用 `i-svg:图标名` 调用
svg: FileSystemIconLoader(iconsDir, (svg) => {
// 如果 SVG 文件未定义 `fill` 属性,则默认填充 `currentColor`
// 这样图标颜色会继承文本颜色,方便在不同场景下适配
return svg.includes('fill="')
? svg
: svg.replace(/^<svg /, '<svg fill="currentColor" ');
}),
},
}),
],
safelist: generateSafeList(), // 动态生成 `safelist`
});
与 官方配置 有两点不同:
-
使用
safelist
解决动态图标加载问题UnoCSS 采用 按需扫描 机制,仅能解析静态类名,而
vue3-element-admin
的菜单图标是动态加载的,例如:<template> <div v-for="item in menuItems" :key="item.name"> <div :class="`i-svg:${item.icon}`"></div> {{ item.name }} </div> </template> <script setup lang="ts"> const menuItems = [ { name: "首页", icon: "home" }, { name: "设置", icon: "settings" }, ]; </script>
由于
unocss
无法在编译阶段解析动态绑定的:class
,导致图标不会被正确加载。因此,我们通过 扫描src/assets/icons
目录并动态生成safelist
,确保所有本地 SVG 图标类名都能被unocss
识别。 -
优化
fill
处理,支持多彩图标为了避免默认
fill="currentColor"
影响多彩图标的渲染,我们仅在SVG
未定义fill
时才自动补充:if (!svg.includes('fill="')) { return svg.replace(/^<svg /, '<svg fill="currentColor" '); }
3️⃣ 使用图标
在 uno.config.ts
中,通过 collections
注册了名为 svg
的本地 SVG 图标集合,并使用 FileSystemIconLoader
读取 src/assets/icons
目录下的 SVG 文件。因此,可直接使用 i-svg:图标名称
调用。
示例:
src/assets/icons/home.svg → i-svg:home
<template>
<!-- 默认尺寸 1em,颜色继承父级 text 颜色 -->
<div class="i-svg:home"></div>
<!-- 自定义颜色和尺寸 -->
<div class="i-svg:home text-xl text-blue-500"></div>
</template>
最终效果如下:
🏆 总结
由于 vite-plugin-svg-icons
停止更新,且部分依赖过时,我们成功迁移到 @unocss/preset-icons
,并针对 vue3-element-admin
进行了优化和改造:
✅ 使用 @unocss/preset-icons
统一管理本地 SVG 图标
✅ 无需手动安装 @unocss/preset-icons
,unocss
已内置
✅ 通过 safelist
自动读取 src/assets/icons
,支持动态菜单图标
✅ 减少额外依赖,提高项目长期可维护性
开源项目地址:vue3-element-admin
🚀 通过这次改造,我们实现了 更灵活、现代的 SVG 图标管理方式,欢迎大家尝试并优化自己的项目!