大森的博客

内网环境下动态菜单图标的终极离线方案:部署本地 Iconify API

2026/06/21
2
0

背景

项目中使用了 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 一键启动。

部署步骤

1. 拉取 Iconify 官方 API 镜像

bash

docker pull iconify/api

2. 准备图标数据目录

在宿主机创建一个目录用于存放图标集 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 会动态读取)。

3. 启动容器

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:开启内存缓存,提高响应速度。

4. 验证服务

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,完全脱离外网依赖。

效果对比

指标

全量 JSON 注册(旧方案)

本地 API 服务(新方案)

开发环境启动速度

明显变慢(加载 90MB+ JSON)

几乎无影响

生产环境打包体积

巨大(整个图标集被打入包)

不增加打包体积

网络请求

无网络请求但内存爆炸

本地请求,每个图标仅几 KB

动态扩展图标

需要重新构建

只需在服务器目录中添加 JSON 文件

维护复杂度

需手动管理图标注册

零代码侵入

常见问题

1. 为什么不用 unplugin-icons 编译时按需打包?
unplugin-icons 非常适合图标名在代码中静态写死的场景。但本项目菜单图标完全由后端动态配置,编译时无法获知所有可能出现的图标名,因此必须走运行时按需加载方案。

2. 能否只复制用到的图标集而不是全部?
完全可以。只需要将你菜单中用到的那些前缀(如 material-symbolssolar 等)的 JSON 文件复制到数据目录即可。以后需要新图标集时再动态补充。

3. 内网环境多个前端项目可以共用这个 API 吗?
可以,只需在各自的前端配置中指向同一个 API 地址即可。

总结

通过部署本地 Iconify API,我们完美解决了内网环境下动态菜单图标的离线使用问题,同时避免了全量 JSON 带来的性能灾难。整个过程只需一次简单的 Docker 部署和一行前端配置,后续所有图标均可动态使用,无需再为图标加载而烦恼。

如果你的项目也存在类似需求,不妨一试。