Prometheus Web UI 开发指南:目录结构、构建流程与二进制资产集成机制
本文围绕 web/ui 目录文档 展开,系统讲解 Prometheus 新版(mantine-ui)与旧版(react-app)两套 React Web UI 的目录组织、npm/pnpm 工作区依赖安装、Vite 开发服务器与 API 代理、测试与生产构建,以及静态资源如何通过 Go embed 打包进 Prometheus 二进制、或从文件系统与预构建包提供的三种集成方式。读完你可以独立完成 UI 本地开发联调,也能复现完整的二进制资产编译链路。
UI 仓库整体结构:两套 React 应用加共享模块
web/ui 目录同时承载新旧两代 Prometheus Web 界面,其子目录分工如下:
| 目录 | 职责 |
|---|---|
mantine-ui/ |
新版(3.x)基于 React + Mantine 的 Web UI,由 Prometheus 默认提供 |
react-app/ |
旧版(2.x)React Web UI,可通过功能标志回退使用 |
module/ |
共享 npm 模块,基于 CodeMirror 实现 PromQL 代码编辑,供两个 React 应用及外部项目复用 |
static/ |
两个 React 应用的构建输出目录,默认被编译进 Prometheus 二进制 |
从 web/ui/package.json 可以看到,根工作区名为 prometheus-io(私有 monorepo 包),其 workspaces 声明为 mantine-ui 与 module/*;web/ui/pnpm-workspace.yaml 同样只把这两个路径纳入工作区。这印证了 README 中说明的关键设计:旧版 UI 所在的 react-app 因依赖与新工作区不兼容,被刻意分离在工作区之外,因此需要单独安装依赖。当前 module/ 下实际包含 module/codemirror-promql 与 module/lezer-promql 两个 PromQL 编辑器相关包。
此外,Prometheus 默认提供新版 UI;如需临时切回旧版界面,可以启动服务器时添加功能标志 --enable-feature=old-ui。
根目录还提供了构建辅助文件:web/ui/build_ui.sh(被根 package.json 的 build、build:mantine-ui、build:module 脚本调用)、web/ui/embed.go.tmpl(生成内置资产 Go 文件的模板),以及下文会讲到的资产开关文件 web/ui/assets_embed.go 与 web/ui/ui.go。
构建前置条件与依赖安装
构建任一 React 应用需要:
- npm >= v10
- node >= v22
(Makefile 中的 check-node-version 目标会在 assets 构建链中先校验 Node 版本。)
在仓库根目录执行:
make ui-build
该目标会先在 web/ui 工作区目录与 web/ui/react-app 目录分别安装 npm 包依赖,然后在两个目录中各执行一次生产构建,确保两个应用及其依赖都能正确编译。npm 依据各目录下的 package.json 与锁文件解析依赖,并生成 node_modules 目录。
对照 Makefile 的实际实现:
.PHONY: ui-install
ui-install:
cd $(UI_PATH) && pnpm install
cd $(UI_PATH)/react-app && pnpm install
.PHONY: ui-build
ui-build:
ifeq ($(BUILD_UI),mantine)
cd $(UI_PATH) && CI="" pnpm run build:mantine-ui
else
cd $(UI_PATH) && CI="" pnpm run build
endif
可以看出当前仓库的 Makefile 目标实际使用 pnpm(工作区文件 pnpm-workspace.yaml 与其配套),且支持 BUILD_UI=mantine 只构建新版 UI 的变体。需要注意 web/ui/README.md 中反复强调的约束:不要直接在 mantine-ui 或 module 的任一子目录里执行依赖安装命令——这些包的依赖只能通过 web/ui 工作区统一安装,否则会破坏工作区的一致性。
启动本地开发服务器
在 web/ui 下执行(根 package.json 中 start 脚本实际执行 pnpm --filter @prometheus-io/mantine-ui run start):
npm start
开发服务器将运行在 http://localhost:5173/,源码修改后页面热重载,lint 错误也会输出到控制台。若要开发旧版 UI,则需进入 react-app 子目录执行同样的命令。
一个重要限制:热重载只对 mantine-ui 和 react-app 目录内的代码生效。由于 module 目录中的 CodeMirror PromQL 编辑器代码是作为构建产物被引用的,修改后需要先在 web/ui 下执行:
npm run build:module
对应 Makefile 中的 ui-build-module 目标(pnpm run build:module,底层调用 bash build_ui.sh --build-module)。
通过 Vite 代理将 API 请求转发到 Prometheus 后端
Web UI 本身无数据,必须连接一个 Prometheus 后端。新版 UI 的 web/ui/mantine-ui/vite.config.ts 中配置了 Vite 开发服务器代理,将 /api 与 /-/ 前缀的请求转发到 http://localhost:9090:
[浏览器] ----> [localhost:5173 (dev server)] --(代理 API 请求)--> [localhost:9090 (Prometheus)]
这样可以在运行一个正常的 Prometheus 服务端处理 API 请求的同时,独立迭代 UI 代码。如需指向其他后端,修改 vite.config.ts 中的 target 即可。连接 HTTPS 服务器时必须额外设置 changeOrigin: true,例如:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
base: '',
plugins: [react()],
server: {
proxy: {
"/api": {
target: "https://prometheus.demo.prometheus.io/",
changeOrigin: true,
},
"/-/": {
target: "https://prometheus.demo.prometheus.io/",
changeOrigin: true,
},
},
},
});
从同一配置文件中还能看到一个与合规性相关的细节:生产构建通过 rollup-plugin-license 把第三方包的许可证收集到 dist/assets/third-party-licenses.txt 并随 Prometheus 一起分发,以满足各依赖包的署名要求。
运行测试
对新版 React 应用及所有模块运行测试(根 package.json 中 test 脚本为 pnpm -r run test,递归执行各工作区包的测试):
npm test
旧版 UI 的测试需在 react-app 子目录执行同样命令;若只想测某个模块,进入该模块目录再执行 npm test。
默认情况下测试以交互式 watch 模式运行,任何源文件变更都会触发重跑;要只运行一次并退出,设置 CI=true:
CI=true npm test
Makefile 的 ui-test 目标即采用此模式:先依赖 ui-build-module(保证模块为最新构建产物),然后在工作区与 react-app 中分别以 CI=true 执行 pnpm run test。
生产构建:npm run build 与 Makefile 构建链
在 web/ui 下执行:
npm run build
会将两个版本的生产优化构建输出到 static/react-app 与 static/mantine-ui 目录(底层调用 bash build_ui.sh --all)。通常不需要手动执行这一步——完整二进制构建时由根 Makefile 的 build 目标统一处理。从 Makefile 可以看到完整的资产构建链:
.PHONY: assets
ifndef SKIP_UI_BUILD
assets: check-node-version ui-install ui-build
else
assets:
@echo '>> skipping assets build, pre-built assets provided'
endif
.PHONY: assets-compress
assets-compress: assets
@echo '>> compressing assets'
scripts/compress_assets.sh
.PHONY: assets-tarball
assets-tarball: assets
@echo '>> packaging assets'
scripts/package_assets.sh
即:校验 Node 版本 → 安装依赖 → 构建 UI → 用 scripts/compress_assets.sh 压缩资产 → 用 scripts/package_assets.sh 打包发布用的资产 tarball。这也解释了发布物 prometheus-web-ui-<version>.tar.gz 的来源。
升级 npm 依赖
由于是包含多个 npm 包的 monorepo,升级依赖需要逐个包处理(module 各子包、react-app、mantine-ui)。完成版本升级后,只在 web/ui 与 web/ui/react-app 两个目录执行依赖安装,不要在其他子包目录执行(工作区机制下会产生错误结果)。Makefile 还提供 update-npm-deps(升级 minor)与 upgrade-npm-deps(升级到 latest)两个目标,底层调用 scripts/npm-deps.sh,可用作批量升级的起点。
资产如何进入二进制:builtinassets 构建标签的双文件开关
README 指出,默认构建时压缩后的 Web 资产通过 Go 的 embed 包静态编译进二进制。这一机制在源码中由一对互斥的构建标签文件实现:
- web/ui/assets_embed.go:带
//go:build builtinassets标签,声明var Assets = http.FS(assets.New(EmbedFS)),即把压缩后的EmbedFS暴露为http.FileSystem(EmbedFS由 web/ui/embed.go.tmpl 模板在构建时生成,内含//go:embed指令)。 - web/ui/ui.go:带
//go:build !builtinassets标签,从当前工作目录解析出web/ui(运行于仓库根)、./ui(运行 web 测试)或./(生成静态资产)三种前缀,然后用http.Dir+ 过滤器挂载文件系统上的static目录,并过滤掉 sourcemap 与遗留的 bootstrap 资源文件。
因此在默认(带 builtinassets 标签)构建下,资产完全内置;去掉该标签后,服务器改为直接从 web/ui/static 目录读取文件,无需重编译 Go 代码。
从文件系统提供 UI 资产
开发期如果希望服务器始终从本地文件系统(web/ui/static 构建输出目录)提供资产、免去每次重新编译 Go 二进制,操作是:
- 在
.promu.yml的flags条目中移除builtinassets构建标签; - 执行
make build(或直接go build ./cmd/prometheus)。
文档同时提醒:多数情况下直接用 npm start 开发服务器更方便,因为文件方式仍需先通过 make ui-build(或 npm run build)重建资产后才可被提供。
使用预构建 UI 资产跳过前端构建
如果你只负责 Go 后端开发,不想处理 npm 依赖与前端构建耗时,可以使用每次 Prometheus 发布附带的预构建资产包 prometheus-web-ui-<version>.tar.gz:
# 1. 解压预构建资产到 web/ui
tar -xvf prometheus-web-ui-<version>.tar.gz -C web/ui
# 2. 通过 Make 变量指向预构建目录进行构建
make PREBUILT_ASSETS_STATIC_DIR=web/ui/static build
该参数会直接把预构建 UI 文件编译进二进制,完全无需安装 npm 或从源码构建前端。这一机制在 Makefile 中有直接对应:
# Only build UI if PREBUILT_ASSETS_STATIC_DIR is not set
ifdef PREBUILT_ASSETS_STATIC_DIR
SKIP_UI_BUILD = true
endif
一旦设置该变量,assets 目标即打印 “skipping assets build, pre-built assets provided” 并跳过 ui-install/ui-build,从而把整个前端构建环节从二进制构建流程中移除。
小结
Prometheus 的 Web UI 采用“新旧双应用 + 共享 PromQL 编辑器模块 + 统一工作区”的布局,通过 react-app 独立工作区规避依赖冲突;开发链路(依赖安装、Vite 代理、热重载、watch 测试)与发布链路(生产构建、压缩、tarball 打包、embed 内嵌或预构建资产注入)在 Makefile 中被组织为 ui-install → ui-build → assets → assets-compress 的可组合目标。理解 builtinassets 构建标签切换的 assets_embed.go 与 ui.go 两个文件,是把握 UI 资产从源码到二进制这一完整路径的关键。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00