文档
开发指南开发常见问题

开发常见问题

技术选型、架构设计和开发实践的常见问题解答

🏗️ 架构设计相关

为什么我们不使用 monorepo

monorepo 对于我们这种小型网站会带来不必要的学习成本和维护复杂性,而且由于文件夹层级更加复杂,加上 AI 不太习惯修改 monorepo 类型代码,所以我们不使用。

具体原因:

  • 📁 复杂性过高: 对于单一产品来说,monorepo 的配置和工具链过于复杂
  • 🤖 AI 友好性: AI 在处理简单目录结构时更加高效
  • 🚀 快速迭代: 单仓库更利于快速原型开发和功能迭代
  • 👥 团队规模: 小团队不需要 monorepo 的隔离和共享优势

为什么将 ui 放在 src/components 目录下而不是 modules

因为放在 src/components 目录下更符合通常的习惯,也方便 AI 修改。

详细说明:

  • 🎯 约定优于配置: 遵循 React/Next.js 社区的标准约定
  • 🤖 AI 兼容性: AI 更容易识别和操作标准目录结构
  • 📦 工具支持: IDE 和构建工具对标准结构有更好的支持
  • 🔍 易于查找: 开发者能快速定位基础 UI 组件

🚀 前端框架选择

为什么选择 Next.js 而不是 Vite + React 或其他框架?

Next.js 的优势:

  • 🌐 全栈能力: 前后端一体化,API Routes 开箱即用
  • 🚀 性能优化: 自动代码分割、图片优化、字体优化
  • 📱 SEO 友好: Server-Side Rendering (SSR) 和 Static Generation
  • 🔄 App Router: 新一代路由系统,支持 React Server Components
  • 🌍 国际化: 内置 i18n 支持
  • 📦 零配置: 开箱即用,无需复杂的 Webpack 配置

与其他方案对比:

  • vs Vite + React: Next.js 提供完整的全栈解决方案,Vite 需要额外配置路由、SSR 等
  • vs Nuxt.js: JavaScript 生态更成熟,TypeScript 支持更好
  • vs Remix: 学习曲线更平缓,生态系统更丰富

🗃️ 数据库技术栈

为什么选择 PostgreSQL 而不是 MySQL 或 MongoDB?

PostgreSQL 优势:

  • 🔒 ACID 事务: 严格的数据一致性保证
  • 🧠 高级功能: JSON 支持、全文搜索、数组类型等
  • 📊 性能优异: 复杂查询性能更好
  • 🔧 扩展性: 丰富的插件生态(PostGIS、pg_vector 等)
  • 💰 成本效益: 开源免费,云服务商支持良好

与其他数据库对比:

  • vs MySQL: PostgreSQL 对复杂数据类型和查询支持更好
  • vs MongoDB: 关系型数据更适合我们的用户、组织、支付等业务模型
  • vs SQLite: PostgreSQL 支持并发和扩展性更好

为什么选择 Prisma 而不是 Drizzle 或其他 ORM?

Prisma 优势:

  • 🎯 类型安全: 自动生成 TypeScript 类型,编译时错误检查
  • 🔍 Prisma Studio: 可视化数据库管理工具
  • 📝 声明式 Schema: 易读易写的数据模型定义
  • 🔄 迁移系统: 安全的数据库版本管理
  • 🤖 AI 友好: 生成的代码结构清晰,AI 容易理解和修改

与其他 ORM 对比:

  • vs Drizzle: Prisma 生态更成熟,工具链更完善
  • vs TypeORM: Prisma 的 Schema 语法更简洁
  • vs 原生 SQL: Prisma 提供类型安全和开发效率

🔐 认证与安全

为什么选择 Better Auth 而不是 NextAuth.js?

Better Auth 优势:

  • 现代设计: 专为现代 React 和 TypeScript 设计
  • 🔧 灵活配置: 更细粒度的控制和自定义能力
  • 📱 多端支持: 同时支持服务端和客户端渲染
  • 🛡️ 安全性: 内置更多安全特性和最佳实践
  • 🚀 性能: 更轻量,启动和运行时性能更好

具体优势:

  • 🔑 更多认证方式: 支持通行密钥、魔术链接、双因素认证
  • 👥 组织管理: 内置多租户和组织支持
  • 📊 会话管理: 更灵活的会话控制和设备管理
  • 🔄 迁移友好: 从其他认证系统迁移更容易

🎨 UI 和样式

为什么选择 Tailwind CSS 而不是 styled-components 或 CSS Modules?

Tailwind CSS 优势:

  • 开发效率: 原子化 CSS,快速构建界面
  • 🎯 一致性: 预定义的设计系统,保证视觉一致性
  • 📦 包大小: 按需编译,最终 CSS 体积更小
  • 🤖 AI 友好: AI 更容易生成和修改 Tailwind 类名
  • 🔧 可定制: 通过配置文件轻松定制设计系统

为什么选择 shadcn/ui 而不是 Ant Design 或 Material-UI?

shadcn/ui 优势:

  • 🎨 设计美观: 现代化的设计语言,视觉效果优秀
  • 🔧 高度可定制: 基于 Radix UI,可以完全控制样式和行为
  • 📦 按需使用: 复制组件代码到项目中,没有额外依赖
  • 🚀 性能优异: 无运行时开销,编译时优化
  • 🤖 AI 兼容: 简单的组件结构,AI 容易理解和修改

与其他组件库对比:

  • vs Ant Design: shadcn/ui 更轻量,样式更现代
  • vs Material-UI: 不受 Google 设计语言限制,更灵活
  • vs Chakra UI: 基于 Tailwind,与项目技术栈更统一

⚡ 性能优化

为什么选择 bun 而不是 npm 或 yarn?

bun 优势:

  • 🚀 安装速度: 比 npm 快
  • 🧠 内存占用: 更低的内存使用率

实际收益:

  • ⏱️ CI/CD 加速: 构建部署时间显著减少
  • 💰 成本节省: 云服务器存储和带宽成本降低
  • 🛡️ 安全保障: 减少供应链攻击风险

🤖 AI 集成

为什么使用 Vercel AI SDK?

AI SDK 优势:

  • 🌊 流式响应: 实时流式输出,用户体验更好
  • ⚛️ React 集成: useChat hook 简化状态管理
  • 🔄 多模型支持: 统一接口支持多个 AI 提供商
  • 🎯 TypeScript: 完整的类型定义和智能提示
  • 🛡️ 错误处理: 内置重试和错误恢复机制

🔧 开发工具

为什么选择 Biome 而不是 ESLint + Prettier?

Biome 优势:

  • 极速性能: Rust 编写,比 ESLint 快 100+ 倍
  • 🎯 一体化: 同时提供 Linting 和 Formatting 功能
  • 🔧 零配置: 开箱即用的合理默认配置
  • 🔄 兼容性: 大部分 ESLint 规则可以平滑迁移
  • 📦 依赖更少: 减少 node_modules 大小和安装时间

为什么选择 Hono 而不是直接使用 Next.js API Routes?

Hono 优势:

  • 🚀 性能: 更快的请求处理和响应时间
  • 🔧 中间件: 更灵活的中间件系统
  • 📊 OpenAPI: 内置 API 文档生成
  • 🌐 跨平台: 可以部署到 Cloudflare Workers 等边缘环境
  • 🎯 类型安全: 端到端类型安全的 API 开发

适用场景:

  • 📱 移动端 API: 为 App 提供高性能 API 服务
  • 🌍 第三方集成: 开放 API 给合作伙伴使用
  • 📊 数据处理: 复杂的业务逻辑和数据处理

🚀 部署与运维

为什么推荐 Vercel 部署?

Vercel 优势:

  • 🔄 Git 集成: 推送代码自动部署,零配置 CI/CD
  • 🌐 全球 CDN: 自动优化静态资源分发
  • 🚀 边缘函数: API 在全球边缘节点运行
  • 📊 性能监控: 内置性能分析和错误追踪
  • 💰 成本效益: 小项目免费额度充足

为什么推荐 Neon 作为数据库服务?

Neon 优势:

  • 无服务器: 按需扩缩容,无需管理服务器
  • 🔄 分支功能: 数据库分支,支持开发测试环境
  • 💰 成本优化: 自动休眠功能,开发阶段零成本
  • 🔒 安全性: 内置连接池和安全隔离
  • 🌍 全球部署: 多区域部署支持

🌍 国际化配置

localePrefix 的 "as-needed" 和 "always" 有什么区别?

配置说明:

localePrefix: config.i18n.enabled ? "as-needed" : "never"

三种模式对比:

1. "always" (默认)

  • 🔗 URL 格式: 所有路径都包含语言前缀
  • 📝 示例: xx.com/en/docsxx.com/zh/docs
  • 🎯 适用场景: 需要明确区分语言版本的网站

2. "as-needed" (按需)

  • 🔗 URL 格式: 默认语言无前缀,其他语言有前缀
  • 📝 示例:
    • 默认语言 (en): xx.com/docs
    • 其他语言 (zh): xx.com/zh/docs
  • 🎯 适用场景: 希望默认语言 URL 更简洁的网站

3. "never" (从不)

  • 🔗 URL 格式: 所有语言都无前缀,通过 Cookie 或域名区分
  • 📝 示例: xx.com/docs (语言通过 Cookie 确定)
  • 🎯 适用场景: 单域名多语言或基于用户设置的语言切换

访问行为说明:

当使用 "as-needed" 模式时:

  • 访问 xx.com/docs: 直接显示默认语言内容,不会跳转
  • 🔄 访问 xx.com/en/docs: 会重定向到 xx.com/docs (如果 en 是默认语言)
  • 🎯 访问 xx.com/zh/docs: 直接显示中文内容,保持 URL 不变

我们的选择理由:

  • 🚀 SEO 友好: 默认语言 URL 更简洁,有利于搜索引擎优化
  • 👥 用户体验: 主要用户群体看到的是无前缀的简洁 URL
  • 🔄 向后兼容: 支持带前缀的 URL 访问,自动处理重定向

🤔 其他常见问题

为什么不使用 Server Actions 而是 API Routes?

我们的选择:

  • 🎯 清晰分离: API 层独立,前后端职责明确
  • 📱 移动端支持: API 可以被移动应用复用
  • 🔧 中间件: 更好的认证和权限控制
  • 📊 监控调试: 更容易监控和调试 API 请求
  • 🌐 第三方集成: 方便第三方服务调用

💡 提示: 如果你对某个技术选型有疑问,可以参考我们的 快速入门指南 了解更多实现细节。

next-intl as-needed 不生效

原因分析:

  • 理论上 as-needed 模式下,默认语言的 URL 不包含语言前缀,其他语言包含前缀

但是实际上这并不生效(可能是 next-intl 的 bug) 所以我们使用了 next.config.ts 的 rewrites 配置来手动处理重定向

			{
				source: "/docs/:path*",
				destination: "/zh/docs/:path*",
				permanent: false,
			},

🔐 用户体验与合规

为什么在注册页面添加隐私政策确认?

根据中国相关法律法规(如《个人信息保护法》)和用户体验最佳实践,用户在注册时需要明确同意隐私政策。

实现细节:

  • 复选框验证: 用户必须勾选才能继续注册
  • 🔗 链接跳转: 点击隐私政策链接在新窗口打开详细条款
  • 🌍 多语言支持: 中英文界面都有相应的文案
  • 📱 移动端友好: 复选框在移动设备上也有良好的交互体验

代码修改说明:

  1. 表单验证: 使用 Zod schema 添加 acceptPrivacyPolicy 字段的必填验证
  2. UI 组件: 添加 Checkbox 组件和相应的 FormField
  3. 多语言文本: 在 en.jsonzh.json 中添加相关翻译
  4. 链接处理: 隐私政策链接指向 /legal/privacy-policy 页面

相关文件:

  • src/modules/dashboard/auth/components/SignupForm.tsx: 注册表单组件
  • src/lib/i18n/translations/en.json: 英文翻译
  • src/lib/i18n/translations/zh.json: 中文翻译