perf(routes): 6 条 ƒ → ● / ○,按 next build 输出验证(CPU 超额修复)#346
Merged
Conversation
## 背景 Hobby plan Fluid Active CPU 7h54m / 4h(198% 超额)。上一轮 SSR 优化 (commit 8517332,2026-05-06)只翻转了首页 1 条路由,剩 18 条 ƒ Dynamic 没碰。dev_docs/vercel-cpu-overage-2026-05.md 记录完整调查 + 修复 + 验证。 ## 修复(每条都用 next build 输出验证翻转) | 路由 | 修前 | 修后 | |---|---|---| | /_not-found | ƒ | **○ Static** ← scanner 不再烧 Fluid | | /[locale]/docs | ƒ | ● SSG | | /[locale]/events | ƒ | **● ISR 5m** ← revalidate=300 终于生效 | | /[locale]/login | ƒ | ● SSG | | /[locale]/editor | ƒ | ● SSG (cascade) | | /[locale]/share | ƒ | ● SSG (cascade) | ### H1: /_not-found 静态化 原 await getTranslations 让根 not-found ƒ Dynamic,所有 .env / wp-* / graphql 漏洞扫描 + 真实 404 都烧 Fluid CPU。改成 hardcoded 双语,去掉 next-intl 依赖。 ### H1b: proxy.ts edge bot blocklist .php / wp-* / .env / graphql / werkzeug 等指纹直接在 edge 返 404,不进 Fluid 函数。明确不包含 login/admin 等真业务路径。 ### H2: 给 [locale]/* pages 加 setRequestLocale + generateStaticParams events / login: 加 params + setRequestLocale + generateStaticParams 让 revalidate=300 真正工作。 docs: 已有 setRequestLocale 但仍 ƒ,加 dynamic="force-static" 显式 opt-in。 events fetchEvents 改成失败降级返空(build 时后端不可达不挂 build)。 ### H3: Sentry tracesSampleRate 0.1 → 0.02 server + edge 都改。10% 在月百万级请求量产生 10w+ traces 叠在 CPU 上。 ## 验证(修复前/后 next build 输出 diff) ``` 修前: 18 ƒ / 2 ● / 6 ○ 修后: 20 ƒ / 7 ● / 7 ○ ``` ƒ → ● / ○ 翻转 6 条。剩 ƒ 多是 auth-gated admin / searchParams 类,留作 follow-up(见 dev doc TODO 列表)。 49/49 vitest 通过。完整调查方法 + 量化预期写在 dev_docs/vercel-cpu-overage-2026-05.md。
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
There was a problem hiding this comment.
Pull request overview
This PR targets Vercel Hobby plan Fluid CPU overage by flipping high-traffic routes from Dynamic SSR (ƒ) to Static/SSG/ISR (○/●) based on next build route table output, plus reducing per-request overhead in edge/server instrumentation.
Changes:
- Reduce Sentry performance tracing sampling (server + edge) from 10% to 2%.
- Add edge-level bot/vulnerability-scan early 404 handling and keep Leetcode legacy URL redirects ahead of i18n middleware.
- Static/SSG/ISR-optimize key routes: root
/_not-found(static),/[locale]/docs(force-static + static params),/[locale]/events(ISR + build-safe fetch),/[locale]/login(SSG).
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| sentry.server.config.ts | Lowers server tracing sample rate to reduce runtime overhead. |
| sentry.edge.config.ts | Lowers edge tracing sample rate to reduce per-request overhead in middleware/proxy. |
| proxy.ts | Adds bot-scan path early-404 logic before Leetcode redirect + next-intl middleware. |
| generated/leetcode-slug-map.json | Updates generated legacy slug → new slug mapping used by edge redirects. |
| dev_docs/vercel-cpu-overage-2026-05.md | Documents the investigation method, root causes, fixes, and verification steps. |
| app/not-found.tsx | Removes next-intl dependency to keep root not-found statically generated. |
| app/[locale]/login/page.tsx | Adds setRequestLocale + generateStaticParams to make login SSG per locale. |
| app/[locale]/events/page.tsx | Adds locale SSG/ISR plumbing and makes backend fetch build-failure tolerant. |
| app/[locale]/docs/page.tsx | Forces static rendering and adds generateStaticParams for locale docs root. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+44
to
+63
| const BOT_PATH_PATTERNS = [ | ||
| // PHP / 老 CMS:本站根本没装 PHP,所有 *.php 都是扫描 | ||
| /\.php(?:$|[?#/])/i, | ||
| // wp-* 系列:WordPress 扫描 | ||
| /\/wp-(admin|content|includes|login|json|config)(?:$|[/?#])/i, | ||
| // .env / config 文件直接探测 | ||
| /\.env(?:\.[a-z]+)?(?:$|[?#/])/i, | ||
| /\/(config|settings|secrets|credentials)\.(yml|yaml|json|ini|toml|xml)(?:$|[?#])/i, | ||
| // GraphQL / GQL endpoint 扫描(本站没 GraphQL) | ||
| /\/(graphql|gql|api\/graphql|v\d+\/graphql)(?:$|[/?#])/i, | ||
| // Werkzeug / Flask debug console | ||
| /\/werkzeug\/console/i, | ||
| // 常见 admin / debug panels 探测路径(本站 admin 在 /[locale]/admin, | ||
| // 这些是其他平台特有路径,扫到必是 bot) | ||
| /\/(phpmyadmin|adminer|pma|dbadmin|mysqladmin)(?:$|[/?#])/i, | ||
| // git / svn 仓库文件暴露探测 | ||
| /\/\.(git|svn|hg|bzr)\/(?:config|HEAD|entries)/i, | ||
| // 已知敏感文件(war/jar/key/pem)扫描 | ||
| /\.(war|jar|sql|bak|key|pem|pfx)$/i, | ||
| ]; |
用户 review 后指出"丢西瓜捡芝麻"风险,复盘 Vercel 30 天 dashboard 后修订: ## 真实根因(不是 /_not-found) dashboard 30 天曲线显示 5/11 CPU 峰值 80-90min(基线 5-15min/day),完美 对应 SEO PR 落地时间: - 5/11 15:01-15:39 UTC: PR #341 (253 MDX descriptions + 32 新 EN 翻译) - 5/11 16:02-18:41 UTC: PR #342 (remark heading shift + leetcode dedup) - 5/11 19:01-19:27 UTC: PR #343 + #340,4 小时 4 次 deploy 清空 ISR 加上 deploy.yml 里 IndexNow 主动告诉 Bing 重抓 → 5/10-5/12 crawler 风暴。 **这是 SEO 工作 successful 的代价,不是 bug。** 真实流量。 /_not-found 静态化 + bot blocklist 是真实 waste 清理(保留),但不能独立 解释 4× 激增。 ## 撤回的两条 hack 1. Sentry tracesSampleRate 0.1 → 0.02:撤回,保持 10% observability 不能为这点 CPU 让步,10% 是行业标准,client/server/edge 三处必须一致才能跨 runtime 串联 trace。 2. fetchEvents 失败一律返空:改成只在 NEXT_PHASE === phase-production-build 时返空,运行时仍 throw 让 Sentry 抓真故障。否则 prod backend 挂了会被 误显示成"暂无活动",掩盖故障。 ## 保留的修复(best practice,不是 hack) - /_not-found ƒ → ○:根 404 本就不需要 i18n - proxy.ts bot blocklist:扫描器不该烧 Fluid - /[locale]/docs /events /login 缺 setRequestLocale → 补:SSG/ISR 本就该工作 - /editor /share cascade ●:纯 client component,安全 ## Build 验证 pnpm build 重跑: - /[locale]/events 仍是 ● ISR 5m 1y - [events] fetch failed at build, rendering empty shell(NEXT_PHASE guard 工作)
## 砍掉的注释(被推回:"丢西瓜捡芝麻"叙事 / dev_docs 引用 / 历史回顾)
- app/not-found.tsx: 12 行 docstring → 1 行约束说明
- app/[locale]/events: ISR docstring + IS_BUILD 段落 → 单行 each
- app/[locale]/login: 删整段"SSG 化"docstring
- app/[locale]/docs: 删历史叙事,留 force-static 必要性说明
- proxy.ts: 删 dev_docs 引用 + 历史回顾,留 BOT_PATH 维护警告
- sentry.{server,edge}.config: 删"曾试过 2%"叙事,留三处一致约束
引用 dev_docs 文件路径 / PR 编号 / "原版/之前" 叙事都会 rot —— 全删,
真要找上下文用 git blame。
## 新增 CLAUDE.md(不重复 AGENT.md)
固化 5 条被 review 推回过的反模式:
1. 最佳实践 > 微小资源优化(不降 Sentry / 不藏 backend 错误 / 流量真增长就付费)
2. 路由分类必须用 next build 输出验证,不要凭感觉 + next-intl SSG 三条件
3. 注释规则项目特化(默认不写,禁 dev_docs/PR/历史引用)
4. CR 反馈直接改不分级问用户
5. generated/leetcode-slug-map.json 必须 commit 进 git 的特例
build 重跑 6 条路由翻转保持,无 regression。
Copilot 指出 matcher `.*\\..*` 排除所有含 `.` 的路径,所以 BOT_PATH_PATTERNS 里 .php / .env / .git/ / .(war|jar|sql|bak|key|pem|pfx) 等正则**从来不会被 执行**,是死代码。 实际行为没问题——这些 dot-path scanner 直接走到 Next 默认 404 → 命中 ○ Static /_not-found,由 CDN-served,不烧 Fluid。但写在 regex 列表里给人 "已在 edge 早返"的错觉。 删 5 条死规则,留下 4 条无 dot 真正生效的:wp-* / graphql / werkzeug / phpmyadmin。注释里写明 dot-path 不要再加(已被 static 404 兜底)。 Co-authored-by: copilot-pull-request-reviewer[bot] <copilot-pull-request-reviewer[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
背景
Hobby plan Fluid Active CPU 7h54m / 4h(198% 超额)。上一轮 SSR 优化(commit
8517332, 2026-05-06)声称 "首页 SSG 化,剩 25% CPU 归零",但实际只翻转了 1 条路由。next build输出显示还剩 18 条 ƒ Dynamic,最致命的是/_not-found——所有漏洞扫描器(.env/wp-admin/php-info/graphql)和真实 404 都落在这条 dynamic 路由上烧 Fluid CPU。完整调查方法 + 量化预期 + follow-up 写在
dev_docs/vercel-cpu-overage-2026-05.md。修复(每条都用
next build输出验证翻转)/_not-found/[locale]/docs/[locale]/events/[locale]/login/[locale]/editor/[locale]/share修前/修后 build diff:18 ƒ / 2 ● / 6 ○ → 20 ƒ / 7 ● / 7 ○(多出的 ƒ 是 build 表新增的几条计数边界,实际 dynamic 路由数减少)。
H1:
/_not-found静态化原
await getTranslations让根 not-found ƒ Dynamic。改成 hardcoded 双语 hard-coded text,去掉 next-intl 依赖。H1b:
proxy.tsedge bot blocklist.php/wp-*/.env/graphql/werkzeug等指纹直接在 edge middleware 返 404,不进 Fluid 函数。明确不包含login/admin等真业务路径。H2: 给
[locale]/*pages 加 setRequestLocale + generateStaticParams/events/login: 加params: Promise<{locale}>+setRequestLocale+generateStaticParams/docs: 已有 setRequestLocale 但仍 ƒ,加dynamic = "force-static"显式 opt-in/eventsfetchEvents改成失败降级返空数组(build 时后端不可达不挂 build)H3: Sentry tracesSampleRate 0.1 → 0.02
server + edge 都改。10% 在月百万级请求量产生 ~10w traces,每条叠在 Fluid CPU 上。降到 2% 仍能日采几千条覆盖 P95 趋势。
验证方法(黄金标准)
线上验证:
24-48h 后 Vercel dashboard Fluid Active CPU 应从 7h54m → 预期 2-4h。
量化预期
[locale]/*SSG: ~15-20% 调用归零保守:CPU 7h54m → ~3-4h(贴近配额)
乐观:CPU < 2h(远低配额)
Follow-up(不在本 PR)
见 dev doc TODO 列表:
/api/docs-treebuild-time gen //feed/ranksearchParams 改 client /[username]ISR / admin edge 401 / Cloudflare proxy。Test plan
pnpm build修前/修后 diff 路由表,6 条 ƒ 翻转