配置文件
Saavo 模板的配置规则、公共类型和配置文件索引。
项目配置统一放在 config/ 目录。修改站点信息、功能开关、产品、支付或第三方服务时,应先找到相应的配置文件,再根据 Schema 和调用代码确认字段要求。
配置文件不能保存密钥
config/ 中的内容会提交到 Git,也可能进入客户端或构建产物。密码、API Key、访问令牌和签名密钥必须放在环境变量或 Cloudflare Secret 中。
配置文件只能保存静态值
配置项只能填写字符串、数字、布尔值、数组和普通对象等静态值。函数、类实例、Promise,以及需要在运行时计算的内容,都不能放进配置文件。5 * 1024 * 1024 这类加载时即可确定结果的常量表达式可以使用;依赖当前请求、用户、数据库、系统时间或随机数的逻辑,应写在对应的业务代码中。
读取配置
config/ 中的文件都是普通的 TypeScript 模块,应用直接导入配置常量,不需要转换成 JSON。大多数配置对象以 as const satisfies ...Input 结尾:
as const会保留产品 ID、角色名等字面量,其他代码可以据此推导出准确的联合类型;satisfies检查字段名和输入类型,同时保留原对象的准确类型。
import type { WebsiteDeployCfgInput } from '@/libs/config/schemas/deploy';
export const websiteDeployCfg = {
// 配置内容
} as const satisfies WebsiteDeployCfgInput;服务端通过以下函数读取完整配置:
getServerConfig(): AppConfig第一次调用时,程序会合并所有配置,并交给 AppConfigSchema 校验。校验通过后,结果会保存在配置注册表中,后续调用直接读取这份配置。校验失败时,程序会报出 Configuration validation failed at startup,并终止启动。
浏览器端通过以下函数读取公开配置:
getClientConfig(): typeof _rawConfig客户端配置目前只包括 base、i18n、scopes、ads 和 analytics。这些内容会打包到浏览器端,访客可以直接查看,因此不能包含敏感信息。
类型检查和启动校验不是一回事
satisfies 只能检查 TypeScript 能表达的约束;邮箱格式、数值范围、时间间隔格式以及产品与联盟推广配置之间的引用关系,还要由 Zod 在启动时检查。因此,修改配置后不能只看编辑器有没有报错。
...Input 是配置文件使用的输入类型,通常与 satisfies 配合使用;不带 Input 的同名类型一般表示 Zod 校验后的结果。如果字段带有默认值、预处理规则或可选设置,两种类型可能不同。填写配置时以 Input 类型为准,业务代码通过 getServerConfig() 读取校验后的配置。
公共类型
多个配置文件都会使用 LocalizedText 和 DateIntervalType。这两个类型的字段含义和填写规则统一见下文。
LocalizedText
LocalizedText 用于填写多语言文案,定义在 src/libs/i18n/types.ts。它是一个包含 value 和 key 的对象,不能直接填写普通字符串。
Prop
Type
value 和 key 至少填写一项。需要支持多语言时通常两项都写:页面先按 key 读取当前语言的文案,未找到时再显示 value。
{
value: 'Saavo Starter',
key: 'website.title',
}DateIntervalType
DateIntervalType 用字符串填写时间长度,常见于会话有效期、缓存时间、请求频率限制周期和联盟推广结算周期。格式为数字加时间单位,数字和单位之间可以留空格。
| 单位 | 含义 | 示例 |
|---|---|---|
ms | 毫秒 | 500ms |
s | 秒 | 30s |
m | 分钟 | 15m |
h | 小时 | 2h |
d | 天 | 7d |
w | 周 | 2w |
mo | 月 | 1mo |
y | 年 | 1y |
单位也可以写成 seconds、minutes、hours 等完整英文单词。只写数字会按毫秒处理,容易填错,建议始终写明单位。注意:m 表示分钟,mo 才表示月。
修改配置
找到负责该功能的文件
先从下方表格进入相应文章,确认字段路径、类型、模板默认值和用途。不要只看字段名称相似,就把配置写进不相关的文件。
按现有结构修改
保留导出变量名和末尾的 satisfies 类型约束。新增对象键时,优先使用稳定、便于阅读的英文标识;需要显示给用户的文字使用 LocalizedText,不要把中文直接当作产品 ID、角色名或授权范围(Scope)。
同步相关资源
修改多语言文案键名时,应同步更新所有已支持语言的 JSON 文件。修改 Stripe Price ID、Cloudflare 资源名称、邮箱地址或第三方服务标识时,还要到相应平台确认资源已经创建,并检查所用账号是否有权访问。
完整检查
依次运行 npm run lint、npx tsc --noEmit 和 npm run build。生产构建会触发内容生成和应用构建,更容易发现只在启动或打包阶段出现的配置错误。
配置文件一览
| 文件 | 用途 |
|---|---|
base.ts | 站点名称、SEO 分享图片、社交账号、管理员邮箱和邮件地址 |
i18n.ts | 站点支持的语言和默认语言 |
deploy.ts | 主机、安全策略、存储、邮件、认证、访问统计和内容开关 |
payment.ts | 支付服务商、Checkout 和账单门户 |
products.ts | 产品、套餐、Stripe Price ID、购买后获得的角色和权益 |
capability.ts | 角色和权益使用的能力定义 |
roles.ts | 角色及其静态能力 |
entitlements.ts | 权益及其包含的能力 |
scopes.ts | OAuth 2.0 授权范围(Scope) |
upgrade.ts | OAuth 授权页的套餐升级建议,默认为空 |
affiliate.ts | 联盟推广、佣金和结算规则 |
analytics.ts | 第三方统计服务 |
notifications.ts | 外部通知通道 |
cookie-consent.ts | Cookie 同意模式、分类和第三方服务 |
header-menu.ts | 页头导航 |
footer-menu.ts | 页脚导航 |
ads.ts | 广告服务的浏览器端配置 |
应用启动时,会使用 src/libs/config/schemas/ 中的 Zod Schema 校验配置。TypeScript 类型检查可以发现字段名和类型错误;Zod 还会检查邮箱格式、数值范围和跨文件引用等内容。
通用注意事项
- 不要随意修改配置文件的导出变量名。
src/libs/config/client.ts和src/libs/config/index.ts会直接导入这些变量,改名后必须同步修改加载代码。 base.ts、i18n.ts、scopes.ts、ads.ts和analytics.ts会进入客户端配置,所有字段都应按公开信息处理。其他配置也会提交到仓库,同样不能保存密钥。- 配置之间存在引用关系。角色引用能力,产品引用角色和权益,联盟推广引用产品与套餐,升级建议引用 OAuth 授权范围(Scope);改名或删除前要搜索整个项目,不能只改定义处。
- TypeScript 和 Zod 无法确认外部资源一定存在。Stripe Price ID、Cloudflare Binding、邮件域名和第三方服务账号仍需到对应平台核对。
- 不要把环境差异硬编码到配置文件。域名、密钥以及开发、预览、生产环境不同的值,应放在环境变量、Cloudflare Secret 或相应的部署配置中。
- 修改默认数组或对象时要注意顺序。有些页面会按配置顺序展示菜单、产品和选项;即使类型不报错,调换顺序也可能改变用户看到的结果。