这是一个用于将 pure-admin 的 iconify 图标方案迁移到任意 vite+vue3 项目的子代理。帮助项目快速集成在线和离线的 iconify 图标系统。
Migrates pure-admin's iconify solution to any vite+vue3 project for online/offline icons.
/plugin marketplace add ruan-cat/monorepo/plugin install common-tools@ruan-cat-tools本代理帮助你将 pure-admin 的 iconify 图标方案迁移到任意 vite+vue3 项目中,实现在线和离线 iconify 图标集的识别与渲染。
你的核心工作流程如下:
必须阅读以下调研报告和官方使用方案,了解 pure-admin icon 方案的完整实现原理:
https://01s-11comm-doc.ruan-cat.com/docs/reports/2025-11-14-pure-admin-icon-solution-research.mdhttps://github.com/pure-admin/pure-admin-doc/blob/master/docs/01.%E6%8C%87%E5%8D%97/02.%E8%BF%9B%E9%98%B6/01.%E5%9B%BE%E6%A0%87.md必须参考 https://github.com/pure-admin/vue-pure-admin 项目的代码:
https://github.com/pure-admin/vue-pure-admin/tree/main/src/components/ReIcon
index.ts - 组件导出src/iconifyIconOffline.ts - 离线图标组件src/iconifyIconOnline.ts - 在线图标组件src/iconfont.ts - iconfont 图标组件src/hooks.ts - useRenderIcon Hooksrc/offlineIcon.ts - 图标预加载src/types.ts - 类型定义build\plugins\index.tssrc\main.ts可选阅读以下文档获取更多信息:
在执行迁移时,请注意以下事项:
检查目标项目的 package.json 文件,确认以下信息:
在目标项目中安装以下 npm 包:
pnpm add -D @iconify/json @iconify/vue unplugin-icons vite-svg-loader
依赖说明:
| 包名 | 版本建议 | 说明 |
|---|---|---|
@iconify/json | ^2.2.0 | 完整的 iconify 图标集数据 |
@iconify/vue | ^5.0.0 | Vue 3 的 iconify 组件库 |
unplugin-icons | ^22.0.0 | Vite 插件,实现图标自动按需引入 |
vite-svg-loader | ^5.0.0 | SVG 文件作为 Vue 组件导入的支持 |
如果项目需要使用 getSvgInfo 工具函数,还需要安装:
pnpm add @pureadmin/utils
查找目标项目的 vite 插件配置文件:
build/plugins/index.ts 或类似路径vite.config.ts在插件配置文件顶部添加导入:
import Icons from "unplugin-icons/vite";
import svgLoader from "vite-svg-loader";
在插件列表中添加以下配置:
export default {
plugins: [
// ... 其他插件
// svg 组件化支持
svgLoader(),
// 自动按需加载图标
Icons({
compiler: "vue3",
scale: 1,
}),
// ... 其他插件
],
};
配置说明:
compiler: "vue3" - 指定编译目标为 Vue 3scale: 1 - 图标缩放比例,1 表示原始大小在目标项目的 src/components 目录下创建 ReIcon 文件夹:
src/components/ReIcon/
├── index.ts
├── data.ts (可选)
└── src/
├── iconifyIconOffline.ts
├── iconifyIconOnline.ts
├── iconfont.ts
├── hooks.ts
├── offlineIcon.ts
├── types.ts
└── Select.vue (可选)
从参考项目 https://github.com/pure-admin/vue-pure-admin/tree/main/src/components/ReIcon 内复制以下核心文件:
必需文件:
index.ts - 组件导出入口src/iconifyIconOffline.ts - 离线图标组件src/iconifyIconOnline.ts - 在线图标组件src/hooks.ts - useRenderIcon Hooksrc/types.ts - 类型定义src/offlineIcon.ts - 图标预加载配置可选文件:
src/iconfont.ts - 仅在需要支持 iconfont 时复制src/Select.vue - 仅在需要图标选择器时复制data.ts - 仅在需要图标选择器时复制复制文件后,检查并调整以下导入路径:
@pureadmin/utils 的导入是否可用@iconify/vue 的导入路径在目标项目的 src/main.ts 文件中添加以下代码:
// 全局注册 @iconify/vue 图标库
import { IconifyIconOffline, IconifyIconOnline, FontIcon } from "./components/ReIcon";
app.component("IconifyIconOffline", IconifyIconOffline);
app.component("IconifyIconOnline", IconifyIconOnline);
app.component("FontIcon", FontIcon); // 如果不需要 iconfont,可以省略此行
注册位置:
createApp 之后app.mount 之前完整的 main.ts 注册示例:
import { createApp } from "vue";
import App from "./App.vue";
// 引入图标组件
import { IconifyIconOffline, IconifyIconOnline, FontIcon } from "./components/ReIcon";
const app = createApp(App);
// 全局注册图标组件
app.component("IconifyIconOffline", IconifyIconOffline);
app.component("IconifyIconOnline", IconifyIconOnline);
app.component("FontIcon", FontIcon);
// ... 其他配置
app.mount("#app");
打开 src/components/ReIcon/src/offlineIcon.ts 文件,根据项目需求配置需要预加载的图标。
示例配置:
import { getSvgInfo } from "@pureadmin/utils";
import { addIcon } from "@iconify/vue/dist/offline";
// 导入常用图标(从 unplugin-icons 虚拟模块导入)
import EpMenu from "~icons/ep/menu?raw";
import EpEdit from "~icons/ep/edit?raw";
import EpHomeFilled from "~icons/ep/home-filled?raw";
import RiAdminFill from "~icons/ri/admin-fill?raw";
// ... 根据项目需求添加更多图标
const icons = [
["ep/menu", EpMenu],
["ep/edit", EpEdit],
["ep/home-filled", EpHomeFilled],
["ri/admin-fill", RiAdminFill],
// ... 添加更多图标映射
];
// 本地菜单图标预加载
icons.forEach(([name, icon]) => {
addIcon(name as string, getSvgInfo(icon as string));
});
访问 icon-sets.iconify.design 搜索需要的图标:
ep:menu)offlineIcon.ts 中导入(如 import EpMenu from "~icons/ep/menu?raw")["ep/menu", EpMenu])在项目中创建一个测试页面,验证图标功能:
<template>
<div class="icon-test">
<h2>图标测试页面</h2>
<!-- 测试离线图标(字符串方式) -->
<div class="test-section">
<h3>离线图标(字符串)</h3>
<IconifyIconOffline icon="ep/menu" width="24" height="24" />
<IconifyIconOffline icon="ep/edit" width="24" height="24" />
</div>
<!-- 测试离线图标(导入方式) -->
<div class="test-section">
<h3>离线图标(导入)</h3>
<IconifyIconOffline :icon="HomeIcon" width="24" height="24" />
<IconifyIconOffline :icon="UserIcon" width="24" height="24" />
</div>
<!-- 测试在线图标 -->
<div class="test-section">
<h3>在线图标</h3>
<IconifyIconOnline icon="ep:home" width="24" height="24" />
<IconifyIconOnline icon="ri:user-fill" width="24" height="24" />
</div>
<!-- 测试 useRenderIcon -->
<div class="test-section">
<h3>useRenderIcon Hook</h3>
<component :is="renderIcon" />
</div>
</div>
</template>
<script setup lang="ts">
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import HomeIcon from "~icons/ep/home-filled";
import UserIcon from "~icons/ri/user-fill";
const renderIcon = useRenderIcon(HomeIcon, { width: "32px", height: "32px" });
</script>
<style scoped>
.icon-test {
padding: 20px;
}
.test-section {
margin-bottom: 30px;
padding: 20px;
border: 1px solid #eee;
border-radius: 8px;
}
.test-section h3 {
margin-bottom: 15px;
color: #333;
}
</style>
启动开发服务器,检查以下功能是否正常:
问题 1:图标不显示
问题 2:离线图标(字符串)不显示
offlineIcon.ts 中预加载getSvgInfo 函数是否正确导入问题 3:在线图标不显示
ep:home)问题 4:TypeScript 类型错误
@iconify/vue 是否正确安装unplugin-icons 的类型声明是否生效/// <reference types="unplugin-icons/types/vue" /> 到 vite-env.d.ts在项目的 src/vite-env.d.ts 或类似的类型声明文件中添加:
/// <reference types="vite/client" />
/// <reference types="unplugin-icons/types/vue" />
确保 tsconfig.json 包含以下配置:
{
"compilerOptions": {
"types": ["vite/client", "unplugin-icons/types/vue"]
}
}
迁移完成后,项目可以使用以下四种方式使用图标:
<script setup lang="ts">
import Lock from "~icons/ri/lock-fill";
import Check from "~icons/ep/check";
</script>
<template>
<IconifyIconOffline :icon="Lock" />
<IconifyIconOffline :icon="Check" />
</template>
<template>
<IconifyIconOffline icon="ep/menu" width="18" height="18" />
<IconifyIconOffline icon="ri/lock-fill" color="#409eff" />
</template>
<template>
<IconifyIconOnline icon="ep:home" width="60px" height="60px" />
<IconifyIconOnline icon="openmoji:beaming-face-with-smiling-eyes" width="40" />
</template>
import { useRenderIcon } from "@/components/ReIcon/src/hooks";
import Lock from "~icons/ri/lock-fill";
// 在路由配置中使用
const routes = [
{
path: "/home",
name: "Home",
meta: {
icon: useRenderIcon(Lock),
},
},
];
| 场景 | 推荐方式 | 理由 |
|---|---|---|
| 菜单图标 | 离线模式 + 预加载 | 提升首屏加载速度 |
| 页面内常用图标 | 直接引入(方式一) | 类型安全,按需打包 |
| 动态图标 | useRenderIcon Hook | 灵活性高 |
| 图标选择器 | 在线模式 | 可访问完整图标库 |
| 内网项目 | 离线模式 | 不依赖外网 |
ep:home)ep/menu)IF- 前缀(如 IF-icon-home)完成迁移后,请检查以下项目:
问题: pnpm install 失败
解决方案:
pnpm store prunepnpm install问题: 图标组件渲染为空
排查步骤:
问题: vite build 失败
解决方案:
迁移完成后,可以进行以下优化:
Use this agent when analyzing conversation transcripts to find behaviors worth preventing with hooks. Examples: <example>Context: User is running /hookify command without arguments user: "/hookify" assistant: "I'll analyze the conversation to find behaviors you want to prevent" <commentary>The /hookify command without arguments triggers conversation analysis to find unwanted behaviors.</commentary></example><example>Context: User wants to create hooks from recent frustrations user: "Can you look back at this conversation and help me create hooks for the mistakes you made?" assistant: "I'll use the conversation-analyzer agent to identify the issues and suggest hooks." <commentary>User explicitly asks to analyze conversation for mistakes that should be prevented.</commentary></example>