首页
/ 构建与定制 one-api 的 air 前端主题:从 npm 构建到 Go 二进制内嵌

构建与定制 one-api 的 air 前端主题:从 npm 构建到 Go 二进制内嵌

2026-09-05 20:37:53作者:霍妲思

web/air 是 one-api 内置的第三套前端主题(React 应用)。本文基于 air 主题说明文档 展开,覆盖本地开发、生产构建、REACT_APP_SERVER 环境变量配置等文档中的全部实操内容,并结合 package.jsonmain.gorouter/web.go 等源码,讲清 air 主题的构建产物如何被 Go 后端以 embed 方式打进单一可执行文件,帮助你在本地独立调试前端、理解主题机制并参与主题定制。

air 主题在 one-api 中的定位

one-api 的前端采用"多主题"组织方式:web 目录下的每个文件夹都是一套独立的前端主题,web/README.md 明确说明"每个文件夹代表一个主题,欢迎提交你的主题",并指出 defaultberryair 等主题由不同开发者维护。从 common/config/config.go 可以确认主题的注册机制:

var Theme = env.String("THEME", "default")
var ValidThemes = map[string]bool{
	"default": true,
	"berry":   true,
	"air":     true,
}
  • THEME 环境变量控制启动时选用哪套主题,默认为 default
  • ValidThemes 是合法主题白名单,air 已注册其中;
  • 启动时 main.go 会打印 using theme %s 日志,便于确认当前生效主题。

air 主题本身是一个 React 应用,README 将其定位为 "React Template",说明它脱胎于一套可复用的 React 模板工程。

本地开发:npm start

文档中的 Basic Usages 给出的第一条命令是在 web/air 目录下运行开发服务:

# Runs the app in the development mode
npm start

npm start 对应 package.json 中的 "start": "react-scripts start",即标准的 Create React App 开发服务器,支持热更新。

package.json 的依赖清单可以看出该主题的技术栈:

依赖 版本 用途
react / react-dom ^18.2.0 UI 框架
react-scripts 5.0.1 CRA 构建体系
@douyinfe/semi-ui / semi-icons ^2.46.1 主 UI 组件库(布局、表格等)
@visactor/react-vchart ~1.8.8 统计图表(用量、收益统计页)
axios ^0.27.2 HTTP 客户端
react-router-dom / history ^6.3.0 / ^5.3.0 前端路由与浏览器 history 管理
react-toastify ^9.0.8 消息提示
react-turnstile ^1.0.5 Cloudflare Turnstile 人机验证

应用入口 src/index.js 中通过 initVChartSemiTheme 初始化图表主题,并用 SiderBarHeaderBar 组装整体布局;src/App.js 通过 react-router-domRoutes 挂载 Channel、Token、User、Log、Setting、TopUp 等页面,并对 Home、About 等页面做了 lazy 懒加载拆分。

关于开发模式下的请求代理:package.json 末尾声明了 "proxy": "http://localhost:3000"。结合 CRA 的 proxy 字段语义可以推断,开发时前端将 API 请求转发到本地 3000 端口的 one-api 后端实例,从而在不修改后端的情况下完成前后端联调。

生产构建与 REACT_APP_SERVER

文档中的第二条命令用于生产构建:

# Builds the app for production to the `build` folder
npm run build

注意 package.json 中的实际构建脚本比文档示例多一步产物归位:

"build": "react-scripts build && mv -f build ../build/air"

react-scripts buildweb/air/build 产出静态文件后,将其强制移动到仓库根的 web/build/air 目录。这是 one-api 多主题共存的约定:所有主题的构建产物统一汇聚到 web/build/<主题名>/ 下(web/README.md 也要求新主题的 build 命令指向 ../build/<主题名>)。

通过 REACT_APP_SERVER 指定后端地址

文档 强调的关键配置是构建前设置 REACT_APP_SERVER 环境变量:

# 例如
REACT_APP_SERVER=http://your.domain.com npm run build

该变量在 src/helpers/api.js 中被消费:

export const API = axios.create({
  baseURL: process.env.REACT_APP_SERVER ? process.env.REACT_APP_SERVER : '',
});
  • 构建时设置了 REACT_APP_SERVER:所有请求的 baseURL 指向该地址,适合前后端分离部署(前端托管在独立域名/CDN,API 在后端域名);
  • 未设置时 baseURL 为空字符串,即默认同源请求,适合前端静态资源与 API 同域(one-api 单二进制内嵌前端的典型部署形态)。

由于 CRA 只在构建期把 process.env.REACT_APP_* 静态替换进产物,该变量必须在 npm run build 之前生效,运行时修改无效。此外 api.js 还通过 axios 响应拦截器统一调用 showError 处理接口错误弹窗。

代码风格约定:Prettier 与 Actions on Save

文档 要求在开始编辑前,确认编辑器的 Actions on Save 开启了 Optimize importsRun Prettier。这一点与 package.json 中的 Prettier 配置相呼应:

"prettier": {
  "singleQuote": true,
  "jsxSingleQuote": true
}

即项目统一使用单引号(JSX 同样单引号),devDependencies 中锁定 prettier 2.8.8。遵循该约定可避免提交大量格式抖动,保持与现有代码风格一致;Actions on Save 中的 Optimize imports 则配合 App.js 这类存在大量按需导入的入口文件,防止无用 import 累积。

构建产物如何进入 Go 后端

air 主题的产物之所以能随 one-api 单二进制分发,源于 Go 的 embed 机制,整条链路如下:

  1. main.go 声明 //go:embed web/build/*,将 web/build 下所有主题产物编译进二进制;
  2. 启动时执行 router.SetRouter(server, buildFS),把内嵌文件系统交给路由层;
  3. router/web.go 按当前主题读取首页并挂载静态资源:
func SetWebRouter(router *gin.Engine, buildFS embed.FS) {
	indexPageData, _ := buildFS.ReadFile(fmt.Sprintf("web/build/%s/index.html", config.Theme))
	// ...
	router.Use(static.Serve("/", common.EmbedFolder(buildFS, fmt.Sprintf("web/build/%s", config.Theme))))
}

也就是说,设置 THEME=air 启动 one-api 后,路由只暴露 web/build/air/ 下的内容作为站点首页与静态资源。而 common/embed-file-system.go 中的 EmbedFolder 通过 fs.Sub 截取子目录并实现 Exists 判断,目的是让 gin-contrib/static 支持 SPA 的 fallback 路由(未命中的路径回落到 index.html,由前端路由接管)。

这也解释了构建脚本必须把产物移动到 web/build/air:只有落位于该目录,go:embed web/build/* 才会在编译 Go 程序时把 air 主题一并打包。

参考与延伸阅读

文档的 Reference 部分 列出了 air 主题(模板)所借鉴的两个开源参考工程:

  1. OIerDb——一个基于 React 的管理后台项目,air 的整体页面结构与数据管理交互可追溯至该模板;
  2. 一个 React Hooks + Redux 的注册/登录示例工程,对应本主题 src/context/Usersrc/context/Status 等 Context 状态管理思路。

如需了解主题整体规范或贡献新主题(包括修改 build 命令、注册 ValidThemes、同步 web/THEMES 文件),请参阅 web/README.md;air 主题的进一步开发说明可参考 web/berry/README.md 的通用约定。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.79 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
988
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384