Bruno 本地开发与贡献实战指南:React + Electron 双进程桌面 API 客户端的构建、运行、测试与提交流程
【免费下载链接】brunoOpensource IDE For Exploring and Testing API's (lightweight alternative to Postman/Insomnia)项目地址: https://gitcode.com/GitHub_Trending/br/bruno
本指南以官方韩文贡献指南 docs/contributing/contributing_kr.md 为骨架,结合当前仓库的真实源码与配置编写。它面向想要为 Bruno 提交代码的开发者,系统讲解其技术栈与多包结构、Node 环境准备、依赖安装、本地双进程开发环境的搭建、构建产物与测试的执行方式,以及 Pull Request 的提交流程规范。读完本文,你将能在本地完整跑起一个可修改、可调试、可测试的 Bruno 开发环境。
说明:contributing_kr.md 是英文版 contributing.md 的韩文翻译(可在同一目录找到 docs/contributing/contributing_cn.md 等其他语言版本)。由于翻译版可能滞后于主仓库演进,本文在继承其全部要点的基础上,会以仓库当前源码为准进行校正与补充,标注“以仓库实际为准”的部分请读者特别留意。
一、项目定位与文档场景
Bruno 是一个开源的 API 客户端(官方定位为探索与测试 API 的 IDE,是 Postman/Insomnia 的轻量级替代品),它在桌面端通过 Electron 运行,同时把请求、集合等数据以文件形式保存在本地。
贡献指南所覆盖的“在本地把 Bruno 跑起来”这一过程,本质上就是一次对仓库整体架构的演练:
- 桌面应用 =React 渲染的前端+Electron 主进程/壳,二者是独立进程;
- 业务逻辑被拆分为多个 npm workspace 子包(如 schema、converters、requests 等),通过 monorepo 统一管理;
- 你可以在本地对任意一层(UI、请求引擎、Schema、语言解析器)做修改、测试与验证后再提交。
二、技术栈与多包架构解读
指南原文概述:Bruno 由 React 构建,并借助 Electron 提供支持本地集合的桌面版本。
这里需要按当前仓库实际情况做一处重要的版本校订:原文档声称前端基于 Next.js,但当前仓库的前端包 packages/bruno-app/package.json 已经改用 React 19 + rsbuild 作为构建与开发服务器(其dev脚本即rsbuild dev,根目录 scripts/dev.js 也只 spawn rsbuild 的 dev server)。React 负责界面渲染,Electron 版本锁定在~37.6.1(见 packages/bruno-electron/package.json)。
指南列出的核心库与其真实用途,结合仓库依赖(见 packages/bruno-app/package.json)可对照如下:
| 库 | 在 Bruno 中的职责 |
|---|---|
| Tailwind CSS | 全局样式与 UI 原子类方案 |
| Codemirror(+ codemirror-graphql) | 请求体、脚本等代码编辑器 |
| Redux / @reduxjs/toolkit | 应用状态管理 |
| Tabler Icons(@tabler/icons) | 图标库 |
| formik | 表单状态与校验逻辑组织 |
| Yup | 与 formik 配合的 Schema 校验 |
| axios | 网络请求客户端 |
| chokidar | 文件系统监听(集合目录变更 → 界面刷新) |
| i18next / react-i18next | 国际化(可作补充,见下文) |
补充:英文主文档还列出了 i18n 库 i18next,与仓库中实际使用的 react-i18next 一致;韩文文档未列出该项,此处一并补全。
多包结构方面,根目录 package.json 通过workspaces字段聚合了 16 个子包(packages/bruno-app、bruno-electron、bruno-cli、bruno-common、bruno-converters、bruno-schema、bruno-schema-types、bruno-query、bruno-js、bruno-lang、bruno-tests、bruno-toml、bruno-graphql-docs、bruno-requests、bruno-filestore、bruno-sqlite)。它们之间以@usebruno/*内部命名空间相互依赖,这是理解“为什么改动底层包后需要先构建”的关键。
三、环境与依赖准备
3.1 Node.js 版本:以 .nvmrc 为准
原文档要求 Node v18 与 npm 8,但以当前仓库为准,Node 22 才是目标版本:
- 仓库根目录存在 .nvmrc,内容为
v22.12.0; - 英文主文档 contributing.md 也更新为要求 Node v22.x 或最新 LTS;
- 热重载开发脚本 scripts/dev-hot-reload.js 启动时会读取
.nvmrc取出主版本号(v22),若当前process.version不匹配会直接报错退出,这正是“必须用 Node 22”的源码级约束。
因此推荐用 nvm 管理版本:
# 在仓库根目录执行,自动读取 .nvmrc 切换 v22 nvm use仓库使用 npm workspaces(monorepo),请使用 npm 而非 yarn/pnpm 执行下述命令。仓库还包含 .npmrc(内容为
min-release-age=10),用于约束依赖发布缓存的最小年龄。
3.2 安装依赖
npm i --legacy-peer-deps--legacy-peer-deps是官方推荐的必选项:由于 workspace 中各包对 peer 依赖的版本声明并不完全对齐(例如根目录 package.json 还通过overrides强制指定了axios、tar等依赖版本),跳过自动 peer 依赖解析可以避免安装中断。仓库把--legacy-peer-deps固化在scripts/setup.js与scripts/dev-hot-reload.js的重装逻辑中,印证了这一约定的必要性。
四、本地开发:双进程联动的完整流程
4.1 为什么要拆成两个终端
Bruno 是桌面应用:一个 React(rsbuild dev server)进程负责前端资源与热更新,一个 Electron 进程作为外壳加载该服务。因此原文档要求:
- 终端 1:先启动前端 dev server;
- 终端 2:再启动 Electron,由它加载终端 1 提供的页面。
在启动 Electron 前,还需要先把若干被引用的子包构建出来(详见 4.2),否则运行时会找不到@usebruno/*的产物。
4.2 先构建共享子包
原文档给出如下构建步骤,需按顺序执行:
# 构建 GraphQL 文档查看器(在请求面板中渲染 GraphQL schema 文档) npm run build:graphql-docs # 构建请求相关类型与运行时(生成代码等场景用到) npm run build:bruno-query # 构建公共工具与类型定义 npm run build:bruno-common # 构建转换器(Postman / Insomnia / OpenAPI 导入导出) npm run build:bruno-converters # 构建请求引擎 npm run build:bruno-requests以仓库为准的补充:上述命令与英文主文档一致,当前根目录 package.json 还提供了更多
build:*脚本(如build:bruno-filestore、build:bruno-sqlite、build:schema-types、build:bruno-common等)。此外,Electron 主进程启动时(见 packages/bruno-electron/src/index.js 顶部逻辑)会检查 JS 沙箱库是否已打包——若缺失会提示先执行:
# 打包 JS sandbox 运行时库(developer 模式下必备) npm run sandbox:bundle-libraries --workspace=packages/bruno-js也可以使用仓库内置的一键脚本npm run setup(对应 scripts/setup.js),它会自动完成清理 node_modules、重装依赖并构建所需包的全流程。
4.3 启动双进程
# 终端 1:启动 React dev server npm run dev:web # 终端 2:启动 Electron 应用 npm run dev:electron两者联动的底层机制可以在源码中看到:
- 前端包 packages/bruno-app/package.json 的
dev脚本执行rsbuild dev,默认监听 3000 端口; - Electron 主进程读取环境变量
BRUNO_DEV_PORT(缺省回退 3000),拼接出http://localhost:<port>后交给主窗口loadURL(见 packages/bruno-electron/src/index.js 中devPort相关逻辑); - 若想省去手动开两个终端的麻烦,可用根脚本
npm run dev(见 scripts/dev.js):它会 spawn rsbuild dev server,从输出文本中正则解析出实际端口(匹配Local: http://localhost:(\d+)),再把端口以BRUNO_DEV_PORT注入 Electron 进程。因此 rsbuild 端口即使变化,Electron 也能自动对准。
4.4 热重载模式(可选)
仓库还提供一套带文件监听的热重载方案npm run dev:watch(对应 scripts/dev-hot-reload.js)。它会用 concurrently 并行启动 common / converters / query / graphql-docs / requests / filestore 的 watch 构建、React dev server,并通过 nodemon 监听packages/**/dist/、packages/bruno-electron/src/等路径,在 Electron 相关代码变化时自动重启外壳。若希望“清理并重装后直接进入开发环境”,可执行:
npm run dev:watch -- --setup4.5 自定义 Electron userData 路径(以仓库为准的补充)
英文主文档中还有一条对调试非常实用的小技巧(韩文版未包含):当设置了环境变量ELECTRON_USER_DATA_PATH且处于开发模式时,Electron 会把userData目录重定向到指定位置。这一逻辑直接实现在 packages/bruno-electron/src/index.js 中:
# 在桌面上创建 bruno-test 目录作为 userData 使用 ELECTRON_USER_DATA_PATH=$(realpath ~/Desktop/bruno-test) npm run dev:electronuserData目录承载着本地数据库(如bruno.db)、cookie、临时文件与快照等状态(可参见 packages/bruno-electron/src/ipc/sqlite.js 等对app.getPath('userData')的引用),隔离它有助于在不污染正式数据的前提下反复验证功能。
五、常见问题排查(Troubleshooting)
原文档指出的典型问题是:执行npm install时遭遇Unsupported platform错误。这通常源于平台相关的可选依赖(典型如 Electron 相关二进制)与本机平台不匹配,或因历史安装残留导致 lockfile 与当前平台不一致。
官方推荐的修复方式是把node_modules与package-lock.json全部删除后重新安装:
# 删除仓库(含各 workspace 子目录)中的所有 node_modules find ./ -type d -name "node_modules" -print0 | while read -d $'\0' dir; do rm -rf "$dir" done # 删除所有子目录下的 package-lock.json find . -type f -name "package-lock.json" -delete执行完毕后回到 .nvmrc 指定的 Node 版本下重新运行:
npm i --legacy-peer-deps补充说明:仓库内建的 scripts/dev-hot-reload.js 在--setup模式下会自动完成“清理全部 node_modules → 重装依赖”,与上述手工流程等价,可作为备选。此外,scripts/setup.js 的清理逻辑特意保留了tests/scripting/additional-context-roots/fixtures下被当作测试夹具(而非构建产物)提交的node_modules,手工执行find删除时无需自行处理此类细节。
六、测试:单包测试与全量测试
6.1 运行指定包测试
# 运行 bruno-schema 包测试 npm test --workspace=packages/bruno-schema6.2 运行所有 workspace 测试
# 对所有声明了 test 脚本的 workspace 依次执行 npm test --workspaces --if-present--if-present表示仅对存在test脚本的包执行,避免因个别子包未配置测试而报错。Bruno 的单元测试体系以 Jest 为主,绝大多数包(如bruno-common、bruno-query、bruno-converters、bruno-app、bruno-lang、bruno-toml等)都带有各自的 jest.config.js 配置文件;其中bruno-electron的测试命令较为特殊,需要在 Node 的 ESM 实验模式下运行 Jest(见 packages/bruno-electron/package.json 的test脚本)。
以仓库为准的补充:仓库还提供了基于 Playwright 的端到端测试(根目录 package.json 的
test:e2e*脚本与 playwright.config.ts),覆盖 UI、认证、SSL、Mock Server 等场景,但这套 E2E 属于进阶验证手段,纯代码贡献以 6.1 / 6.2 的单元测试为主即可。
七、提交规范与 Pull Request 流程
原文档明确两条 PR 要求,这也是仓库贡献者协作的底线:
- 保持 PR 小而聚焦——一个 PR 只解决一件事,便于 Review 与回滚;
- 遵循分支命名规范:
feature/[feature name]:包含某个具体功能的改动,例如feature/dark-mode;bugfix/[bug name]:只包含针对某个 bug 的修复,例如bugfix/bug-1。
与提交流程相关的仓库事实还包括:
- 仓库配置了 Git hooks:
.husky/pre-commit会执行npx nano-staged,而根目录 package.json 的nano-staged配置规定:对改动涉及的*.{js,ts,jsx}文件先自动执行npm run lint:fix(底层是仓库根目录 eslint.config.js 定义的全量 ESLint 规则)。这意味着本地提交前会强制经过一轮代码风格与潜在错误检查,建议提交前先手动跑一遍:
npm run lint- 仓库在
.github下提供了PULL_REQUEST_TEMPLATE.md、ISSUE_TEMPLATE、CODEOWNERS等工作流配套文件,提交 PR 时应遵循模板填写说明; - 若准备深度参与,还可参阅仓库根目录的 CODING_STANDARDS.md(编码规范)与 governance.md(治理约定)。Bruno 以 MIT 协议开源(见 license.md)。
八、快速上手清单
从零到可调试环境的完整命令序列(以仓库当前实际为准):
# 1. 克隆仓库(若尚未获取源码) git clone https://gitcode.com/GitHub_Trending/br/bruno cd bruno # 2. 使用 .nvmrc 指定的 Node v22 nvm use # 3. 安装依赖(跳过 peer 依赖自动解析) npm i --legacy-peer-deps # 4. 构建被引用的子包 npm run build:graphql-docs npm run build:bruno-query npm run build:bruno-common npm run build:bruno-converters npm run build:bruno-requests npm run sandbox:bundle-libraries --workspace=packages/bruno-js # 5a. 终端 1:启动前端 npm run dev:web # 5b. 终端 2:启动 Electron npm run dev:electron # 6. 修改代码后验证(以 bruno-schema 为例) npm test --workspace=packages/bruno-schema # 7. 提 PR 前确保 lint 通过、分支名符合 feature/* 或 bugfix/* 规范 npm run lint整个过程的核心心智模型可以概括为三条:Node 22 + npm workspaces 是前提,共享子包要先构建、双进程要分别启动,改动哪一层就用--workspace=定向测试哪一层。掌握这些之后,无论是修复某个请求渲染 bug、新增认证方式,还是改进 GraphQL 文档面板,你都可以在一个可复现、可验证的本地环境中安全地进行代码贡献。
【免费下载链接】brunoOpensource IDE For Exploring and Testing API's (lightweight alternative to Postman/Insomnia)项目地址: https://gitcode.com/GitHub_Trending/br/bruno
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考