自建 Iconfy API 服务:解决国内访问不稳定问题

Iconify 是一套面向开发人员和设计师的图标工具生态,它以统一的方式整合了200 多个开源图标集超过 27.5 万个图标,是前端开发中极为常用的开源图标库。

但 Iconify 官方 API 服务部署在国外,国内访问时经常出现网络波动、加载缓慢甚至失败的情况。为了保证项目中图标使用的稳定性,我选择自建 Iconify API 服务,以此获得更流畅的开发和使用体验。

先明确:你的项目是如何使用 Iconify 的?

自建 Iconify API 服务仅对「通过网络请求引入图标」的场景有效;如果你的项目是通过「npm 包方式引入 Iconify 图标」,本身就不需要额外部署服务,也无需自建 API。

npm 包方式引入(无需自建 API)

这种方式是将图标集以 npm 包的形式安装到项目中,比如我之前写的《iconfy 配置自动引入 Vue3+Vite3》一文,就是通过自动导入 @iconify-json/<图标集名称> 包来实现图标使用的。

优点: 实现了按需引入,即不是一次性引入所有的图标

缺点:

每次添加新的图标集项目的 package.json 文件中都会新增对应的 @iconify-json/* 依赖,但一个图标集可能只引入了一个图标。

且个人开发过程中,图标样式往往没法一步确定,经常需要反复替换、调整。这种情况下,先前安装的图标集 npm 包就会变成冗余依赖。诚然这其实不影响项目打包 ------Vite 或 Webpack 这类构建工具,本身会自动分析依赖树,只打包项目中实际用到的图标代码,不会因为安装了多余的图标集包就显著增加打包体积。

(不过本人有点 "代码洁癖",看着 package.json 里躺着一堆用不上的 @iconify-json/* 依赖就觉得不舒服,这纯属是无伤大雅的个人习惯~)

这种方式的特征也是缺点每次添加新的图标集,项目的 package.json 文件中都会新增对应的 @iconify-json/* 依赖。

网络请求方式引入(适合自建 API)

如果不想通过 npm 安装图标包,也可以使用 Iconify 官方提供的对应语言组件,通过网络请求动态加载图标。这里以 Vue 项目为例,基础使用代码如下:

vue 复制代码
<template>
  <!-- 使用图标,name 格式为「图标集前缀:图标名称」,比如 mdi:home -->
  <Icon :icon="name" />
</template>

<script setup>
// 导入 Iconify 的 Vue 组件
import { Icon } from '@iconify/vue'
const props = defineProps({
  name: { // 定义要使用的图标名称
    type: String,
    required: true,
  },
})
</script>

Iconify 的核心构成

Iconify 并非单一工具,而是由多个核心开源库协同构成的生态。先理清这些库的关系,才能更好理解自建 API 服务的本质:

图标源:icon-sets

仓库地址:https://github.com/iconify/icon-sets

这是 Iconify 所有图标的数据源,它以 JSON 格式汇集了 200+ 开源图标集的内容,并且会定时自动更新。这些图标并非直接照搬原图标库,而是经过了专门处理:

  • 通过 Iconify Tools(Iconify 官方的图标处理工具库)筛选和优化,剔除了脚本、事件监听器、字体、光栅图像等冗余内容。
  • 图标中的单色填充色被替换为 currentColor,你可以通过修改文本颜色直接更改图标颜色,适配性更强。
  • 图标代码被压缩优化,最大限度减小文件体积。

前端展示层:iconify

仓库地址:https://github.com/iconify/iconify

这是 Iconify 的前端核心框架,提供了各类前端框架(Vue/React/Angular 等)的图标组件,也就是在项目中用来展示图标的界面层。

后端服务层:Iconify API

仓库地址:https://github.com/iconify/api

这是为前端提供图标数据的后台服务,也是本次自建部署的核心对象 。前端组件会通过请求 API 来获取 icon-sets 中的图标数据。

构建 Iconfy API 服务

官方原本在 Docker Hub 提供了 Iconify API 的镜像(地址:iconify/api),理论上可以直接拉取镜像部署。但实际测试发现,国内 Docker Hub 镜像源并没有这个docker,国内无法直接拉取这个官方镜像 ,会出现超时错误(timeout error

因此,笔者选择通过 Iconify API 的 GitHub 仓库代码自行打包构建 Docker 镜像 ,再进行容器化部署,接下将会介绍本次部署遇到的各种问题,即对应的解决方法,笔者采用的系统是Ubuntu 24.04.3 LTS

前序准备

首先需要去 GitHub 克隆Iconify API代码,然后将代码压缩包上传到云端,在云端压缩,解压完成进入对应的目录,需要关注的文件是docker.shDockerfile

bash 复制代码
sftp username@server_ip # 建立sftp连接
put  api-main.zip api-main.zip # 上传文件 put [上传文件路径][远端路径]
apt install -y unzip # 下载解压工具
unzip api-main.zip  # 解压到当前目录
cd ./api-main

修改对应文件

由于官方给的 Dockerfile 是适配大公司的 CI 环境 / 公司内网镜像,因此构建镜像过程出现了很多问题,下面是需要修改的东西:

dockerfile 复制代码
# 注释掉这三行
RUN cp /etc/apt/sources.list /etc/apt/sources.list.original
RUN ([ -s /tmp/sources.list.tmp ] && mv -f /tmp/sources.list.tmp /etc/apt/sources.list && cat /etc/apt/sources.list) || (cat /etc/apt/sources.list)
COPY tmp/build-ca-cert.crt /usr/local/share/ca-certificates/build-ca-cert.crt
# 删除
# Restore the original sources.list
    ([ -s /etc/apt/sources.list.original ] && mv /etc/apt/sources.list.original /etc/apt/sources.list) && \
    # Remove the temporary build CA cert
    rm -f /usr/local/share/ca-certificates/build-ca-cert.crt

如果你不想修改,可以通过ls -l 去判断自己系统内是否具有/etc/apt/sources.list & tmp/build-ca-cert.crt 这两个文件,即使存在,也需要判断大小是否为 0,为 0 也不行。

dockerfile 复制代码
# 加速 apt
# 新增 阿里云 Debian Bullseye 源
RUN sed -i 's|deb.debian.org|mirrors.aliyun.com|g' /etc/apt/sources.list && \
    sed -i 's|security.debian.org|mirrors.aliyun.com/debian-security|g' /etc/apt/sources.list
    
# 修改 RUN set -ex 行命令
# rm -rf /tmp/* && \ 替换为 
rm -rf /var/lib/apt/lists/*

构建镜像

在修改对应文件后,在当前目录下执行:sh ./docker.sh 这里也可以不加 sh 如果没有报 -bash: ./docker.sh: Permission denied错误的话。

bash 复制代码
# 检查镜像
docker image ls
# 出现下面两个镜像即构建成功
iconify/api            3.2.0 
iconify/api            latest

部署镜像

笔者是通过docker compose进行部署的,如果不想采用这个方案,可以将我下面提供的docker-compose.yml进行转化为对应的docker run命令

yaml 复制代码
# docker-compose.yml
version: '3.9'
services:
  iconify-api:
    image: iconify/api:latest
    container_name: iconify-api
    restart: always  # 容器故障自动重启
    ports:
      - "3000:3000"   # 映射端口(宿主机:容器内)
    environment:
      # - ICONIFY_SOURCE=none  # 禁用官方图标源
      - HOST=0.0.0.0
      - PORT=3000
      # 性能优化:禁用不需要的功能(根据需求调整)
      # - ENABLE_ICON_LISTS=false  # 仅提供图标数据,不提供列表接口
      # - ENABLE_SEARCH_ENGINE=false  # 禁用搜索功能(节省内存)
      - NODE_ENV=production  # 生产环境标识
    volumes:
      # 挂载自定义图标集目录(本地图标集放在宿主机 ./icons 目录)
      - /home/iconify/custom-icons:/data/iconify-api/icons:ro  # ro=只读,防止容器内误修改
      # 挂载缓存目录(持久化图标缓存,避免重启后重新加载)
      - /home/iconify/iconify-cache:/data/iconify-api/cache
    logging:
      driver: "json-file"
      options:
        max-size: "5m"    # 单个日志文件最大10MB
        max-file: "3"      # 最多保留3个日志文件
bash 复制代码
# 没有docker compose 可以通过下面命令下载
apt install -y docker-compose-plugin # 验证 docker compose version
# 部署命令
docker compose up -d # 出现 Container iconify-api  Started 即部署成功
# 验证
docker ps # 查看对应的docker有没有运行
docker logs iconify-api # 查看运行日志是否报错
# 记得开启ufw端口
# 外部请求
curl http://<ip>:3000/material-symbols.json?icons=database-search-outline

前端切换请求源

还是以 Vue为例子,只需要在main.ts(Vue 挂载的入口文件)中添加如下代码:

js 复制代码
// 采用自定义iconfy API 服务器地址
import { addAPIProvider } from '@iconify/vue'
addAPIProvider('', {
  resources: ['http:xxx:3000' || 'https://api.iconify.design'],
})

''指代默认请求地址,除此外还可以指定con集请求源地址,详细内容请看文档https://iconify.design/docs/api/providers.html

扩展源码讲解

这个部分,笔者将简要讲解一下 iconify-api代码的扩展使用。

  • api/icons/ 目录:存放自定义图标集(IconifyJSON 格式,可参考 icon-set 仓库内的 json 目录下的 json 文件)。
  • src/config/icon-sets.ts:配置图标集来源(决定是否加载自定义图标)。

图标集加载流程: src/config/icon-sets.tsgetImporters 函数定义图标来源,优先加载 icons/ 目录的自定义图标。若 ICONIFY_SOURCE=none,则仅加载 icons/ 目录下的图标集。

看过代码发现,其实在 API 的代码里并没有直接存放图标集 ,而是在服务启动时或更新时从指定源下载并本地存储 (缓存数据默认存储在容器内/data/iconify-api/cache下面),之后所有请求都从本地服务获取,无需依赖外部链接。(详见src/config/importers/该目录下对应不同ICONIFY_SOURCE配置有不同的加载方式,默认是full)

相关推荐
AAA阿giao3 小时前
从零开始学 React:用搭积木的方式构建你的第一个网页!
前端·javascript·学习·react.js·前端框架·vite·jsx
遇到困难睡大觉哈哈3 小时前
Harmony OS Web 组件:如何在新窗口中打开网页(实战分享)
前端·华为·harmonyos
你脸上有BUG3 小时前
【工程化】前端打包时间优化
前端
TeleostNaCl3 小时前
Google Chrome 浏览器历史记录的存储位置
前端·chrome·经验分享
技术小李...3 小时前
docker下mysql更改密码后WordPress提示无法连接数据库问题
运维·docker·容器
大模型教程3 小时前
前端可以转型AI工程师吗?那可太能了...
前端·llm·agent
转转技术团队3 小时前
前端开发应该了解的浏览器背后的黑科技
前端
2503_928411563 小时前
12.15 element-plus的一些组件(上)
前端·vue.js
JS_GGbond4 小时前
JavaScript原型链:一份会“遗传”的家族传家宝
前端·javascript