开发指南开发常见问题
开发常见问题
技术选型、架构设计和开发实践的常见问题解答
🏗️ 架构设计相关
为什么我们不使用 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/docs
、xx.com/zh/docs
- 🎯 适用场景: 需要明确区分语言版本的网站
2. "as-needed"
(按需)
- 🔗 URL 格式: 默认语言无前缀,其他语言有前缀
- 📝 示例:
- 默认语言 (en):
xx.com/docs
- 其他语言 (zh):
xx.com/zh/docs
- 默认语言 (en):
- 🎯 适用场景: 希望默认语言 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,
},
🔐 用户体验与合规
为什么在注册页面添加隐私政策确认?
根据中国相关法律法规(如《个人信息保护法》)和用户体验最佳实践,用户在注册时需要明确同意隐私政策。
实现细节:
- ✅ 复选框验证: 用户必须勾选才能继续注册
- 🔗 链接跳转: 点击隐私政策链接在新窗口打开详细条款
- 🌍 多语言支持: 中英文界面都有相应的文案
- 📱 移动端友好: 复选框在移动设备上也有良好的交互体验
代码修改说明:
- 表单验证: 使用 Zod schema 添加
acceptPrivacyPolicy
字段的必填验证 - UI 组件: 添加 Checkbox 组件和相应的 FormField
- 多语言文本: 在
en.json
和zh.json
中添加相关翻译 - 链接处理: 隐私政策链接指向
/legal/privacy-policy
页面
相关文件:
src/modules/dashboard/auth/components/SignupForm.tsx
: 注册表单组件src/lib/i18n/translations/en.json
: 英文翻译src/lib/i18n/translations/zh.json
: 中文翻译