SaaS-Boilerplate介绍
April 11, 2024
SaaS Boilerplate是一个全栈React应用开发框架,基于Next.js、Tailwind CSS、Shadcn UI、TypeScript构建,具备Auth、Multi-tenancy、Roles & Permissions、i18n、Landing Page、DB、Logging、Testing等功能。它还支持14+ Next.js版本、Tailwind CSS 3.4和TypeScript。开发环境包括:Prettier、Lint-Staged、Jest、Testing Library、Commitlint、VSCode、PostCSS、Clerk、DrizzleORM、Sentry、Log Management、Checkly、Storybook、Multi-language(i18n)等。它具有非常灵活的代码结构,并严格类型检查,支持多语言(i18n)和团队协作。此外,它还具备强大的身份验证和访问控制功能,并支持多因素Auth和多因素认证(如Google、Facebook、Twitter等)。最后,它还具备数据库管理和多语言支持,以及强大的Validation Library和Linter。
特性
authentication
使用Clerk实现用户认证、orgniztion管理的基础能力。
database
使用 DrizzleORM 操作DB。虽然官方推荐使用Turso + libSQL ,看代码貌似没有强制。理论上任意平台的SQLite, PostgreSQL, MySQL 都可以。也集成了drizzle studio,方便查看、管理DB。
注意项目中仅仅集成了其基础特性,并没有限制业务如何使用。
Translation (i18n)
使用了Crowdin的能力, src/locales/ 目录下有两个对应的本地化结果(默认支持英语和法语)。
- 如何更新?
利用Crowdin的能力,只需要更新一个源文件,就可以自动生成其他语言的翻译文件。Crowdin有两种使用方式,一种是直接去网站手工上传&下载。另外一种是通过官方提供的命令行工具,通过配置文件 crowdin.yml 自动生成。Loading...
项目中推荐使用git action自动完成翻译工作。
// The localisation files are synced with Crowdin using GitHub Actions. // By default, there are 3 ways to sync the message files: // 1. Automatically sync on push to the `main` branch // 2. Run manually the workflow on GitHub Actions // 3. Every 24 hours at 5am, the workflow will run automatically
- 如何新增其他语种?
除了使用Crowdin生成对应的翻译文件外,项目中也需要配置其他语言的切换入口。参看 AppConfig/locals 中的语言列表定义。
多语言支持使用的是 next-intel 的能力,大致流程如下,详细流程参考官网:
- 配置 next.config.mjs 以及定义 i18n.ts :目的是根据请求动态加载不同的翻译文件,供后续components中使用。
- 中间件引入locales:指定 locales 相关定义,用于路由判断。注意中间件中需要考虑 @clerk/nextjs 鉴权的执行顺序。主要包括以下几个参数:
- locales:支持的语言列表
- localePrefix:路由的处理方式,可以控制在URL path中是否出现locale,详见文档。项目中使用的是 as-needed ,即默认locale时不需要出现在path中。
- defaultLocale:默认locale
- 全局layout中增加locale的处理:中间件会将locale转换为url参数,在layout中通常做以下几件事:
- 判断locale合法性,异常请求拦截
- 在输出的html中增加lang property,主要用于浏览器的拼写检查、SEO优化等。Loading...
- 在服务、客户端组件中使用,在服务端和客户端的使用方式上有差异,具体使用方法详见文档。项目中的典型用法:Loading...
- locales 切换入口:页面需要提供语言切换的入口。
- 在 dashboard/layout 中引入了LocaleSwitcher组件,提供语言切换的组件。
- LocaleSwitch封装 next-intl/navigation 中更新locale的能力,当用户点击切换button时实现参数切换、路由跳转等。
next-sitemap
使用https://github.com/iamvishnusankar/next-sitemap来生成 sitemap.xml 和 robots.txt 。貌似相比Next的原生方案可以更加灵活,比如支持 index sitempas。
Commit Message Format
借助 cz 工具,要求所有commit message必须按照《约定式提交规范》的格式来生成commit message,相对自己裸写会commit message更加清晰。另外按照此规范,可以自动生成 CHANGELOG 文件(本项目使用semantic-release生成)。
为什么使用约定式提交
- 自动化生成 CHANGELOG。
- 基于提交的类型,自动决定语义化的版本变更。
- 向同事、公众与其他利益关系者传达变化的性质。
- 触发构建和部署流程。
- 让人们探索一个更加结构化的提交历史,以便降低对你的项目做出贡献的难度。
Testing & Code Coverage
- 项目支持使用jest进行单侧
- 支持使用playwright进行自动化测试
- 支持使用codecov来统计覆盖率【仅统计】—— 貌似jest也支持本地统计吧
Edge runtime
项目支持Edge runtime方式部署,不过由于Edge与自动迁移无法兼容,启用前需要先禁用掉db的自动迁移,db变更时改为手动执行 migrate 操作。
Logging
使用 Pino.js来作为本地日志库,pino在性能上有着不错的口碑。
在生产环境,支持使用Better Stack来管理远程日志。Better Statck支持日志记录、查询以及监控等能力。——感觉跟Sentry、Datadog等类似。
Error Monitoring
错误监控使用的是 Sentry,包含了日志收集、告警通知、性能监控等能力。类似的前端监控产品有Datalog等。
部署方式上,Sentry支持官方托管(支持免费、付费套餐)和Self-Hosting两种方式,看上去对开发更加友好。
Checkly监控
使用Checkly来实现生成环境的可用性监控。类似接口测试工具,Checkly支持远程API测试验证接口可用性,同时也支持远程对页面的e2e可用性测试。
源码解析
路由
项目采用 AppRoute 的方式,一级路由为 locale 用于区分语言,二级路由拆分了两个不同的目录,分别用于是否认证(auth / unauth)的场景【拆分无实际意义,只是为了管理方便】。
layout
- 注入基础metadata:icons
- 处理locale:写入html.lang, 增加NextIntlClientProvider父组件封装,供后续component使用。
(unauth)
- 动态生成metadata(因为需要根据locale获取对应的 meta_title meta_description)
- page内容:内容由首页几个component组成,主要介绍产品features
认证拦截
中间件中需要对部分路由设置认证保护,主要有几个选项需要设置:
- publicRoutes:公共路由,目前是手工将unauth目录下的两个目录加入的,后续有新增path时也需要更新。
- beforeAuth:在认证前处理的逻辑,会根据beforeAuth的处理结果决定是否需要进行认证校验。项目中将 next-intel 中间件放到了这里,因为请求可能会被redirect等。
- afterAuth:自定义的 afterAuth 除了将登录和注册添加到公共路由外,完全取代了clerk的默认行为。项目的处理逻辑:
- 未登录:跳转登录
- 已登录无orgId,跳转 /onboarding/organization-selection
感觉Clerk的orgnization组织逻辑有点奇怪,注册后必须指定orgnization。为何不能默认?
(auth)
- layout:主要包括以下几个部分
- OrganizationSwitcher:clerk提供的orgnization切换组件(clerk还真是提供全套,页面组件都覆盖到了)
- 各page入口,包括
- /dashboard 登录后的首页
- /dashboard/organization-profile members管理
- /dashboard/organization-profile/organization-settings orgnization设置页
- locale 切换和UserButton,UserButton也是直接使用Clerk的组件来展示用户信息以及log out入口。
- pages
- dashboard 登录后的首页,这里也是模板适用方来定制业务逻辑最合适的地方。
- /dashboard/organization-profile orgnization member管理和setting,主要用来承载clerk的成员管理组件OrganizationProfile
- /dashboard/organization-profile/organization-settings
- sign-in/sign-up
借助clerk的SignUp、SignIn组件,实现登入、登出的能力。
总结
优点
- 特性集成比较丰富,重点包括
- 基于Drizzle ORM实现DB存储能力
- 基于Clerk的用户及orgnization管理能力
- SEO:sitemap、robot等基础SEO特性
- 可观测能力:基于Sentry、Checkly实现的可观测、监控能力。
- 测试:单侧以及e2e测试
- 工程化能力:包括eslint、commit message format规范化等
- next.js等版本都比较新
不足
- 覆盖的特性有点求多,比如监控就引入了好几个。感觉在选型上可以考虑更加简单些的方案。重点关注基础能力上,毕竟小型SaaS对单测、可观测的要求并没有那么高【ps: 个人意见】。
- 用户认证(登入、登出、orgnization等)完全依赖Clerk,不确定是否是最优解。在我本地测试时发现响应也比较慢,可能在国外这个不是问题。
- 个人觉得在一些Saas基础能力上可以做一些扩展,比如支付、文档化、文件存储、邮件能力等。
整体来说SaaS Boilerplate是个不错的模板选项,试用有一定开发能力且需要快速搭建Saas平台的场景。另外作者响应也比较迅速,提个issue能很快被响应。类似的产品还有https://github.com/wasp-lang/open-saas等。后续可以做个对比。