拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Omi Frontend:h.omi.me 公开分享页与商店前端的技术架构与 Cloud Run 部署指南

Omi Frontendh.omi.me 公开分享页与商店前端的技术架构与 Cloud Run 部署指南【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend本文基于 FriendOmi开源仓库中 web/frontend/README.md 展开系统讲解frontend这一 Next.js 公开 Web 服务的定位、技术栈、本地开发、CI 检查与 Cloud Run 部署全链路并结合 next.config.mjs、Dockerfile、gcp_frontend.yml 与 public-build-contract.json 等仓库源码给出源码级佐证。读完本文你将掌握如何在本仓库中运行、测试、构建并部署 Omi 公开前端理解其与登录态 Web 客户端web/app的边界以及/conversations与/memories双 URL 空间的实现机制。一、项目定位公开分享页与商店门户web/frontend是一个基于 Next.js App Router 构建的公开 Web 应用生产环境以 Cloud Run 服务frontend部署在 https://h.omi.me。它承载两类核心页面公开分享页/chat/:id、/conversations/:id用于向外部访客展示 Omi 用户分享的对话与记忆内容公开商店门户应用市场/apps、开发者入口/create-app、年度回顾/wrapped、以及/unlimited等页面。README 特别强调了一个关键边界web/frontend不是登录态 Web 客户端签名用户使用的 Web 客户端位于web/app对应 app.omi.me。两者在仓库中分属独立的 Next.js 工程拥有各自的 Dockerfile 与部署工作流web/app走 gcp_app.ymlfrontend走 gcp_frontend.yml。理解这一分工是后续阅读部署配置的前提。二、技术栈与目录结构按 README 与 package.json 的依赖清单该工程的技术栈为层次选型仓库证据框架Next.jsApp Router当前锁定~16.2.11package.json语言/样式TypeScript、Tailwind CSStailwind.config.ts、globals.cssUI 组件Radix UI / shadcn 风格组件accordion、dialog、progress、scroll-area 等package.json、src/components/ui数据服务Firebaseauth/Firestore、Algolia搜索、Redis缓存package.json包管理器npmpackage-lock.jsonpackage.json源码主体位于web/frontend/src可按职责划分为几块src/app/App Router 路由包括memories/[id]分享页、chat/[token]、apps、create-app、wrapped、unlimited、tasks/[token]等页面src/actions/Server Actions 层如memories/get-shared-memory.ts、chat/get-shared-chat.ts、apps/submit-app.ts、trends/get-trends.tssrc/components/业务组件memories/、plugins/、trends/与通用 UI 组件ui/src/lib/纯函数工具URL 拼接、Markdown 转纯文本、Firebase 初始化与 API 客户端src/__tests__/基于 Node 内置node --test的测试用例。值得注意的一点是仓库根目录同时存在web/admin管理后台、web/app登录态客户端、web/personas-open-source等多个独立前端工程web-checks.yml 会通过detect-changes按变更路径精确选择需要执行的 lint/test/build 任务避免无关工程互相阻塞。三、本地开发三行命令启动README 给出的开发流程非常简洁直接继承如下npm ci cp .env.template .env.local # fill in values npm run dev # http://localhost:3000三点实操提示结合源码必须用npm ci而非npm install包管理器固定为 npm且 Dockerfile 与 CI 均使用 lockfile 冻结依赖本地保持一致可避免依赖漂移。npm run dev实际执行next dev --turbo见 package.json启用 Turbopack 加速开发迭代。环境变量以 .env.template 为准其中API_URL默认指向http://127.0.0.1:8787本地后端服务WEB_URL默认http://localhost:3000。src/constants/envConfig.ts会在运行时读取这些值其中WEB_URL还会经过shareBaseUrl()归一化处理见下文第六节。工程提供的全部 npm scripts 如下来自 package.jsonScript命令说明devnext dev --turbo开发服务器Turbopackbuildnext build生产构建输出 standalonestartnext start启动生产服务器testnode --test src/__tests__/*.test.mjs运行 Node 原生测试linteslint ./src ...ESLint 静态检查lint:fixeslint ./src ... --fix自动修复lint:formatprettier ... --writePrettier 格式化四、测试与 CIlint test build 三道关卡README 指出测试采用node --test测试用例位于src/__tests__。从 src/tests目录可见测试覆盖了相当多的关键契约例如share-base-url.test.mjs断言shareBaseUrl()对WEB_URL的解析与回退逻辑shared-api-url.test.mjs断言sharedApiUrl()对动态路由参数的 URL 编码shared-conversation-chat-contract.test.mjs、wrapped-unlimited-deeplink-parity.test.mjs验证前后端分享链路与深链的一致性。之所以把share-base-url.mjs、shared-api-url.mjs实现为纯 JS 模块源码注释写得很明确“Kept as plain JS so node:test can assert without a TS loader”share-base-url.mjs这是为降低测试运行成本而做的刻意设计。CI 侧有两份工作流与本工程相关web-checks.ymlpush 到main或 PR 到main时触发先由detect-changes判断是否有has_frontend变更随后在frontend-lint任务中执行npm ci npm run lint npm run lint:format -- --check bash scripts/run-web-frontend-tests.shNode 版本固定为 20npm 缓存指向web/frontend/package-lock.json。gcp_frontend.yml负责真正的生产部署详见下一节。五、生产构建与 Cloud Run 部署5.1 部署触发条件与目标环境按 gcp_frontend.yml部署由两类事件触发push 事件分支为main或development且变更路径命中web/frontend/**、config/public-build-*.json、.github/actions/deploy-public-build/**、.github/scripts/preflight_public_build_*.py、.github/scripts/smoke_public_build_browser.py等workflow_dispatch支持手动指定environment可选值仅development、prod与可选的release_version。环境映射规则为development分支 →development环境main分支 →prod环境。README 明确说明该服务只有development和prod两档环境不存在 staging tier也没有 docker-compose 配置。concurrency组按环境隔离部署队列且cancel-in-progress: false避免新一次 push 中断正在进行的滚动发布。5.2 构建契约public-build-contract.json部署动作由 .github/actions/deploy-public-build 复合 Action 执行其参数化配置来自仓库级的 config/public-build-contract.json。其中targets.frontend段定义了本工程的完整契约服务名service: frontend生产 URLhttps://h.omi.meDockerfileweb/frontend/Dockerfile构建上下文为仓库根build_context: .因为 Dockerfile 需要从仓库根复制源码部署区域us-central1平台linux/amd64prod 专属 gcloud 标志--ingressinternal-and-cloud-load-balancing仅允许内部流量 Cloud Load Balancing 入口公网通过负载均衡接入development环境无额外标志运行时 SecretDD_API_KEYDatadog与PUBLIC_SHARED_CONVERSATION_CHAT_IP_HMAC_KEY分享页 IP HMAC 密钥并显式移除OPENAI_API_KEY等敏感项构建输入inputsNEXT_PUBLIC_FIREBASE_API_KEY、NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN、NEXT_PUBLIC_FIREBASE_PROJECT_ID、NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET、NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID、NEXT_PUBLIC_FIREBASE_APP_ID、NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID、API_URL全部标记为required: true候选发布验收candidate_acceptance部署候选后执行python3 .github/scripts/smoke_public_build_browser.py --target frontend --base-url {base_url} --expect-sha {sha}通过后以frontend:ready为标记采用candidate_after_browser_acceptance策略切流量——即先构建“候选版本”并用真实浏览器冒烟验证通过后才把流量切到新版本。5.3 部署前校验与发布后验证工作流在部署前专门校验“前端调用共享对话服务的身份契约”gcp_frontend.ymlPUBLIC_SHARED_CONVERSATION_CHAT_FRONTEND_INVOKER_SA必须是合法的 Cloud Run 服务账号用户型xxxxproject.iam.gserviceaccount.com或计算型123-computedeveloper.gserviceaccount.comPUBLIC_SHARED_CONVERSATION_CHAT_FRONTEND_AUDIENCE必须是仅含 origin 的 HTTPS audience否则直接失败。部署完成后工作流调用backend/scripts/deploy_status_report.py对 Cloud Run 服务做 rollout 状态核验形成“校验 → 构建 → 候选 → 浏览器冒烟 → 切流量 → 核验”的完整闭环。5.4 多阶段 Docker 构建Dockerfile 采用经典三段式deps阶段基于node:20-alpine按 lockfile 优先级执行npm ciyarn/pnpm为兜底分支builder阶段通过ARG注入全部NEXT_PUBLIC_*构建期环境变量并有一段强制校验逻辑Dockerfile——遍历OMI_REQUIRED_PUBLIC_BUILD_INPUTS中列出的 8 个必填变量任一为空即构建失败从构建期杜绝“缺环境变量上线”runner阶段非 root 用户nextjs运行仅拷贝public/、.next/standalone与.next/staticEXPOSE 3000并以node server.js启动。注意 next.config.mjs 中的outputFileTracingRoot配置它把文件追踪根固定到web/frontend自身。源码注释解释了原因——Next.js 15 在 monorepo 中会依据兄弟 lockfile 推断工作区根从而把 standalone 输出嵌套到仓库根路径下破坏 Dockerfile 的COPY .../.next/standalone ./与CMD [node,server.js]。这一配置是 monorepo 部署能成功的关键细节。六、路由机制/conversations 与 /memories 双 URL 空间README 的 Notes 一节揭示了一个重要的路由事实公开分享 URL 对外使用/conversations/:id但内部页面与组件仍存放在src/app/memories/下。其桥梁是 next.config.mjs 中的一对规则// 301 永久重定向旧路径 /memories/* → 新路径 /conversations/* redirects: [{ source: /memories/:path*, destination: /conversations/:path*, permanent: true }], // 内部重写/conversations/* → 仍由 /memories/* 的页面组件渲染 rewrites: [{ source: /conversations/:path*, destination: /memories/:path* }],两者配合实现了“对外新 URL 稳定、对内组件零迁移”的平滑演进。sitemap 侧同样联动sitemap.ts 通过getPublicMemoriesPrerender(20000)拉取最多 2 万条公开记忆并输出memories/id路径development环境下返回空数组避免污染线上索引。其他值得留意的next.config.mjs细节output: standalone配合上文 Dockerfile 的自包含产物cacheHandler指向 cache-handler.cjs其注释表明目的是“绕过 Next.js 2MB fetch 缓存上限”直接复用框架内置的FileSystemCache实现让分享页对后端数据的 ISR 缓存revalidate: 60可以承载更大响应体安全响应头全站下发X-Frame-Options: DENY防点击劫持并对/.well-known/apple-app-site-association设置application/json内容类型以支持 iOS 通用链接远程图片白名单images.remotePatterns仅放行raw.githubusercontent.com、storage.googleapis.com、pbs.twimg.com、abs.twimg.com、static.vecteezy.comServer Actions 请求体上限experimental.serverActions.bodySizeLimit: 10mb为应用市场缩略图上传等操作预留空间。七、运行时配置与 URL 安全细节src/constants/envConfig.ts统一汇集运行时配置其中两个纯函数工具值得关注share-base-url.mjsshareBaseUrl(raw)对WEB_URL做严格归一化——补全https://前缀、剔除 query/hash/认证信息、去除尾斜杠非法输入一律回退到默认值https://h.omi.meshareHost()则提取 hostname 用于intent:///omi://深链。该逻辑与后端OMI_SHARE_BASE_URL及 Flutter/桌面端分享助手保持一致注释引用 issue #4339保证“一条分享链接多端一致”。shared-api-url.mjssharedApiUrl(base, ...segments)对每个路径段执行encodeURIComponent再拼接。其动机在源码注释中讲得很清楚Next.js 会把动态路由参数预先解码如/tasks/a%2Fb变成a/b若直接拼进 fetch URL 会导致请求误路由或 query 损坏逐段编码则保证 wire URL 始终合法。分享页的实际调用链可参考 memories/[id]/page.tsxgenerateMetadata通过sharedApiUrl(envConfig.API_URL, v1, conversations, params.id, shared)请求后端共享对话接口并设置next.revalidate: 60做 ISR 缓存接口失败或返回非 JSON 时静默降级为默认标题与“Shared Conversation Not Found”文案兼顾 SEO 元数据生成与健壮性。八、本地验证与进阶排查路径若想在本地完整跑通分享页链路可参考以下顺序均为仓库内已有资产启动本地后端使API_URLhttp://127.0.0.1:8787可访问或将其指向已部署的 API按 .env.template 补齐 Firebase 与 Algolia 配置后执行npm run dev用node --test src/__tests__跑契约测试重点看shared-api-url、share-base-url与shared-conversation-chat-contract三组用例部署行为验证可阅读 .github/scripts/preflight_public_build_config.py 与 .github/scripts/smoke_public_build_browser.py均为仓库内真实脚本理解候选版本在切流量前经过的配置预检与浏览器冒烟步骤。小结web/frontend是 Omi 面向公众的“门面”服务用 Next.js App Router 同时支撑分享页与商店页以standalone输出 多阶段 Docker 构建交付 Cloud Run并通过public-build-contract.json将服务名、区域、入口策略、运行时 Secret、必填构建输入与“浏览器冒烟后再切流量”的发布策略全部声明化。其/memories ↔ /conversations的双 URL 重写方案、绕过 2MB 缓存上限的文件系统 cache handler以及为测试友好而刻意保持纯 JS 的 URL 工具函数都是值得在同类公开分享型 Next.js 服务中复用的工程实践。【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门