Iconify在纯内网环境下的处理方式,不使用docker自建
1. 背景与问题
项目管理后台基于 soybean-admin-element-plus,图标主要使用 Iconify 编码,原有 @iconify/vue 使用按需加载模式。页面只保存图标名称,浏览器首次渲染时再向 Iconify API 请求 SVG 数据。该模式在互联网环境下使用方便,但在纯内网部署时会产生以下问题:
- 浏览器无法访问公网 Iconify 服务,菜单、按钮图标显示为空。
- 图标加载失败会增加页面请求超时、控制台报错和首屏等待时间。
- 依赖外部图标服务不符合生产静态资源随应用交付、网络边界可控的内网部署要求。
- docker自建方式运维复杂,系统离线部署太多不可控因素。
因此,本项目需要将通用图标改为“构建时提取、随前端产物发布、运行时只读本地集合”的离线模式。
2. 目标与非目标
2.1 建设目标
- 生产环境浏览器不请求 Iconify 公网 API、CDN 或其他外部图标服务。
- 保持已有
mdi:*、ph:*、carbon:*、ant-design:*图标编码,避免数据库大规模迁移。 - 动态菜单、门户应用、权限路由等场景可以继续通过编码渲染图标。
- 图标随前端
dist一起交付,前端服务器只需托管静态文件即可。 - 图标清单可审查、可复现、可在构建阶段发现错误图标编码。
- 对未知图标提供本地占位显示,不因异常编码触发网络回退。
2.2 非目标
- 不在运行时建设或维护通用 Iconify 内网服务。
3. 方案选型
| 方案 | 运行时是否联网 | 交付复杂度 | 图标扩展方式 | 评估结论 |
|---|---|---|---|---|
| 构建时内置受控图标集 | 否 | 低 | 更新清单后重新构建 | 采用 |
| 自建内网 Iconify API | 仅访问内网服务 | 中高 | 服务端更新图标包 | 仅适合有独立图标服务运维能力的场景 |
| 全部改为本地 SVG 文件 | 否 | 中 | 新增 SVG 和名称映射 | 可作为业务专用图标补充 |
| 自建图标字体 | 否 | 中 | 维护字体和编码表 | 不采用,调试和可访问性较弱 |
| 浏览器缓存 / Service Worker | 不可靠 | 中 | 依赖历史访问结果 | 不采用,不能作为内网保障 |
3.1 采用构建时内置的原因
项目已有以下基础条件:
package.json已锁定@iconify/json,可以在构建阶段读取标准 Iconify JSON 图标集。@iconify/vue提供offline入口,支持注册本地集合后渲染,不启用 API 加载器。- Vite 已统一负责生产前端构建,可以在构建阶段生成虚拟模块。
src/assets/svg-icon已有本地 SVG 精灵机制,可继续承载项目自有图标和占位图标。
该方案不增加生产服务器、不增加数据库表、不增加运行时网络依赖,并且保留现有 Iconify 名称,改造边界最小。
4. 总体架构
┌──────────────────────┐
│ @iconify/json │ 已锁定的开源图标包
└──────────┬───────────┘
│ 构建阶段读取
▼
┌──────────────────────┐
│ offline-iconify Vite │ 按受控清单提取图标
│ plugin │ 生成 virtual:offline-iconify
└──────────┬───────────┘
│ 打包进 JS
▼
┌──────────────────────┐
│ @iconify/vue/offline │ 注册本地集合
└──────────┬───────────┘
│ 运行时按名称查找
▼
┌──────────────────────┐
│ SvgIcon │ 动态菜单、门户、按钮图标
└──────────────────────┘
静态组件图标(例如 <icon-mdi-drag />)由 unplugin-icons 在构建期直接编译为本地 SVG,同样不需要运行时访问网络。运行时请求边界如下:
| 资源类型 | 来源 | 是否允许外部请求 |
|---|---|---|
| 通用 Iconify 图标 | 前端 JS 内置集合 | 否 |
src/assets/svg-icon 自有 SVG | 前端静态资源 / SVG symbol | 否 |
| 门户应用上传图标 | 同域 /media | 仅允许同域受控资源 |
| 门户 Logo、背景图 | 同域 /media | 仅允许同域受控资源 |
5. 详细设计
5.1 受控图标清单
清单位于:
web-admin/src/constants/iconify.ts清单包含源码静态引用、菜单种子、门户默认图标和已知历史数据中使用的 Iconify 名称,覆盖主要的 mdi、phosphor、carbon 和 ant-design 图标集。
清单设计原则:
- 只纳入项目实际使用或经过审核允许配置的图标。
- 使用完整的
prefix:name编码,避免不同图标集同名冲突。 - 清单变更必须随前端版本提交并重新构建。
- 清单不从数据库或外部接口动态扩展,避免运行时资源不可预测。
- 发现历史别名或下线图标时,优先添加显式本地回退映射,而不是恢复公网请求。
当前已对历史 ph:chart-line-bars 做本地回退,将其映射到可用的 ph:chart-line。该回退只影响图标显示,不修改数据库中的历史菜单值。
5.2 Vite 构建插件
实现文件:
web-admin/build/plugins/offline-iconify.ts构建插件执行以下步骤:
- 读取
offlineIconifyNames。 - 按前缀分组,例如
mdi、ph、carbon。 - 从
@iconify/json/json/{prefix}.json读取完整图标集。 - 仅复制清单中的
icons数据,保留必要的宽高信息。 - 生成
virtual:offline-iconify虚拟模块。 - 由 Vite 将虚拟模块内容打入前端产物。
若清单中的图标在已锁定图标包中不存在,构建插件直接抛出错误,使问题在构建阶段暴露,而不是部署后才发现页面空白。
5.3 运行时注册
实现文件:
web-admin/src/plugins/iconify.ts应用启动时从虚拟模块读取图标集合,并调用 addCollection 注册到 @iconify/vue/offline 的本地存储。该入口不包含 Iconify API 加载器,因此图标未命中时不会向公网发起请求。
5.4 统一图标渲染组件
实现文件:
web-admin/src/components/custom/svg-icon.vue渲染优先级:
- 传入
localIcon时,使用已有 SVG symbol 精灵。 - 传入受控 Iconify 编码时,从本地 Iconify 集合渲染。
- 传入历史回退编码时,先转换为本地可用编码再渲染。
- 传入未知编码时,使用
no-icon本地占位图标。
该组件不拼接外部 URL,也不根据图标名称生成 <img src="https://...">。
5.5 静态组件图标
项目中通过 unplugin-icons 使用的组件图标,例如:
<icon-mdi-drag />
<icon-ant-design-reload-outlined />由构建工具在编译阶段转换为本地 SVG。此类图标不经过运行时 SvgIcon 网络加载流程,也不依赖公网 API。
5.6 动态配置图标
以下数据仍然可以保存 Iconify 编码:
sys_menu.icon- 门户应用的
icon_key
前端展示时统一经过 SvgIcon 的本地集合解析。管理端选择器只展示受控图标清单;历史数据库中暂不在清单内的编码显示占位图标,避免页面因脏数据触发外部请求。
门户应用的 FILE 图标类型仍使用现有同域上传文件能力,适用于彩色业务 Logo 或业务专用图片,不与通用 Iconify 图标混用。
6. 资源体积与性能
6.1 只打包受控图标
不直接把完整 MDI、Phosphor 或 Material Symbols 图标库打入浏览器,而是在构建阶段裁剪为项目清单。因此:
- 首屏不需要逐个请求图标。
- 浏览器不产生图标 API 请求。
- 图标数据随主 JS 或代码分片由静态服务器一次提供。
- 新增图标的体积影响可以在构建产物中直接审查。
6.2 缓存策略
生产环境建议继续使用现有 Vite 文件名哈希和 Nginx 静态缓存策略:
- 带哈希的 JS、CSS、SVG 文件可设置较长缓存时间。
index.html使用较短缓存或按现有发布策略处理。- 图标变更随前端版本发布,不能只替换服务器上的某个图标文件而不更新 JS 产物。
7. 方案优缺点
7.1 优点
- 完全适配纯内网和隔离网络。
- 不新增生产服务和运维端口。
- 保留现有图标编码和数据库结构,迁移成本低。
- 构建期校验,问题比运行时网络失败更早暴露。
- 图标来源、版本和许可证可追踪。
- 未知图标有确定的本地降级行为。
7.2 限制
- 新增图标需要修改清单并重新构建前端。
- 动态配置不能任意使用完整 Iconify 社区图标库。
- 受控清单过大时会增加前端包体积,需要定期清理未使用图标。
- 图标包升级可能带来名称、路径或 SVG 内容变化,需要重新执行构建验证。
8. 后续优化建议
- 在 CI 中增加“源码/菜单种子图标编码覆盖率”和“产物公网地址扫描”两个门禁。
- 定期从数据库导出有效菜单与门户图标编码,与前端清单做差异检查。
- 对菜单管理和门户管理增加服务端受控编码校验,减少新的未知图标进入数据库。
- 将图标清单和开源许可证信息纳入版本发布物料。
- 对业务专用彩色图标优先使用同域上传文件或本地 SVG,不扩张通用 Iconify 清单。
9. 结论
本方案将 Iconify 从“运行时远程资源”调整为“构建时受控静态资源”,满足纯内网部署对网络隔离、可重复构建和静态交付的要求。现有菜单和门户图标编码可以继续使用,前端通过本地集合、历史回退和占位图标保证渲染稳定性;部署侧无需增加图标服务,后续维护简单,比跑docker更方便,当然也有其短处,如果都是大型项目,自建docker服务应该更好,如果只是单机构的小型项目,本方案较好。
评论
0成为第一个留下想法的人。