首页
/ Folo(follow)开源贡献指南:从 Corepack 环境准备到四端开发工作流与质量门禁

Folo(follow)开源贡献指南:从 Corepack 环境准备到四端开发工作流与质量门禁

2026-09-05 17:10:42作者:温玫谨Lighthearted

本文基于 Folo(AI RSS 阅读器,仓库 follow)的官方贡献文档 CONTRIBUTING.md 编写,覆盖从 Corepack + pnpm 环境准备、四种开发入口(浏览器 / Electron / 外部 SSR / 移动端)的完整操作步骤,到提交前必须通过的质量门禁(typecheck → lint → test)。读完本篇,你可以独立把该 monorepo 跑起来,并对每一步命令背后的实现(如 __debug_proxy 在线调试机制、移动端的 App Check 调试令牌)有源码级的理解,具备直接向该项目提交代码的基础。

一、准备工作:monorepo 结构与包管理器

Folo 是一个由 pnpm workspaces + Turbo 管理的 monorepo。在动手前需要先理解仓库的组织方式,这决定了后续每条命令的作用范围:

  • 根工作区定义在 pnpm-workspace.yaml,包含 apps/*packages/**/*apps/desktop/layer/* 以及 apps/mobile/web-app/html-renderer,并排除了 **/example 目录;
  • 四个主要应用分别是 apps/desktop(Electron 桌面端,Vite + React 渲染层)、apps/mobile(Expo / React Native 移动端)、apps/ssr(用于外部分享的极简 SSR 站点)、apps/landing(落地页),共享逻辑沉淀在 packages/internal/*(components、store、hooks、database 等)。

启用 Corepack

官方要求贡献者先启用 Corepack,它会根据根 package.json 中声明的 packageManager 字段(当前仓库锁定为 pnpm@10.17.0)自动匹配正确的 pnpm 版本,避免团队内包管理器版本漂移:

corepack enable && corepack prepare

从源码结构看,这一机制被双重加固:根 package.jsonprepare 脚本为 simple-git-hooks && corepack prepare,即 pnpm install 后会自动再次执行 corepack prepare,确保锁定的 pnpm 版本与 git hooks 同步就绪。

安装依赖

pnpm install

需要注意 package.json 中配置了 postinstall 钩子:

"postinstall": "pnpm run build:packages",
"build:packages": "turbo run build --filter=\"./packages/**/*\""

也就是说,安装依赖的同时会用 Turbo 把所有 packages/** 下的内部包预先构建一遍。这也解释了为什么 AGENTS.md 中给出的"Setup commands"以 pnpm install 作为第一条——安装命令本身就是环境准备的一部分,首次安装耗时会明显长于后续安装。

二、四种开发入口

CONTRIBUTING.md 提供了四条开发路径:浏览器、Electron、外部 SSR Web、移动端。下面逐一展开,并给出源码层面的佐证。

2.1 浏览器开发(推荐):__debug_proxy 调试入口

官方推荐"在浏览器中开发",因为它体验更轻、更接近最终 Web 形态:

cd apps/desktop && pnpm run dev:web

该命令的实际定义在 apps/desktop/package.json 中:

"dev:web": "cross-env WEB_BUILD=1 vite"

WEB_BUILD=1 标记这是一个纯 Web 构建(不带 Electron 主进程)。文档说明启动后会引导你访问 https://app.folo.is/__debug_proxy,从而复用线上 API 环境进行开发调试。这个 __debug_proxy 机制在源码中可以直接验证:

  1. 桌面端的 vite.config.ts 在构建时会把调试页写出到 dist/__debug_proxy.htmldist/__debug_proxy/index.html,并在开发模式打印两条调试地址——生产调试页 https://app.folo.is/__debug_proxy.html 与开发调试页 https://dev.folo.is/__debug_proxy.html
  2. 部署侧,vercel.json 配置了重写规则,把 /__debug_proxy/__debug_proxy/:path* 请求统一落到 __debug_proxy.html,保证线上路径可用;
  3. 路由侧,apps/desktop/layer/renderer/src/router.web.tsx 通过 globalThis["__DEBUG_PROXY__"] 或 pathname 前缀 /__debug_proxy 判断是否处于调试代理运行时,此时改用 createHashRouter(因为线上页面并非部署在站点根路径下,hash 路由可避免刷新 404)。

也就是说:本地 Vite dev server 提供 JS 资源,线上 __debug_proxy 页面提供 API 与域名环境,二者结合即构成"浏览器里开发、打线上后端"的完整链路。

2.2 Electron 开发

若需要在桌面壳内开发,CONTRIBUTING.md 给出的步骤为:

# 0. 进入目录
cd apps/desktop

# 1. 复制示例环境变量文件
cp .env.example .env

# 2. 将 .env 中的 VITE_API_URL 设置为 https://api.follow.is

# 3. 启动开发服务器
pnpm run dev:electron

dev:electron 实际执行的是 electron-vite dev(见 apps/desktop/package.json),即同时启动 Electron 主进程与渲染进程。

关于 .env 文件,仓库内已提供 apps/desktop/.env.example,包含以下变量:

变量 示例值 说明
VITE_WEB_URL http://localhost:5173 本地 Web 渲染地址
VITE_API_URL http://localhost:3000 API 后端地址(文档要求改为 https://api.follow.is
VITE_IMGPROXY_URL http://localhost:2873 图片代理地址
VITE_SENTRY_DSN 错误上报 DSN
VITE_BUILD_TYPE production 构建类型
VITE_INBOXES_EMAIL @follow.re 收件箱邮箱
VITE_PUBLIC_POSTHOG_KEY / VITE_PUBLIC_POSTHOG_HOST 埋点配置

文档中的排障提示:如果遇到登录问题,可以把浏览器 Cookie 里的 __Secure-better-auth.session_token 复制到应用中,复用已有的浏览器会话完成登录态。

2.3 外部 SSR Web 应用开发

SSR 站点对应 apps/ssr 目录,用于外部分享场景(例如分享内容页的服务端渲染版本)。启动方式最简单:

cd apps/ssr
pnpm run dev

另外,根 package.json 还提供了一条 dev:web 脚本(turbo run @follow/web#dev @follow/ssr#dev),可并行拉起 desktop 渲染端与 SSR 端,适合需要两侧同时联动的改动。

2.4 移动端开发(需要 Mac)

CONTRIBUTING.md 明确标注:移动端开发需要 Mac 设备,并已安装 Xcode 及相应依赖。步骤如下:

# 1. 进入目录
cd apps/mobile

# 2. 复制环境变量文件,并写入调试令牌
cp .env.example .env
echo 'EXPO_PUBLIC_APP_CHECK_DEBUG_TOKEN="xxx"' >> .env
# 也可以手动在 .env 中添加 EXPO_PUBLIC_APP_CHECK_DEBUG_TOKEN="xxx"
# 注意:令牌值可以是任意字符串

# 3. 从源码构建并安装 Folo(dev) 应用(耗时较长,只需做一次)
pnpm expo prebuild --clean # 可选
pnpm run ios

# 4. 启动开发服务器
pnpm run dev

EXPO_PUBLIC_APP_CHECK_DEBUG_TOKEN 并不是随意要求——从源码 apps/mobile/src/initialize/app-check.ts 可以看到它的用途:

provider.configure({
  apple: {
    provider: __DEV__ ? "debug" : "appAttest",
    debugToken: env.APP_CHECK_DEBUG_TOKEN,
  },
  android: {
    provider: __DEV__ ? "debug" : "playIntegrity",
    debugToken: env.APP_CHECK_DEBUG_TOKEN,
  },
  isTokenAutoRefreshEnabled: true,
})

即开发态(__DEV__)下 Firebase App Check 使用 debug provider 并注入该调试令牌,生产态则切换为 iOS 的 appAttest / Android 的 playIntegrity。这就是为什么该令牌"值可以是任意字符串":它在 debug provider 下由开发者自行生成并配置到 Firebase 控制台即可。仓库中的 apps/mobile/.env.example 也同时预留了 SENTRY_AUTH_TOKEN 变量位。

开发 iOS 原生模块

需要修改 FollowNative 原生模块时(对应 apps/mobile/native 下的 Expo 原生模块),按文档操作:

# 1. 进入 iOS 工程目录
cd apps/mobile/ios

# 2. 在 Xcode 中打开工作区
open Folo.xcworkspace

# 3. 在左侧 Pods 目录中选择 FollowNative 后直接 Build & Run

原生模块本身是一个 Expo module(见 apps/mobile/native/expo-module.config.json),native/ios 下包含 Swift 实现,通过 CocoaPods 以 FollowNative 名义接入工程,因此改动后需在 Xcode 中重新编译 Pods 才会生效。

三、质量门禁与代码规范

CONTRIBUTING.md 的 "Contribution Guidelines" 要求:代码遵循项目编码规范、提交信息清晰简洁、为改动附带相关测试、按需更新文档。落到可执行层面,AGENTS.md 给出了明确的"提交前必过"质量门禁,并且顺序是固定的

# 1) 先跑类型检查(必须)
pnpm run typecheck

# 2) 再跑 Lint 并自动修复
pnpm run lint:fix

# 3) 最后跑测试
pnpm run test

对应的根 package.json 脚本值得细看:

"typecheck": "turbo typecheck",
"lint": "pnpm run lint:tsl && eslint",
"lint:fix": "eslint --fix",
"lint:tsl": "tsslint --project apps/*/tsconfig.json",
"test": "cross-env CI=1 pnpm --recursive run test"

即 lint 实际包含两层:tsslint(基于 ts 项目的类型级 lint,作用于所有 app 的 tsconfig)加 eslint;测试则以 CI=1 递归执行各包的测试(测试框架为 Vitest,测试文件与源码就近放置,如 apps/cli/src/args.test.ts 这类同名 *.test.ts 文件)。

此外仓库还配了自动化护栏,提交时会额外触发:

  • simple-git-hooks 的 pre-commit 钩子执行 pnpm exec lint-staged
  • lint-staged 对暂存文件统一执行 eslint --fixprettier --write,并对 locales/**/*.json 额外运行 dedupe:locales(即 eslint --fix locales/**,保持多语言词条排序一致),对 apps/mobile/src/** 触发构建号自增脚本。

代码风格上的硬性约定(同样来自 AGENTS.md):TypeScript strict 模式、避免 any、注释使用英文;跨平台路径用 pathe 而非 node:path;通用可复用组件放在 packages/internal/components,应用专属 UI 留在各自 app 内;测试用 Vitest 并与源码同目录。

四、社区与许可证

  • 社区交流渠道:官方 Discord 与 Twitter/X(@folo_is),用于讨论想法、提问和分享贡献。
  • 许可证:根据 CONTRIBUTING.md 与根 package.json"license": "AGPL-3.0-only"),向 Folo 提交代码即表示同意其贡献以 GNU Affero General Public License v3 授权发布,特殊例外条款见 README.md

五、贡献流程速查清单

  1. corepack enable && corepack prepare 准备包管理器环境;
  2. pnpm install 安装依赖(postinstall 会自动构建所有内部包);
  3. 按改动目标选择开发入口:
    • 改 Web/渲染层:cd apps/desktop && pnpm run dev:web,通过线上 __debug_proxy 页面调试;
    • 改 Electron 主进程/桌面能力:cp .env.example .env、设置 VITE_API_URLpnpm run dev:electron
    • 改分享页 SSR:cd apps/ssr && pnpm run dev
    • 改移动端:配置 EXPO_PUBLIC_APP_CHECK_DEBUG_TOKENpnpm run ios(一次)+ pnpm run dev;改原生模块则进 apps/mobile/ios 用 Xcode 编译 FollowNative
  4. 提交前按固定顺序通过门禁:pnpm run typecheckpnpm run lint:fixpnpm run test
  5. 保持提交信息清晰、附测试、更新文档,并遵守 AGPL-3.0 授权约定。
登录后查看全文
热门项目推荐
相关项目推荐