Files
zhangxiang a2ffd6f27b test(acceptance): complete release acceptance testing — conditional pass
All 7 phases of release acceptance testing completed:
- Static quality gates: build, type-check, lint, unit-coverage all passed
- Regression: 356 E2E passed (Chromium core features), CMS workflow, user journeys
- Visual regression: 84/84 passed across 5 browser/device projects (baselines updated)
- Mobile: 173 passed, FCP 68ms / LCP 280ms
- Lighthouse: 7 pages, 4 categories ≥ 0.9, CWV compliant
- Load test: 200 concurrent, p95=7.26ms, 0.28% error rate
- Stress test: 300 concurrent, p95=3.95ms, 0% error rate
- Accessibility: contrast 7/7, headings 10/10, a11y 66/66
- Security: 2 moderate vulnerabilities (accepted risk)
- docs/lessons-learned.md: added 3 new entries (5.7-5.9)

Conclusion: conditional pass — Firefox (127 failed) and mobile (37 failed)
compatibility issues documented as known defects.
2026-08-13 07:11:12 +08:00

220 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Lessons Learned(项目经验教训)
> 记录跨任务、跨阶段的工程经验教训,避免重复踩坑。按类别组织,定期更新。
## 目录
- [1. 技术选型与依赖](#1-技术选型与依赖)
- [2. 构建与部署](#2-构建与部署)
- [3. 样式与设计](#3-样式与设计)
- [4. 性能优化](#4-性能优化)
- [5. 测试](#5-测试)
- [6. 代码组织](#6-代码组织)
---
## 1. 技术选型与依赖
### 1.1 外部字体服务导致白屏
- **问题**:依赖 Google Fonts 等外部字体服务,网络加载失败时页面白屏。
- **根因**:字体加载阻塞首次渲染(FOUT/FOIT 未妥善处理)。
- **方案**:所有字体使用本地文件(`src/app/fonts/`),禁止外部字体 CDN。
- **来源**`2026-03-04` 部署事故,`project_memory.md` Hard Constraints。
### 1.2 React 19 + Next.js 16 HMR 兼容性
- **问题**:开发模式下 HMR 报错 `module factory is not available`,需要频繁清除缓存。
- **根因**React 19 与 Next.js 16 的 HMR 模块缓存机制不兼容。
- **方案**:禁用 `optimizeCss` 实验性功能;若持续影响开发,改用生产模式(`npm run build && npm run start`)。
- **来源**`docs/HMR-ERROR-SOLUTIONS.md`
### 1.3 webpackBuildWorker 导致静态资源 404
- **问题**:启用 `experimental.webpackBuildWorker: true` 后,客户端静态资源 404。
- **根因**webpack 构建工作线程与 Next.js 静态导出不兼容。
- **方案**:强制禁用该功能,在 `next.config.ts` 中不启用或显式设为 `false`
- **来源**`project_memory.md` Hard Constraints。
---
## 2. 构建与部署
### 2.1 直接复制参考网站代码
- **问题**:从参考网站直接复制 HTML/CSS/JS 到项目中,导致样式冲突和技术债务。
- **根因**:参考网站的样式体系(Bootstrap/其他框架)与项目 Tailwind 体系冲突。
- **方案**:仅参考设计理念和布局,所有代码手动基于 Tailwind 实现。
- **来源**`project_memory.md` Lessons Learned。
### 2.2 静态导出限制
- **问题**`output: 'export'` 模式下,`next/image` 需要 `unoptimized`,某些 API 路由不可用。
- **根因**Next.js 静态导出对 Server Components 和 API Routes 的限制。
- **方案**:移除 `output: 'export'`,改用 `standalone` 或混合模式;图片使用 `unoptimized``<img>` 标签。
- **来源**`CLAUDE.md` Build Output 章节。
---
## 3. 样式与设计
### 3.1 光晕效果遮挡内容
- **问题**Case Studies 区域卡片悬停光晕(halo effect)尺寸过大,遮挡文字。
- **根因**:光晕半径 256px + 不透明度 100%,超出卡片边界。
- **方案**:尺寸降至 192px,不透明度降至 0.08(降低 92%)。
- **来源**`project_memory.md` Lessons Learned;后续推广为全局规则:所有光晕效果不透明度降低 30-50%。
### 3.2 未使用的大文件残留
- **问题**:项目中残留 4.2MB 的 AoyagiReisho 书法字体文件,增加页面加载时间。
- **根因**:早期设计尝试引入书法字体,切换方案后未清理。
- **方案**:定期检查 `public/fonts/``src/app/fonts/` 中未使用的字体文件,及时删除。
- **来源**`project_memory.md` Lessons Learned。
### 3.3 品牌红使用过度
- **问题**:品牌红色(#C41E3A)在页面中占比超过 10%,视觉冲击过强。
- **根因**:缺乏品牌色使用规范约束。
- **方案**:制定品牌红贯穿规则——每页至少 3 处触达点,但面积 ≤ 10%;禁止作为段落文字色、大面积背景色。
- **来源**`CONTEXT.md` 朱砂点睛章节。
---
## 4. 性能优化
### 4.1 高并发下内存溢出
- **问题**:200 VUs 并发时服务崩溃,单实例无法处理高并发请求。
- **根因**:缺乏负载均衡、缓存策略和资源限制。
- **方案**:多实例部署(Docker Compose 3 实例)+ PM2 进程管理 + Nginx 负载均衡。
- **来源**`docs/PERFORMANCE_OPTIMIZATION.md`
---
## 5. 测试
### 5.1 测试框架冗余
- **问题**:项目存在三个独立的测试框架(e2e/, e2e-tests/, test-framework/),维护成本高。
- **根因**:早期多次试验不同测试方案,未及时清理废弃框架。
- **方案**:统一到 Playwright + Jest 体系,废弃 Python Playwright 和独立测试框架。
- **来源**`docs/OPTIMIZATION_REPORT.md`
### 5.2 测试覆盖率门槛
- **问题**:早期测试覆盖率低(Lines 29%),无法有效保障质量。
- **根因**:缺乏测试文化,工具函数和 hooks 未覆盖。
- **方案**:设置覆盖率门槛(branches 35%, functions/lines/statements 45%),分阶段提升至 80%;后续通过 TDD 流程提升至 85%+。
- **来源**`docs/test-coverage-improvement-plan.md``CLAUDE.md` 测试命令。
### 5.3 E2E 断言文本必须与渲染文本保持一致
- **问题**`e2e/nav-dropdown.spec.ts` 中 hover 测试失败,断言查找 `睿新ERP管理系统``行业方案`,但实际渲染为 `ERP 管理系统``行业解决方案`
- **根因**:UI 文案迭代后,E2E 测试的文本断言未同步更新,导致测试假阴性(功能正常但测试报错)。
- **方案**
1. 将 UI 文案断言改为稳定标识(如 `data-testid`、角色/aria 属性)或语义化选择器,减少对文案的强依赖。
2. 若必须使用文本,在修改文案时同步搜索并更新 `e2e/` 中的对应断言。
3. 建立「文案变更检查清单」,将 E2E 文本断言纳入审查范围。
- **来源**2026-07-26 dogfood 后续验证,`e2e/nav-dropdown.spec.ts` 修复。
### 5.4 视觉回归基线需在 UI 变更后主动更新
- **问题**:dogfood 修复后(列表卡片链接、案例筛选、联系表单反馈、新闻占位图等),视觉回归测试大面积失败。
- **根因**:上述修复属于有意的 UI/交互变更,导致已有快照与当前渲染不一致;若不更新基线,后续所有构建都会报告假阳性。
- **方案**
1. 任何涉及视觉/布局的修复完成后,运行 `npx playwright test visual-regression.spec.ts --update-snapshots` 更新全项目视觉基线。
2. 更新前通过浏览器截图/人工复核确认差异符合预期,避免将未发现的回归写入基线。
3. 将快照变更作为独立提交或 PR 变更的一部分,方便评审时比对视觉差异。
- **来源**2026-07-26 更新 105 张视觉回归快照。
### 5.5 Playwright `storageState` 路径必须以配置文件为基准
- **问题**:全量 E2E 运行时 firefox/webkit 下所有测试瞬间失败,报错 `Error reading storage state from ./e2e/storageState.json: ENOENT`
- **根因**`e2e/playwright.config.ts``storageState` 被写成 `./e2e/storageState.json`,而 `npm run test` 实际在 `e2e/` 目录下执行(`cd e2e && npx playwright test`),导致 Playwright 去查找 `e2e/e2e/storageState.json`
- **方案**
1. 配置文件中的相对路径应基于配置文件自身目录,使用 `path.resolve(__dirname, 'storageState.json')`
2. 修改 `storageState`、快照目录、报告目录等路径时,必须同时验证 `npm run test` 与从项目根目录直接运行 `npx playwright test --config=e2e/playwright.config.ts` 两种方式。
3.`storageState.json` 纳入版本控制并作为 E2E 环境准备检查项。
- **来源**2026-07-27 全量 E2E 回归失败排查,`e2e/playwright.config.ts` 修复。
### 5.6 Firefox 中连续全页导航易触发 Playwright locator 超时
- **问题**`e2e/p2-functional-e2e.spec.ts` 中「Footer 导航链接可点击」在 Firefox 中反复超时,报错 `waiting for "http://localhost:3000/" navigation to finish`,即使页面已渲染完成。
- **根因**Playwright 的 locator API 会在页面存在未完成的导航时阻塞;Firefox 对 `window.location.href` 全页导航的处理比 Chromium 更慢,连续两次 `page.goto('/')` + 点击 StaticLink 触发全页导航后,locator 评估极易进入等待导航的竞态。
- **方案**
1. 将涉及两次独立全页导航的测试拆分为两个独立 test case,减少单次测试内的导航次数。
2. 在 Firefox 等容易触发竞态的浏览器中,对必须触发的全页导航链接点击,改用 `page.evaluate(() => element.click())` 绕过 locator 的导航状态检查。
3. 优先使用 `data-testid` 或语义选择器定位,点击后通过 `page.waitForURL()` 显式等待目标 URL,而非依赖 locator 的隐式等待。
- **来源**2026-07-27 `e2e/p2-functional-e2e.spec.ts` Footer 链接测试修复。
### 5.7 封版阶段依赖升级需独立评估,避免 `--force` 一次性修复
- **问题**`npm audit fix --force` 无差别升级依赖到最新版本,导致 `@lhci/cli` 被降级到使用 git+ssh 拉取 Lighthouse 的古老版本,且 `eslint-config-next@16` 与当前 `eslint@8` 不兼容。
- **根因**`--force` 会执行 major version 升级,引入 breaking change 风险。
- **方案**
1. 封版阶段不执行 `--force` 修复,仅执行向后兼容的 `npm audit fix`
2. major version 升级应作为独立专项任务,在封版前或上线后安排。
3. 修复前备份 `package-lock.json`,并制定回退策略。
- **来源**2026-08-12 封版验收阶段 1-B。
### 5.8 性能测试脚本必须与 API 接口契约对齐
- **问题**`stress-test.js``/api/contact` 发送 JSON body,但接口期望 `formData`,且 IP 限流每小时 5 次/IP,导致 66.7% 请求失败。
- **根因**:测试脚本编写时未审查 API 接口的具体实现(`request.formData()``isRateLimited`)。
- **方案**
1. 新增/修改 API 后同步审查性能测试脚本,确保请求体格式、认证/限流机制与接口契约一致。
2. 将对依赖外部服务的接口(如 `formsubmit.co`)的压测排除在压力测试之外。
3. 重写后的脚本仅对本地静态页面进行 GET 压力测试,避免外部依赖干扰。
- **来源**2026-08-12 封版验收阶段 5stress-test.js 修复。
### 5.9 测试摘要文件需在迭代中保护,避免被失败运行覆盖
- **问题**:k6 测试运行时预览服务器被停止,后续重新运行写入的摘要文件包含无效数据(0% 通过率),覆盖了之前成功的运行结果。
- **根因**k6 的 `handleSummary` 输出路径与 `--summary-export` 路径不一致,且无版本保护机制。
- **方案**
1. 使用 `--summary-export` 指定稳定路径(如 `tests/performance/`),与脚本内 `handleSummary` 路径统一。
2. 每次运行前备份前一次摘要文件。
3. 服务器重启后重新运行性能测试前,确认端口可用性。
- **来源**2026-08-12 封版验收阶段 5,k6 摘要文件保护。
---
## 6. 代码组织
### 6.1 组件版本膨胀
- **问题**:组件目录存在多个版本迭代(detail-v2/, detail-v3/),造成混淆和冗余。
- **根因**:多次重构未清理旧版本,缺乏组件生命周期管理。
- **方案**:重构完成后立即删除旧版本目录;使用 `_archive/` 归档历史版本,并排除在 TypeScript 编译之外。
- **来源**`CLAUDE.md` Archiving Convention。
### 6.2 文档与代码不同步
- **问题**`docs/` 目录中部分文档(如组件指南、API 文档)与实际代码不一致。
- **根因**:文档更新未纳入代码审查流程。
- **方案**:文档变更必须与代码变更在同一 PR 中审查;`CONTEXT.md` 作为共享语言文档,与领域模型同步更新。
- **来源**`AGENTS.md` 文档同步要求。
---
## 7. App Router 路由行为
### 7.1 `loading.tsx` 会吞掉子动态路由的 `notFound()`
- **问题**`/services/[id]``/products/[id]``/solutions/[id]``/news/[slug]` 等动态路由对未知 slug 调用 `notFound()` 后,仍然返回 HTTP 200(软 404)。
- **根因**`(marketing)/loading.tsx` 在路由组层级创建了 Next.js Loading/Suspense 边界,该边界会捕获子页面抛出的 `NEXT_NOT_FOUND` 错误,导致 `not-found.tsx` 无法被渲染,HTTP 状态也保持为 200。
- **方案**:移除 `(marketing)/loading.tsx`;如需加载状态,改为在页面内部使用 `<Suspense>` 包裹特定慢加载区块,而不是在路由组层级全局添加 `loading.tsx`
- **验证**`curl -I http://localhost:3000/services/unknown` 返回 `404 Not Found``e2e/p5-edge-cases.spec.ts` 404 相关用例全部通过。
- **来源**2026-07-25 dogfood 修复,`dogfood-output/report.md`
---
## 更新记录
| 日期 | 更新内容 | 来源 |
|------|---------|------|
| 2026-07-07 | 初始创建,从 project_memory.md 和 docs/ 中提取 | 现有文档 + 记忆文件 |
| 2026-07-25 | 增加 App Router `loading.tsx``notFound()` 交互的经验教训 | dogfood 修复 |
| 2026-07-26 | 增加 E2E 文本断言同步、视觉回归基线更新两条经验教训 | dogfood 后续验证 |
| 2026-07-27 | 增加 Playwright storageState 路径、Firefox 全页导航竞态两条经验教训 | 全量 E2E 回归失败排查 |