项目中使用了 SoybeanAdmin 框架,菜单图标基于 Iconify 的动态 <Icon> 组件渲染。菜单配置完全由后端返回,图标名称为运行时数据(如 material-symbols:code-blocks-outline),无法在编译时确定。
当项目部署到内网(无法访问外网)时,所有的 Iconify 图标请求都会指向 https://api.iconify.design,导致图标无法加载。同时,若通过官方文档建议的全量注册 JSON 文件(@iconify/json),两个大体积图标集(material-symbols 约 50MB,solar 约 44MB)会严重拖慢开发环境启动速度,甚至造成浏览器卡顿。
本文提供一种完全离线、按需加载、零性能损耗的解决方案:在内网部署一个本地 Iconify API 服务,前端只需修改请求地址即可像访问官方 CDN 一样使用所有图标。
无需修改任何菜单配置或组件代码:仍然使用 <Icon icon="xxx" /> 动态写法。
无需在项目中导入庞大的 JSON 文件:本地 API 服务只返回请求的单个图标数据。
支持任意图标动态扩展:管理员在后台新增图标只需保证对应图标集的 JSON 文件存在于服务端即可。
部署简单,维护成本低:基于 Docker 一键启动。
bash
docker pull iconify/api在宿主机创建一个目录用于存放图标集 JSON 文件,例如 /opt/iconify-data。然后从项目 node_modules/@iconify/json/json/ 中复制需要用到的图标集 JSON 文件(按需复制,无需全部):
bash
mkdir -p /opt/iconify-data
# 复制你需要的图标集(示例)
cp node_modules/@iconify/json/json/material-symbols.json /opt/iconify-data/
cp node_modules/@iconify/json/json/solar.json /opt/iconify-data/
cp node_modules/@iconify/json/json/carbon.json /opt/iconify-data/
cp node_modules/@iconify/json/json/tabler.json /opt/iconify-data/
# ... 其他用到的图标集提示:如果后续需要新增图标集,只需将新 JSON 文件复制到该目录,无需重启服务(API 会动态读取)。
bash
docker run -d \
--name iconify-api \
-p 3000:3000 \
-v /opt/iconify-data:/var/www/iconify/api/data \
-e ICONIFY_API_CACHE=memory \
-e ICONIFY_API_DATA=/var/www/iconify/api/data \
iconify/api参数说明:
-v:将宿主机数据目录挂载到容器内指定路径。
-e ICONIFY_API_DATA:告诉服务数据目录的位置。
-e ICONIFY_API_CACHE=memory:开启内存缓存,提高响应速度。
bash
curl http://localhost:3000/material-symbols/code-blocks-outline.json若返回该图标的 JSON 数据,说明服务部署成功。
只需修改 Iconify 的 API 请求地址,使其指向我们刚部署的本地服务。在项目 index.html 的 <head> 标签内添加以下脚本:
html
<script>
window.IconifyConfig = {
api: {
providers: [
{
provider: '',
url: 'http://你的内网服务器IP:3000'
}
]
}
};
</script>如果使用的是较新版本的 @iconify/vue,也可以在 main.ts 中通过编程方式设置:
ts
import { setAPIProvider } from '@iconify/vue';
setAPIProvider('', { resources: ['http://你的内网服务器IP:3000'] });完成配置后,重启前端项目,所有图标请求都会发送至本地 API,完全脱离外网依赖。
1. 为什么不用 unplugin-icons 编译时按需打包?unplugin-icons 非常适合图标名在代码中静态写死的场景。但本项目菜单图标完全由后端动态配置,编译时无法获知所有可能出现的图标名,因此必须走运行时按需加载方案。
2. 能否只复制用到的图标集而不是全部?
完全可以。只需要将你菜单中用到的那些前缀(如 material-symbols、solar 等)的 JSON 文件复制到数据目录即可。以后需要新图标集时再动态补充。
3. 内网环境多个前端项目可以共用这个 API 吗?
可以,只需在各自的前端配置中指向同一个 API 地址即可。
通过部署本地 Iconify API,我们完美解决了内网环境下动态菜单图标的离线使用问题,同时避免了全量 JSON 带来的性能灾难。整个过程只需一次简单的 Docker 部署和一行前端配置,后续所有图标均可动态使用,无需再为图标加载而烦恼。
如果你的项目也存在类似需求,不妨一试。