「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 图标管理方式,欢迎大家尝试并优化自己的项目!

相关推荐
一支鱼1 小时前
leetcode-6-正则表达式匹配
算法·leetcode·typescript
PBitW3 小时前
element plus 使用细节 (二)
前端·vue·element plus·element使用细节
拜无忧6 小时前
【教程】vue+vite+ts创建一个最新的高性能后台项目架构
vue.js·typescript·vite
叫我阿柒啊6 小时前
从全栈开发到云原生:一位Java工程师的实战经验分享
java·spring boot·redis·云原生·kafka·vue·全栈开发
咔叽布吉6 小时前
【前端】ElementPlus表单数组形式数据自定义校验(必填)
前端·elementui
几度风雨见丹心11 小时前
vue+elementUI 进行表格行内新增及校验,同行其他输入框数据影响当前输入框校验结果
前端·vue.js·elementui
叫我阿柒啊13 小时前
Java全栈工程师的实战面试:从Vue到Spring Boot的技术旅程
java·spring boot·微服务·vue·api·react·rest
GDAL13 小时前
解决 ES 模块与 CommonJS 模块互操作性的关键开关esModuleInterop
typescript
Sui_Network1 天前
Yotta Labs 选择 Walrus 作为去中心化 AI 存储与工作流管理的专用数据层
大数据·javascript·人工智能·typescript·去中心化·区块链
一支鱼1 天前
leetcode-5-最长回文子串
算法·leetcode·typescript