「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: [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected], [email protected]

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

相关推荐
月明长歌8 小时前
Vue + Axios + Mock.js 全链路实操:从封装到数据模拟的深度解析
前端·javascript·vue.js·elementui·es6
头顶秃成一缕光8 小时前
若依——基于AI+若依框架的实战项目(实战篇(下))
java·前端·vue.js·elementui·aigc
念九_ysl8 小时前
基数排序算法解析与TypeScript实现
前端·算法·typescript·排序算法
安分小尧13 小时前
[特殊字符] 使用 Handsontable 构建一个支持 Excel 公式计算的动态表格
前端·javascript·react.js·typescript·excel
跟着珅聪学java15 小时前
spring boot +Elment UI 上传文件教程
java·spring boot·后端·ui·elementui·vue
....49215 小时前
Vue3 + Element Plus + AntV X6 实现拖拽树组件
javascript·vue.js·elementui·antvx6
杉之20 小时前
常见前端GET请求以及对应的Spring后端接收接口写法
java·前端·后端·spring·vue
yanxy5121 天前
【TS学习】(18)分发逆变推断
前端·学习·typescript
剑亦未配妥1 天前
Vue2函数式组件实战:手写可调用的动态组件,适用于toast轻提示、tip提示、dialog弹窗等
前端·vue.js·vue
喜陈2 天前
解决elementui-plus使用el-table的合计功能时横向滚动条显示在了合计上方
前端·vue.js·elementui