☰
danswer(Onyx)Web 前端开发指南:Next.js 本地开发、云端后端联调与 Playwright E2E 测试全解析
2026/10/11 20:25:34 网站建设 项目流程

danswer(Onyx)Web 前端开发指南:Next.js 本地开发、云端后端联调与 Playwright E2E 测试全解析

【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswer

本文以 web/README.md 为骨架,结合 Onyx(原 danswer)仓库中的实际源码与配置,系统讲解web/前端模块的本地开发环境搭建、如何用INTERNAL_URL与DEBUG_AUTH_COOKIE对接云端后端,以及基于 Playwright 的端到端测试体系。读完你既能在一分钟内启动本地开发服务器,也能配置一套安全的远程后端联调环境,并掌握本项目 Playwright 测试的组织规范与调试技巧。

一、web/前端模块概览

web/是 Onyx 项目的前端应用目录,基于Next.js 16.3.3与React 19.2.8构建,采用 App Router 架构,代码位于 web/src 下(app/、components/、lib/、sections/、views/等)。项目还通过 npm workspaces 托管了两个内部共享包(见 web/package.json):

  • @onyx-ai/opal(web/lib/opal):设计系统与 UI 组件库,负责侧边栏断点等视觉规范;
  • @onyx-ai/shared(web/lib/shared):前后端共享的类型与工具。

从依赖清单(web/package.json)可以看出该前端的业务广度:@radix-ui/*系列提供无障碍原语组件,react-markdown+rehype-*+remark-*负责聊天消息的 Markdown/数学公式渲染与消毒,recharts承担使用量统计图表,@sentry/nextjs负责错误监控,swr与zustand分别管理服务端数据缓存和客户端状态。

启动整个栈并非只有前端一件事:聊天、搜索、文档索引等能力全部由backend/(FastAPI)提供,前端默认代理到本地 8080 端口(详见下文"后端地址的解析链路")。

二、环境准备:安装 bun 与依赖

Onyx 前端使用 bun 作为包管理器与运行时(这也与仓库根目录、web/下分别存在bun.lock的事实一致)。首先安装 bun(详见官方安装文档),然后在web/目录下安装依赖:

cd web bun install

依赖安装的细节

  • 仓库通过 npm workspaces(workspaces: ["lib/opal", "lib/shared"])把内部包软链进node_modules,因此bun install会一并处理@onyx-ai/opal与@onyx-ai/shared两个本地包。
  • 切换分支后如果package.json发生变化,项目通过 pre-commit 钩子自动重装依赖(见根目录 CONTRIBUTING.md 中 Formatting and Linting 一节),通常无需手动干预。
  • Playwright 相关依赖(@playwright/test)同样在此步骤中就位,后续bunx playwright install才能解析到仓库锁定的版本。

三、启动开发服务器

安装完成后,在web/目录执行:

bun run dev

该命令对应 web/package.json 中的next dev,启动后:

  • 浏览器访问http://localhost:3000即可看到应用。
  • 如果 3000 端口访问异常(例如被占用或代理冲突),README 建议设置WEB_DOMAIN环境变量指向http://127.0.0.1:3000再访问:
WEB_DOMAIN=http://127.0.0.1:3000 bun run dev

后端地址的解析链路

前端默认假定本地后端运行在8080端口。这个默认值在源码中有三处体现:

  • web/src/lib/constants.ts:export const INTERNAL_URL = process.env.INTERNAL_URL || "http://localhost:8080";
  • web/src/lib/utilsSS.ts:服务端请求统一拼接为${INTERNAL_URL}${path};
  • web/next.config.js:rewrites()把/api/docs、/openapi.json等路径代理到INTERNAL_URL(未设置时同样回退到http://localhost:8080)。

因此,bun run dev配合本地backend/(FastAPI,8080)即可组成完整可用的开发环境。理解这条链路是下一步对接云端后端的基础。

四、连接云端后端:.env.local与INTERNAL_URL

日常开发中你可能不想本地起一整套后端(含数据库、向量库等),而是让前端直连远程的后端环境(如 staging 或 production)。此时需要在web/目录下(与package.json同级)创建.env.local文件:

# 让本地开发服务器指向云端后端 INTERNAL_URL=https://st-dev.onyx.app/api # 用于对远程后端做认证的调试 Cookie # 开发模式下该 Cookie 会被自动注入到 API 请求中 # 获取方式: # 1. 打开 https://st-dev.onyx.app(或你的目标后端地址)并登录 # 2. 打开 DevTools(F12)→ Application → Cookies → [你的后端域名] # 3. 找到名为 "fastapiusersauth" 的 Cookie,复制其值 # 4. 粘贴到下面(不要加引号) # 注意:该 Cookie 会过期,需要定期刷新 DEBUG_AUTH_COOKIE=你的cookie值

关键行为与注意事项

  • 配置文件位置:.env.local必须放在web/目录(与package.json同级),不要放在仓库根目录。
  • 修改后必须重启:创建或修改.env.local后,需要重启开发服务器(bun run dev)才能生效。
  • DEBUG_AUTH_COOKIE仅开发模式生效:只有NODE_ENV=development时才被注入,生产构建完全不受影响。
  • 未设置INTERNAL_URL时:前端回退到本地后端http://127.0.0.1:8080(见上文源码)。
  • 不会覆盖已有 Cookie:默认情况下该机制不会覆盖已存在的同名认证 Cookie,如果你之前登录过,可能需要先清除localhost域下的 Cookie。
  • 安全红线:.env.local中存放的是有效会话凭证,务必保持机密,绝不能提交进版本控制(该文件已列入.gitignore)。

注入机制的源码实现

DEBUG_AUTH_COOKIE的注入逻辑位于 web/src/lib/users/svcSS.ts 的processCookies()函数:

  1. 收集当前请求携带的所有 Cookie,拼成name=value; name=value字符串;
  2. 当process.env.DEBUG_AUTH_COOKIE && process.env.NODE_ENV === "development"时,检查字符串中是否已存在认证 Cookie(Cookie 名由SERVER_SIDE_ONLY__AUTH_COOKIE_NAME决定);
  3. 若不存在,则把DEBUG_AUTH_COOKIE以fastapiusersauth=<value>的形式追加进请求头。

Cookie 名称默认是fastapiusersauth(FastAPI-Users 标准名称),定义于 web/src/lib/constants.ts,并且可通过AUTH_COOKIE_NAME环境变量覆盖——这样在 localhost 不同端口并行开多个 worktree 时,各前端实例可以维护彼此独立的认证 Cookie,避免串号。getCurrentUserSS()(同一文件 web/src/lib/users/svcSS.ts)通过调用后端/me接口完成服务端会话校验,注入后的 Cookie 会随该请求一并发送。

五、Playwright E2E 测试:从入门到调试

5.1 警告:测试会重置应用状态

在web/下执行测试会把应用重置为干净状态(注册测试账号、清理/重建测试数据),如果你不希望动当前数据,就不要在本地随意运行整套测试。

5.2 安装 Playwright 浏览器

先确保已执行过bun install(这样bunx会解析到node_modules中仓库锁定的 Playwright 版本,而不是临时拉取最新版),然后安装浏览器:

bun install bunx playwright install

5.3 运行测试

playwright脚本在 web/package.json 中展开为playwright test:

bun run playwright

只跑单个测试文件:

bun run playwright landing-page.spec.ts

本地调试时可以加交互式参数,直观看到每一步在浏览器中的执行情况:

bun run playwright --ui # UI 模式,可视化管理与单步调试 bun run playwright --headed # 有头模式,弹出浏览器窗口

5.4 测试结果与截图输出

web/playwright.config.ts 将输出目录配置为:

web/output/playwright/

测试运行过程中会自动截图并保存到web/output/screenshots/。跨 CI 运行对比截图可使用 ODS 工具:

ods screenshot-diff compare --project admin

该命令属于仓库内 ODS(Onyx Developer Suite)工具集,详见 tools/ods/README.md 的 screenshot-diff 章节。

5.5 Playwright 配置要点

从 web/playwright.config.ts 可以看到本项目测试基础设施的关键设定:

配置项取值说明
单测超时100 秒timeout: 100000
断言超时15 秒降低断言抖动(expect.timeout: 15000)
截图容差maxDiffPixelRatio: 0.01、threshold: 0.2容忍抗锯齿/亚像素渲染差异
CI 重试2 次本地 0 次(retries: process.env.CI ? 2 : 0)
CI 并发4 个 worker本地默认并发(可注释切换为串行workers: 1便于调试)
测试范围tests/e2e/*.spec.ts用testMatch与 Jest 测试隔离
失败追踪trace: "retain-on-failure"失败时保留 Trace 供回放
基准地址BASE_URL环境变量覆盖,默认http://localhost:3000对应use.baseURL

项目还定义了三个测试项目(project):

  • admin:默认全量测试(grepInvert排除@exclusive、@lite标记),桌面 Chrome、1280×720 视口,复用admin_auth.json登录态;
  • exclusive:仅跑带@exclusive标记的用例,串行、单 worker,适合独立慢速场景;
  • lite:针对 Onyx Lite 栈(DISABLE_VECTOR_DB=true,无 Vespa/Redis)的用例,仅跑带@lite标记的测试。

5.6 Global Setup:测试前的自动准备

测试不是裸奔的。globalSetup(web/tests/e2e/global-setup.ts)会在测试套件运行前自动完成:

  1. 健康检查:轮询BASE_URL直到返回 200(最长 60 秒,每 2 秒一次,15 秒后开始告警)。若超时会抛出明确错误并提示先用ods compose dev启动前后端;
  2. 注册测试账号:通过 APIPOST /api/auth/register幂等注册管理员(admin_user@example.com)、二号管理员(admin2_user@example.com)和 8 个 worker 用户(worker0..7@example.com,凭证定义见 web/tests/e2e/constants.ts)。第一个注册的用户自动成为管理员;
  3. API 登录并保存登录态:用 Playwright 的轻量 request context 调POST /api/auth/login,把 Cookie 保存为admin_auth.json、admin2_auth.json、workerN_auth.json等 storage state 文件——比真实浏览器登录更快、更安静;
  4. 消除新手引导干扰:通过PATCH /api/user/personalization设置显示名称,关掉首次登录时"Onyx 该怎么称呼你?"的弹窗,避免它遮挡聊天界面导致测试误判;
  5. 提升权限:把二号管理员加入默认 Admin 用户组(/api/manage/admin/user-group+add-users);
  6. 准备公共 LLM Provider:复用 admin 会话确保存在默认的公开 LLM Provider(许多测试——文件上传、Agent 创建等——都依赖默认 LLM 已配置)。

从 web/tests/e2e 的目录结构可以看到测试覆盖范围:admin/(管理后台、安全加固、Token 限流、SCIM、OAuth 等)、agents/、auth/、chat/、connectors/、craft/、mcp/、onboarding/、settings/等,基本对应前端全部功能面。

六、E2E 测试编写规范(给测试作者)

仓库为 e2e 测试制定了明确的硬性规则,见 web/tests/e2e/README.md,核心两条:

6.1 强制使用 Page Object Model

所有定位器与交互逻辑必须封装在 Page Object 类中(放在tests/e2e/pages/,一个类一个文件,按界面命名如ChatPage、InputBar),复合页面用嵌套对象暴露方法(chatPage.inputBar.someMethod()),spec 只调用方法、绝不直接构造定位器:

// ✅ 正确 —— spec 调用 POM 方法 await chatPage.goto(); await chatPage.inputBar.type("hello"); await chatPage.inputBar.send(); await chatPage.expectHumanMessage("hello"); // ❌ 错误 —— spec 内写裸定位器 await page.goto("/app"); await page.locator('[contenteditable="true"]').fill("hello"); await page.keyboard.press("Enter"); await expect(page.locator(".message")).toContainText("hello");

定位器优先级从高到低:data-testid/aria-label(getByTestId、getByLabel)→ 角色(getByRole)→ 文本/标签(getByText、getByLabel)→ CSS 选择器(最后手段)。

6.2 断言必须用自动重试的 matcher

Playwright 的expect(locator).*会轮询重试直到断言通过或超时;而locator.getAttribute()、page.evaluate()只读取一次 DOM 快照,在 React 异步更新场景下极易产生抖动(flaky)测试:

断言对象应使用不应使用
属性expect(locator).toHaveAttribute(name, value)getAttribute()后expect(...)
classtoHaveClass(/regex/)/.not.toHaveClass(...)page.evaluate手写判断
文本toHaveText(value)/toContainText(value)textContent()后expect(...)
数量toHaveCount(n)count()后expect(...)
可见性toBeVisible()/toBeHidden()手写isVisible()判断
值toHaveValue(value)inputValue()后expect(...)

getAttribute/evaluate等一次性读取仍可用于 spec 内部的控制流分支(例如按读取值决定后续动作),只是不能作为对异步状态的断言基础。这些规则连同更宏观的 Onyx 测试分层策略(单元 / 外部依赖单元 / 集成 / E2E),在 backend/AGENTS.md 与 backend/tests/README.md 中有更完整的说明。

七、生产构建与常用脚本速查

开发之外,web/package.json 还提供了完整的工程化脚本:

命令作用
bun run dev启动开发服务器(next dev)
bun run dev:profile开启NEXT_PUBLIC_ENABLE_STATS=true的带统计开发模式
bun run dev:clean清理.next缓存后启动开发服务器
bun run build生产构建(next build)
bun run build:fast跳过类型检查的快速构建(SKIP_TYPE_CHECK=1)
bun run start启动生产服务器(next start)
bun run lint/lint:fix基于 oxlint 的代码检查与自动修复
bun run types:checkNext 类型生成 + TypeScript 严格类型检查(tsconfig.types.json)
bun run format/format:check基于 oxfmt 的格式化与校验
bun run test系列Jest 单元测试(含 watch、coverage、CI 模式)
bun run playwrightPlaywright E2E 测试
bun run storybook组件文档(Storybook,6006 端口)

值得注意的是 web/next.config.js 中的几处工程化决策:output: "standalone"支持独立部署镜像;turbopack.root显式固定到web/以避免仓库根目录多 lockfile 干扰;React Compiler 在next build时开启、next dev时关闭(可用ENABLE_REACT_COMPILER=1强制开启)——这些配置共同支撑了前端在开发、CI、生产三条链路上的稳定性。

八、总结

围绕 web/README.md,本篇梳理了 Onyx 前端开发的完整闭环:

  1. 本地开发:bun install+bun run dev,默认对接本地 8080 后端(源码回退逻辑见 web/src/lib/constants.ts);
  2. 远程联调:通过web/.env.local中的INTERNAL_URL指向云端后端、DEBUG_AUTH_COOKIE注入fastapiusersauth会话(注入实现见 web/src/lib/users/svcSS.ts),并牢记 Cookie 会过期、需定期刷新且严禁入库;
  3. 质量保障:Playwright E2E 测试体系(web/playwright.config.ts)配备 global-setup 自动造数、storage state 复用登录态、POM 分层与自动重试断言规范(web/tests/e2e/README.md),配合--ui/--headed调试和 ODS 截图对比工具,构成从开发到 CI 的完整质量闭环。

掌握了这三层,你就可以在 Onyx 仓库中高效地进行前端开发、后端联调与回归测试,无论面向本地全栈环境还是云端后端。

【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswer

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询