ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Onyx(Danswer)Web 前端工程规范全解:Opal 设计系统、组件分层、i18n 与测试实践

Onyx(Danswer)Web 前端工程规范全解:Opal 设计系统、组件分层、i18n 与测试实践 OnyxDanswerWeb 前端工程规范全解Opal 设计系统、组件分层、i18n 与测试实践【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswerOnyx前身 Danswer是一个开源的 Gen-AI 与企业搜索平台其 Web 前端基于 Next.js 16、React 19 与 TypeScript 构建。本文以仓库 web/AGENTS.md 为骨架系统讲解 Onyx 前端团队沉淀的工程规范组件从哪来、如何选型、为什么禁用dark:修饰符与内置 Tailwind 色、next-intl 国际化如何约束硬编码字符串以及 Jest 组件测试与 Playwright E2E 测试的硬性规则。读完本文你将掌握一套可复制的企业级 React 前端开发约定并能直接在 Onyx 仓库中对照源码验证每一条规则。一、规范文档的定位与前端仓库结构web/AGENTS.md是 Onyx 前端web/与desktop/后者是 Tauri 壳的宪法式标准文件。它在仓库根目录的 AGENTS.md 中被显式引用根文档将仓库拆分为backend/FastAPI Celery、web/Next.js 前端、mobile/React Native Expo三个子项目并说明各子项目必须先读自己的 AGENTS.md 再动手。与web/直接相关的前端目录结构如下web/lib/opal/opal/*设计系统包组件、布局、图标、核心原语是组件的第一来源web/lib/shared/onyx-ai/shared跨平台共享包是设计令牌tokens的唯一真源web/src/refresh-components/尚未沉淀进 Opal 的生产组件web/src/sections/ 与 web/src/layouts/业务特性组合与页面布局web/src/components/遗留目录正在被删除规范明令禁止再从这里导入。规范还强调了一个工程约定每一个 Opal 组件与布局旁边都有一份README.md使用前先读 README而不是去猜 props。这与 web/lib/opal/src/components/README.md 中新增组件必须附带架构、props 与用法示例文档的要求相互印证形成组件即文档的文化。二、组件来源优先级从设计系统到业务组合web/AGENTS.md给出了明确的组件来源优先级链这是整个前端规范的地基web/lib/opal/src/opal/*设计系统第一选择web/src/refresh-components/尚未进入 Opal 的生产组件web/src/sections/特性组合实体卡片在sections/cards/与web/src/layouts/。唯一的例外严禁从web/src/components/导入任何东西除了一处——web/src/components/icons/icons.tsx 中的createLogoIcon。也就是说遗留组件库只剩这一个函数有免死金牌。具体 UI 场景的选型表规范针对常见 UI 场景给出了近乎点菜式的选型场景组件来源管理页/设置页框架SettingsLayouts.{Root,Header,Body}opal/layouts图标标题描述含空状态、错误页Content/ContentAction/IllustrationContentopal/layouts按钮Button禁止裸buttonopal/components输入框Opal 或 refresh-components禁止裸input、textarea、select—文本Text配合font、colorprops禁止裸露文本节点refresh-components/texts/Text的布尔 flag API 已废弃opal/components图标仅opal/icons禁止lucide-react、react-icons—悬停显示Hoverable必须手写时补no-hover:opacity-100以兼容触屏opal/core交互原语Interactive、Disabled仅用于构建组件应用代码不得直接使用opal/core图标缺失时的标准流程是用 Figma MCP 工具从 Figma 导入图标添加到lib/opal/src/icons/即 web/lib/opal/src/icons/。这与 web/lib/opal/src/components/README.md 描述的组件生态一致——Opal 是一个内部自维护的设计系统所有 UI 资产从设计源直接进入代码库。三、有理由的规则每条约束背后的原理web/AGENTS.md特意将这一节命名为 Rules with a reason——每条规则都附带技术理由理解原理后执行起来才不会机械。1. 禁止dark:Tailwind 修饰符Nodark:Tailwind modifier.令牌本身已定义了两套主题覆盖写法会破坏暗色模式。仅createLogoIcon可用。从源码看设计令牌确实承载了双主题能力web/lib/shared/tokens/ 下同时存在semantic-light.json与semantic-dark.json构建后通过 web/lib/shared/README.md 中描述的.dark类在运行时切换。组件只消费令牌变量主题翻转由令牌层完成若在业务代码里写dark:bg-...就会在令牌之外另起炉灶造成覆盖失效与样式漂移。2. 禁止内置 Tailwind 颜色不要写bg-gray-100、text-blue-600改用令牌类text-0X、background-neutral-0X、background-tint-0X、border-0X、action-selection-0X、action-danger-0X、status-{info,success,warning,error}-0X、theme-*。令牌定义在 web/lib/shared/tokens/primitives.json、semantic-light.json、semantic-dark.json、shadow.json、size.json、typography.json、typography-presets.json。语义色引用原色例如{alpha-grey-100-90}构建后生成var(--alpha-grey-100-90)从而在暗色模式下整体翻转。业务代码只与语义层text-0X、status-*等打交道颜色语义与具体色值解耦——这是企业级设计令牌体系的标准做法。3. 文本 props 接受 Markdown任何渲染为可见文本的 proptitle、description、label都要类型化为string | RichStr来自opal/types并用Text渲染调用方通过opal/utils的markdown()显式开启解析。纯字符串永不解析。这个设计很精妙默认情况下文案就是普通字符串不会被 Markdown 引擎误解析只有显式调用markdown()的调用点才具备富文本能力避免了字符串里出现*就被渲染成斜体之类的隐式陷阱。4. Size props 默认值为md当 prop 类型是opal/types的SizeVariants或其子集时缺省值必须为md。这保证了不同组件在未指定尺寸时表现一致避免了这个组件默认小、那个组件默认大的割裂体验。5. 优先 padding而非 margin使用组件的paddingprop而不是在外面包一层div若库组件没有该 prop应给组件本身补上而不是增加 wrapper。这条规则的动机很实际wrapperdiv会把 DOM 层级越包越深影响样式隔离与可访问性把内边距收进组件则保持了结构扁平、API 自洽。6. 数据获取模式useSWRuseSWR客户端内、在真正需要数据的组件内部使用pending 时显示 loader。禁止在页面顶部统一拉取再向下传。数据靠近消费方是 SWR 的核心理念——每个组件自己声明依赖缓存与失效由 SWR 全局管理同时避免了 prop drilling 层层透传。这与 Onyx 前端大量使用 React Query/SWR 生态的现状一致。四、代码风格让代码库看起来像一个人写的web/AGENTS.md的 Style 一节定义了机械但可自动化的风格约束绝对导入/指向src/opal/指向 Opal禁止../相对路径组件用函数声明function Foo() {}不用箭头函数props 接口FooProps与组件同文件共享类型放进同目录types.tsinterfaces.ts是旧名碰到就改名类名拼接用cn来自opal/utils禁止模板字符串拼接Hooks 分层特性 hooks 放web/src/lib/feature/hooks.ts不感知业务状态的 UI hooks 进 Opalweb/src/hooks/是最后兜底。这些规则与根目录 AGENTS.md 中保持严格类型Python 与 TypeScript 都要注释要简短且聚焦长期有效信息的全局要求一脉相承。cn工具函数的具体实现可查看opal/utilsweb/lib/opal/src/utils.ts。五、国际化next-intl把文案关进笼子里国际化是 Onyx 前端规范中约束最严的领域之一核心诉求是源码里不允许出现裸的用户可见字符串。1. 禁止硬编码字符串客户端用useTranslations(namespace)服务端用await getTranslations(...)oxlint 规则i18n/no-raw-jsx-text会直接让裸文案构建失败。2. 单一事实源与键的稳定性web/src/i18n/messages/en.json 是唯一事实源。新增或修改键时必须把最佳翻译同步到该目录下的其他所有语言文件仓库实际包含ar、de、en、es、fr、ja、ko、pt、zh共 9 个 locale见 web/src/i18n/messages/。缺键或多键都会让types:check失败——键对齐是编译期检查由 web/src/i18n/messages/keyParity.ts 实现。键是稳定标识符命名规范为namespace.section.element.role的 camelCase例如settings.appearance.colorMode.title。改写英文文案不改变键——键只描述文案在 UI 中的位置与角色与具体措辞解耦。3. ICU 形状必须一致每个 locale 的消息不仅要能通过 ICU 解析还必须与英文源使用完全相同的 ICU 占位符。这个约束由 web/src/i18n/tests/catalog.test.ts 守护——该测试用formatjs/icu-messageformat-parser逐条解析所有 locale 的消息检查占位符集合是否与英文源一致。也就是说跨语言的占位符漂移比如中文少了{count}会在 CI 中被拦截。4. 日期、数字与排版方向日期与数字一律用useFormatter和useLocale禁止硬编码en-US新样式使用逻辑属性ms-、pe-、start-而非物理属性ml-、pr-、left-为 RTL 语言如阿拉伯语留好余地。六、测试从 Jest 组件测试到 Playwright E2Eweb/AGENTS.md只给测试划了三条边界细节交给两个 README1. 组件测试Jest React Testing Library完整指南在 web/tests/README.md核心要点测试与源码同目录存放co-located必须用setupUser()而非userEvent.setup()——前者自动包裹 React 的act()消除 Not wrapped in act() 告警查询选择器优先级Role 查询getByRole Label Placeholder Text禁止getByTestId、类名、元素类型等脆弱的反模式异步断言用findBy*或waitFor禁止在状态更新后立即getBy*Mock 遵循最小化原则只 mock 外部依赖fetch、Next.js router不 mock 应用代码测试命名描述用户行为user can create new prompt不描述实现细节。2. E2E 测试Playwright硬性规则见 web/tests/e2e/README.md强制 Page Object ModelPOM一个 UI 表面一个 Page Object 类如ChatPage、InputBar存放在tests/e2e/pages/spec 只调用 POM 方法绝不内联 locatorLocator 优先级data-testid/aria-label Role Text/Label CSS 选择器最后手段只用自动重试断言expect(locator).toHaveAttribute(...)、toHaveClass(...)、toHaveText(...)、toHaveCount(...)、toBeVisible()等会重试到超时禁止用getAttribute/page.evaluate/textContent/count的单次快照读来做异步状态断言否则必然 flaky。3. 运行命令规范明确指出 E2E 的启动方式cd web bun run playwright TEST_NAME且不要用bunx或npx——它们可能拉取未固定版本的 Playwright。这一要求在 web/package.json 中可验证playwright: playwright test直接调用仓库本地固定版本playwright/test: ^1.39.0test: jest则用于组件测试。更多脚本types:check、lint、format、storybook等同样可以在该文件的scripts段找到。七、规范如何与仓库其他文档协同web/AGENTS.md并非孤立的孤岛它与仓库文档体系形成闭环根目录 AGENTS.md 定义全局工程环境uv 虚拟环境、测试密钥解析、Postgres 连接、Playwright 登录账号admin_userexample.com/TestPassword123!等web/lib/shared/README.md 说明设计令牌的唯一真源、构建命令bun run build:tokens与跨平台消费方式web 用 CSS 变量、mobile 用 NativeWindweb/lib/opal/src/components/README.md 说明 Opal 组件如何基于opal/core的Interactive原语构建以及新增组件的六步流程kebab-case 目录 →styles.css→components.tsx→ 导入样式 → README → barrel 导出backend/AGENTS.md根文档中提及承载全局测试策略的完整描述。因此可以把web/AGENTS.md理解为一棵树的主干而各目录下的 README 是向四周伸展的枝干——先读主干定方向再读枝干补细节。结语Onyx 前端的这套规范回答了三个根本问题组件从哪里来设计系统优先、遗留代码隔离、为什么这样写令牌体系、双主题、i18n、可访问性背后的原理、如何保证质量编译期键检查、ICU 一致性测试、POM 化 E2E 与自动重试断言。对于正在建设内部设计系统或重构大型 React 前端的团队这份规范本身就是一份可借鉴的工程蓝本——组件分层、令牌驱动主题、文案键与措辞解耦、测试定位分层这些思路可以原样迁移到任何 Next.js 项目中。要在真实代码里验证这些约定可直接从 web/lib/opal/src/components/、web/src/refresh-components/ 与 web/src/i18n/messages/ 入手研读。【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表