「vue3-element-admin」告别 vite-plugin-svg-icons!用 @unocss/preset-icons 加载本地 SVG 图标

🚀 作者主页: 有来技术

🔥 开源项目: youlai-mallvue3-element-adminyoulai-bootvue-uniapp-template

🌺 仓库主页: GitCodeGiteeGithub

💖 欢迎点赞 👍 收藏 ⭐评论 📝 如有错误敬请纠正!

目录

    • [📝 前言背景](#📝 前言背景)
    • [🔍 问题分析:插件停止维护,依赖过时](#🔍 问题分析:插件停止维护,依赖过时)
    • [🛠️ 解决方案:使用 `@unocss/preset-icons`](#🛠️ 解决方案:使用 @unocss/preset-icons)
      • [1️⃣ 安装依赖](#1️⃣ 安装依赖)
      • [2️⃣ 配置 `uno.config.ts`](#2️⃣ 配置 uno.config.ts)
      • [3️⃣ 使用图标](#3️⃣ 使用图标)
    • [🏆 总结](#🏆 总结)

📝 前言背景

在此之前,开源项目 vue3-element-admin 使用 vite-plugin-svg-icons 管理和加载从iconfont 等网站下载到本地 SVG 图标。但由于该插件 已停止维护,部分依赖逐渐过时,可能影响未来兼容性,因此需要迁移到更稳定的方案。

🔍 问题分析:插件停止维护,依赖过时

在项目中执行 pnpm install 时,我们发现控制台出现了以下 废弃依赖警告

bash 复制代码
 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 作为开发依赖:

bash 复制代码
pnpm add -D @iconify/utils

⚠️ 注意:@unocss/preset-icons 已包含在 unocss 中,无需单独安装。

2️⃣ 配置 uno.config.ts

vue3-element-admin 项目中,应在 uno.config.ts 配置,而非 vite.config.ts

完整配置如下:

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`
});

官方配置 有两点不同

  1. 使用 safelist 解决动态图标加载问题

    UnoCSS 采用 按需扫描 机制,仅能解析静态 类名,而 vue3-element-admin 的菜单图标是动态加载的,例如:

    html 复制代码
    <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 识别。

  2. 优化 fill 处理,支持多彩图标

    为了避免默认 fill="currentColor" 影响多彩图标的渲染,我们仅在 SVG 未定义 fill 时才自动补充:

    ts 复制代码
    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:图标名称 调用。

示例:

text 复制代码
src/assets/icons/home.svg → i-svg:home
html 复制代码
<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-iconsunocss 已内置

通过 safelist 自动读取 src/assets/icons,支持动态菜单图标

减少额外依赖,提高项目长期可维护性

开源项目地址vue3-element-admin

🚀 通过这次改造,我们实现了 更灵活、现代的 SVG 图标管理方式,欢迎大家尝试并优化自己的项目!

相关推荐
IT教程资源6 小时前
N-159基于springboot,vue,AI协同过滤算法旅游推荐系统
mysql·vue·前后端分离·springboot旅游推荐·协同过滤算法旅游推荐·ai旅游推荐
EndingCoder6 小时前
反射和元数据:高级装饰器用法
linux·运维·前端·ubuntu·typescript
We་ct6 小时前
LeetCode 135. 分发糖果:双向约束下的最小糖果分配方案
前端·算法·leetcode·typescript
孟无岐1 天前
【Laya】Byte 二进制数据处理
网络·typescript·游戏引擎·游戏程序·laya
孟无岐1 天前
【Laya】ClassUtils 类反射工具
typescript·游戏引擎·游戏程序·laya
半兽先生1 天前
解决使用jsPDF实现表格数据导出pdf功能时中文乱码问题
前端·vue.js·elementui
We་ct1 天前
LeetCode 380. O(1) 时间插入、删除和获取随机元素 题解
前端·算法·leetcode·typescript
孟无岐1 天前
【Laya】Ease 缓动函数
typescript·游戏引擎·游戏程序·laya
We་ct1 天前
LeetCode 238. 除了自身以外数组的乘积|最优解详解(O(n)时间+O(1)空间)
前端·算法·leetcode·typescript
wanzhong23331 天前
开发日记13-响应式变量
开发语言·前端·javascript·vue