99 * `RAW_SITE_URL` / `SITE_URL` 逻辑,完全同形。抽到这里避免两边独立 drift —— 任何
1010 * 调整(比如以后加 trailing-slash 归一、加端口清洗、换 env 名)只改这一个地方。
1111 *
12- * 关于 fallback(2026 年 Round 4 改):原实现用 `?? "https://involutionhell.com"`
13- * 做生产兜底,违反 `docs/architecture/frontend-backend-separation.md:96-103` 的
14- * "生产环境不做硬编码 fallback" 约定 —— 在 preview/staging 漏配 env 时会静默产出
15- * 指向 prod 域的 sitemap/robots,典型的"漏配变静默错地址"失败模式。
12+ * 策略(实事求是版):
13+ * 1. `NEXT_PUBLIC_SITE_URL` 显式设置 → 用它(保留 override 能力,几乎没人会用)。
14+ * 2. Vercel preview / branch deploy → `VERCEL_URL`(系统注入,每个 preview 一个临时域名)。
15+ * 3. 本地 dev / test → `http://localhost:3000`(项目里 OAuth 回调、rewrites 都按这个约定)。
16+ * 4. 其它(含 prod)→ 硬编码常量 `https://involutionhell.com`。
1617 *
17- * 新策略:
18- * - 生产 (VERCEL_ENV === "production" 或裸 NODE_ENV=production):env 缺失 → 模块加载时抛错,构建/启动失败。
19- * - Vercel preview / branch deploy:env 缺失 → 用 Vercel 系统注入的 VERCEL_URL
20- * (形如 myproject-git-branch-team.vercel.app),preview 站本来就是临时域名,不应卡 build。
21- * - 开发/测试:env 缺失 → fallback 到 http://localhost:3000(与 next start 默认端口
22- * 和项目里 OAuth 回调、rewrites 的 localhost:3000 约定一致),保留本地联调无门槛。
18+ * 为什么 prod 不要求 env:这台站 prod 域名永远是 involutionhell.com,是事实而非配置;
19+ * `docs/architecture/frontend-backend-separation.md:96-103` 反对的是 "BACKEND_URL ?? localhost"
20+ * 那种把内部接口悄悄改路线的兜底,公开站点根 URL 当代码常量更安全(漏配也不会指错地址)。
2321 */
2422
23+ /** 生产域名常量。Prod 域永远是它,不靠 env。 */
24+ const PROD_SITE_URL = "https://involutionhell.com" ;
25+
2526/**
2627 * 规范化站点 URL:
2728 * 1. 没协议头的补 `https://`
@@ -38,32 +39,27 @@ export function normalizeSiteUrl(url: string): string {
3839}
3940
4041/**
41- * 解析并校验 NEXT_PUBLIC_SITE_URL。抽成函数纯粹为了把 "prod 必须有 / dev 可 fallback"
42- * 逻辑集中在一处。模块加载时调用一次,结果赋给 SITE_URL。
42+ * 模块加载时调用一次,结果赋给 SITE_URL。优先级见文件头 docstring。
4343 */
4444function resolveSiteUrl ( ) : string {
45+ // 1. 显式 env override(罕用;保留口子方便临时调试 / staging 自定义域名)。
4546 const raw = process . env . NEXT_PUBLIC_SITE_URL ;
4647 if ( raw && raw . trim ( ) . length > 0 ) {
4748 return normalizeSiteUrl ( raw ) ;
4849 }
4950
50- // Vercel preview / branch deploy:用系统注入的 VERCEL_URL(hostname 形式,无协议头)。
51- // VERCEL_ENV 取值 "production" | "preview" | "development";只在 preview 走这条 fallback。
52- // production 故意不接受 VERCEL_URL,避免漏配 env 时静默用 *.vercel.app 域名替代真域名。
51+ // 2. Vercel preview / branch deploy:用系统注入的 VERCEL_URL。
5352 if ( process . env . VERCEL_ENV === "preview" && process . env . VERCEL_URL ) {
5453 return normalizeSiteUrl ( process . env . VERCEL_URL ) ;
5554 }
5655
57- if ( process . env . NODE_ENV === "production" ) {
58- // 故意抛错:漏配 env 时构建/启动直接失败,比静默产出指向错误域名的 sitemap 安全。
59- throw new Error (
60- "[lib/site-url] NEXT_PUBLIC_SITE_URL is required in production " +
61- "(see docs/architecture/frontend-backend-separation.md:96-103)." ,
62- ) ;
56+ // 3. 本地 dev / test。
57+ if ( process . env . NODE_ENV !== "production" ) {
58+ return "http://localhost:3000" ;
6359 }
6460
65- // dev / test:沿用项目里 localhost:3000 的约定(next start 默认端口、OAuth 回调、rewrites 都是 3000) 。
66- return "http://localhost:3000" ;
61+ // 4. Prod (含 Vercel production deploy):硬编码常量 。
62+ return PROD_SITE_URL ;
6763}
6864
6965/**
0 commit comments