@bovinphang/frontend-craft 2.5.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +7 -3
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +77 -1
- package/CHANGELOG.zh-CN.md +77 -1
- package/CONTRIBUTING.md +15 -10
- package/CONTRIBUTING.zh-CN.md +15 -10
- package/README.md +69 -43
- package/README.openclaw.md +11 -9
- package/README.openclaw.zh-CN.md +11 -9
- package/README.zh-CN.md +69 -43
- package/agents/fec-typescript-reviewer.md +1 -1
- package/commands/fec-doc-sync.md +7 -6
- package/dist/bin/frontend-craft.js +30 -27
- package/docs/example-prompts.md +82 -69
- package/docs/ja-JP/README.md +110 -84
- package/docs/ko-KR/README.md +100 -74
- package/docs/project-structure.md +8 -4
- package/docs/runtimes/antigravity.md +1 -1
- package/docs/runtimes/augment.md +1 -1
- package/docs/runtimes/claude.md +16 -10
- package/docs/runtimes/claude.zh-CN.md +16 -10
- package/docs/runtimes/cline.md +1 -1
- package/docs/runtimes/codebuddy.md +1 -1
- package/docs/runtimes/codex.md +1 -1
- package/docs/runtimes/copilot.md +1 -1
- package/docs/runtimes/cursor.md +1 -1
- package/docs/runtimes/gemini.md +1 -1
- package/docs/runtimes/kilo.md +1 -1
- package/docs/runtimes/openclaw.md +1 -1
- package/docs/runtimes/opencode.md +1 -1
- package/docs/runtimes/qoder.md +1 -1
- package/docs/runtimes/trae.md +1 -1
- package/docs/runtimes/windsurf.md +1 -1
- package/docs/zh-CN/example-prompts.md +82 -69
- package/docs/zh-CN/project-structure.md +8 -4
- package/docs/zh-TW/README.md +88 -62
- package/openclaw.plugin.json +1 -1
- package/package.json +3 -3
- package/skills/eval_queries.json +179 -56
- package/skills/fec-accessibility-check/SKILL.md +1 -1
- package/skills/fec-alchemy/SKILL.md +74 -0
- package/skills/fec-alchemy/assets/absorption-plan-template.md +47 -0
- package/skills/fec-alchemy/assets/intake-template.md +55 -0
- package/skills/fec-alchemy/assets/review-checklist.md +31 -0
- package/skills/fec-alchemy/references/methodology.md +94 -0
- package/skills/fec-alchemy/references/originality-and-licensing.md +57 -0
- package/skills/fec-backend-requirements-handoff/SKILL.md +45 -0
- package/skills/fec-browser-storage/SKILL.md +1 -1
- package/skills/fec-canvas-threejs/SKILL.md +1 -1
- package/skills/fec-code-review/SKILL.md +11 -3
- package/skills/fec-data-fetching/SKILL.md +15 -15
- package/skills/fec-data-fetching/references/query-patterns.md +27 -1
- package/skills/fec-debug-framework/SKILL.md +14 -19
- package/skills/fec-debug-framework/references/report-template.md +58 -0
- package/skills/fec-doc-sync/SKILL.md +19 -17
- package/skills/fec-drawio-studio/SKILL.md +69 -0
- package/skills/fec-drawio-studio/data/THIRD_PARTY_NOTICES.md +10 -0
- package/skills/fec-drawio-studio/data/brand-icons.json +878 -0
- package/skills/fec-drawio-studio/data/shape-index.json.gz +0 -0
- package/skills/fec-drawio-studio/references/data-residency.md +27 -0
- package/skills/fec-drawio-studio/references/diagram-patterns.md +41 -0
- package/skills/fec-drawio-studio/references/layout-and-export.md +57 -0
- package/skills/fec-drawio-studio/references/troubleshooting.md +29 -0
- package/skills/fec-drawio-studio/references/xml-and-mermaid.md +54 -0
- package/skills/fec-drawio-studio/scripts/brand-symbols.mjs +99 -0
- package/skills/fec-drawio-studio/scripts/diagram-lint.mjs +143 -0
- package/skills/fec-drawio-studio/scripts/diagram-url.mjs +102 -0
- package/skills/fec-drawio-studio/scripts/layout-graph.mjs +107 -0
- package/skills/fec-drawio-studio/scripts/png-embed-fix.mjs +26 -0
- package/skills/fec-drawio-studio/scripts/scan-go-packages.mjs +36 -0
- package/skills/fec-drawio-studio/scripts/scan-js-modules.mjs +52 -0
- package/skills/fec-drawio-studio/scripts/scan-python-classes.mjs +30 -0
- package/skills/fec-drawio-studio/scripts/scan-python-modules.mjs +55 -0
- package/skills/fec-drawio-studio/scripts/scan-rust-modules.mjs +35 -0
- package/skills/fec-drawio-studio/scripts/scan-ts-modules.mjs +7 -0
- package/skills/fec-drawio-studio/scripts/shape-query.mjs +81 -0
- package/skills/fec-drawio-studio/scripts/studio-core.mjs +139 -0
- package/skills/fec-drawio-studio/styles/built-in/corporate.json +49 -0
- package/skills/fec-drawio-studio/styles/built-in/default.json +49 -0
- package/skills/fec-drawio-studio/styles/built-in/handdrawn.json +49 -0
- package/skills/fec-drawio-studio/styles/schema.json +112 -0
- package/skills/fec-e2e-testing/SKILL.md +5 -3
- package/skills/fec-e2e-testing/references/e2e-ci-reporting.md +62 -0
- package/skills/fec-e2e-testing/references/e2e-special-scenarios.md +52 -0
- package/skills/fec-e2e-testing/references/e2e-visual-regression.md +60 -0
- package/skills/fec-form-handling/SKILL.md +11 -11
- package/skills/fec-form-handling/references/advanced-form-patterns.md +34 -5
- package/skills/fec-image-generation/SKILL.md +56 -0
- package/skills/fec-image-generation/references/artifact-routing.md +80 -0
- package/skills/fec-image-generation/references/diagram-workflows.md +43 -0
- package/skills/fec-image-generation/references/png-qa-autofix.md +30 -0
- package/skills/fec-image-generation/scripts/png-qa.mjs +431 -0
- package/skills/fec-implement-from-design/SKILL.md +9 -2
- package/skills/fec-legacy-to-modern-migration/SKILL.md +29 -163
- package/skills/fec-legacy-to-modern-migration/references/migration-execution-checklist.md +110 -0
- package/skills/fec-legacy-to-modern-migration/references/migration-strategy-and-mapping.md +48 -0
- package/skills/fec-legacy-web-standard/SKILL.md +1 -1
- package/skills/fec-list-virtualization/SKILL.md +3 -3
- package/skills/fec-list-virtualization/references/virtualization-patterns.md +32 -4
- package/skills/fec-motion-interaction/SKILL.md +7 -0
- package/skills/fec-nextjs-project-standard/SKILL.md +7 -1
- package/skills/fec-performance-optimization/SKILL.md +9 -1
- package/skills/fec-performance-optimization/references/framework-performance-patterns.md +38 -0
- package/skills/fec-performance-optimization/references/report-template.md +59 -0
- package/skills/fec-pwa-implementation/SKILL.md +3 -4
- package/skills/fec-react-project-standard/SKILL.md +12 -4
- package/skills/fec-react-project-standard/references/react-performance-patterns.md +35 -0
- package/skills/fec-react-project-standard/references/react-project-structure.md +197 -0
- package/skills/fec-react-project-standard/references/react-quality-patterns.md +131 -0
- package/skills/fec-react-project-standard/references/react-runtime-patterns.md +293 -0
- package/skills/fec-refactor-clean/SKILL.md +4 -1
- package/skills/fec-refactor-clean/references/report-template.md +42 -0
- package/skills/fec-responsive-layout/references/responsive-layout-patterns.md +11 -0
- package/skills/fec-security-review/SKILL.md +3 -3
- package/skills/fec-source-driven-development/SKILL.md +26 -0
- package/skills/fec-state-management/SKILL.md +1 -1
- package/skills/fec-storybook-component-doc/SKILL.md +2 -2
- package/skills/fec-tailwind-design-system/references/tailwind-system-patterns.md +5 -1
- package/skills/fec-typescript-project-standard/SKILL.md +54 -0
- package/skills/{fec-typescript-type-safety → fec-typescript-project-standard}/references/type-safety-patterns.md +1 -1
- package/skills/{fec-typescript-type-safety/SKILL.md → fec-typescript-project-standard/references/type-safety.md} +1 -10
- package/skills/fec-ui-design/SKILL.md +26 -8
- package/skills/fec-ui-design/data/style-archetypes.json +40 -0
- package/skills/fec-ui-design/data/ux-quality-rules.json +35 -0
- package/skills/fec-ui-design/references/design-intelligence.md +66 -6
- package/skills/fec-ui-design/references/pre-delivery-checklist.md +6 -0
- package/skills/fec-ui-design/scripts/design-system.mjs +119 -1
- package/skills/fec-validation-fix/SKILL.md +5 -2
- package/skills/fec-validation-fix/references/report-template.md +43 -0
- package/skills/fec-vue3-project-standard/SKILL.md +12 -3
- package/skills/fec-vue3-project-standard/references/vue3-composables-routing.md +163 -0
- package/skills/fec-vue3-project-standard/references/vue3-performance-patterns.md +13 -0
- package/skills/fec-vue3-project-standard/references/vue3-project-structure.md +177 -0
- package/skills/fec-vue3-project-standard/references/vue3-state-api-quality.md +216 -0
- package/skills/fec-web-video-presentation/SKILL.md +61 -0
- package/skills/fec-web-video-presentation/data/starter-themes.json +59 -0
- package/skills/fec-web-video-presentation/references/chapter-craft.md +37 -0
- package/skills/fec-web-video-presentation/references/content-plan.md +38 -0
- package/skills/fec-web-video-presentation/references/recording-and-audio.md +33 -0
- package/skills/fec-web-video-presentation/references/theme-system.md +36 -0
- package/skills/fec-web-video-presentation/scripts/create-video-presentation.mjs +430 -0
- package/skills/fec-web-workers/SKILL.md +3 -4
- package/skills/metadata.json +381 -168
- package/skills/relations.json +136 -25
- package/templates/shared/rules/fec-ci-cd.md +20 -108
- package/templates/shared/rules/fec-design-system.md +47 -223
- package/templates/shared/rules/fec-error-handling.md +35 -179
- package/templates/shared/rules/fec-i18n.md +43 -91
- package/templates/shared/rules/fec-refactoring.md +4 -0
- package/templates/shared/rules/fec-rendering-patterns.md +28 -171
- package/templates/shared/rules/fec-responsive-design.md +34 -211
- package/templates/shared/rules/fec-state-management.md +41 -144
- package/templates/shared/rules/fec-typescript.md +47 -290
- package/skills/fec-e2e-testing/references/e2e-advanced.md +0 -176
- package/skills/fec-react-project-standard/references/react-project-details.md +0 -642
- package/skills/fec-vue3-project-standard/references/vue3-project-details.md +0 -547
|
@@ -1,200 +1,56 @@
|
|
|
1
1
|
# 错误处理规范
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
| 层级 | 错误类型 | 处理方式 |
|
|
6
|
-
|------|----------|----------|
|
|
7
|
-
| 全局 | 未捕获异常、Promise rejection | 全局捕获 + 上报 + 降级 UI |
|
|
8
|
-
| 路由/页面 | 页面级组件渲染错误 | Error Boundary + 页面级降级 |
|
|
9
|
-
| 模块 | 功能模块内的运行时错误 | Error Boundary + 模块级降级 |
|
|
10
|
-
| 组件 | 数据请求失败、操作失败 | 用户提示 + 重试机制 |
|
|
11
|
-
| 表单 | 校验失败 | 字段级错误提示 |
|
|
12
|
-
|
|
13
|
-
## 全局错误捕获
|
|
14
|
-
|
|
15
|
-
### React
|
|
16
|
-
|
|
17
|
-
```tsx
|
|
18
|
-
// main.tsx — 未捕获的 Promise
|
|
19
|
-
window.addEventListener("unhandledrejection", (event) => {
|
|
20
|
-
reportError(event.reason);
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
// 推荐:react-error-boundary,业务侧保持函数组件 + FallbackComponent
|
|
24
|
-
import { ErrorBoundary } from "react-error-boundary";
|
|
25
|
-
|
|
26
|
-
function GlobalErrorFallback({
|
|
27
|
-
error,
|
|
28
|
-
resetErrorBoundary,
|
|
29
|
-
}: {
|
|
30
|
-
error: Error;
|
|
31
|
-
resetErrorBoundary: () => void;
|
|
32
|
-
}) {
|
|
33
|
-
return (
|
|
34
|
-
<div role="alert">
|
|
35
|
-
<p>页面出现异常</p>
|
|
36
|
-
<button type="button" onClick={resetErrorBoundary}>
|
|
37
|
-
重试
|
|
38
|
-
</button>
|
|
39
|
-
</div>
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// 根节点包裹示例(root 来自 createRoot(document.getElementById("root")!) 等)
|
|
44
|
-
root.render(
|
|
45
|
-
<ErrorBoundary
|
|
46
|
-
FallbackComponent={GlobalErrorFallback}
|
|
47
|
-
onError={(error, info) => {
|
|
48
|
-
reportError(error, { componentStack: info.componentStack });
|
|
49
|
-
}}
|
|
50
|
-
>
|
|
51
|
-
<App />
|
|
52
|
-
</ErrorBoundary>,
|
|
53
|
-
);
|
|
54
|
-
```
|
|
3
|
+
本文件约定前端错误处理的常驻边界。React/Vue 组件边界细节交给对应框架 skill,API 错误映射和鉴权刷新交给 `fec-api-integration`,安全敏感错误交给 `fec-security-review`。
|
|
55
4
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
// main.ts
|
|
60
|
-
app.config.errorHandler = (err, instance, info) => {
|
|
61
|
-
reportError(err, {
|
|
62
|
-
component: instance?.$options.name,
|
|
63
|
-
lifecycleHook: info,
|
|
64
|
-
});
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
window.addEventListener('unhandledrejection', (event) => {
|
|
68
|
-
reportError(event.reason);
|
|
69
|
-
});
|
|
70
|
-
```
|
|
5
|
+
## 错误分层
|
|
71
6
|
|
|
72
|
-
|
|
7
|
+
| 层级 | 错误类型 | 默认处理 |
|
|
8
|
+
| ---- | -------- | -------- |
|
|
9
|
+
| 全局 | 未捕获异常、Promise rejection | 捕获、上报、全局降级 UI |
|
|
10
|
+
| 路由 / 页面 | 页面级渲染异常 | Error Boundary / 框架错误边界 + 页面级降级 |
|
|
11
|
+
| 模块 | 功能模块运行时异常 | 模块级边界 + 局部降级 |
|
|
12
|
+
| 组件 / 请求 | 数据请求失败、操作失败 | 用户可理解提示 + 可恢复动作 |
|
|
13
|
+
| 表单 | 校验失败 | 字段级错误提示和修正入口 |
|
|
73
14
|
|
|
74
|
-
|
|
75
|
-
App (GlobalErrorBoundary)
|
|
76
|
-
├── Header
|
|
77
|
-
├── Main
|
|
78
|
-
│ ├── Sidebar (ErrorBoundary)
|
|
79
|
-
│ └── Content
|
|
80
|
-
│ ├── Dashboard (ErrorBoundary)
|
|
81
|
-
│ └── UserList (ErrorBoundary)
|
|
82
|
-
└── Footer
|
|
83
|
-
```
|
|
15
|
+
## 全局与模块边界
|
|
84
16
|
|
|
85
|
-
-
|
|
86
|
-
-
|
|
87
|
-
-
|
|
17
|
+
- 应在应用入口注册未捕获异常和 Promise rejection 监听,并接入项目错误上报平台。
|
|
18
|
+
- React 使用项目统一的 Error Boundary 方案;业务组件保持函数式,不新增手写类组件边界。
|
|
19
|
+
- Vue 使用项目统一的 `app.config.errorHandler`、`onErrorCaptured` 或框架级错误边界。
|
|
20
|
+
- 独立功能模块应有局部降级能力,模块崩溃不应导致整个页面白屏。
|
|
21
|
+
- Error Boundary 处理渲染异常;普通 API 失败应落到 loading/error/empty/data 状态和可恢复操作。
|
|
88
22
|
|
|
89
23
|
## API 错误处理
|
|
90
24
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
code: string;
|
|
96
|
-
message: string;
|
|
97
|
-
details?: Record<string, string[]>;
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
### 错误分级处理
|
|
102
|
-
|
|
103
|
-
```typescript
|
|
104
|
-
function handleApiError(error: ApiError) {
|
|
105
|
-
switch (error.code) {
|
|
106
|
-
case 'UNAUTHORIZED':
|
|
107
|
-
redirectToLogin();
|
|
108
|
-
break;
|
|
109
|
-
case 'FORBIDDEN':
|
|
110
|
-
showToast('无权限执行此操作');
|
|
111
|
-
break;
|
|
112
|
-
case 'VALIDATION_ERROR':
|
|
113
|
-
return error.details; // 返回给表单显示字段级错误
|
|
114
|
-
case 'NETWORK_ERROR':
|
|
115
|
-
showToast('网络异常,请检查网络连接');
|
|
116
|
-
break;
|
|
117
|
-
default:
|
|
118
|
-
showToast(error.message || '操作失败,请稍后重试');
|
|
119
|
-
reportError(error);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### 请求拦截器
|
|
125
|
-
|
|
126
|
-
在 axios / fetch 封装层统一处理:
|
|
127
|
-
|
|
128
|
-
- 401 → 跳转登录(或刷新 token)
|
|
129
|
-
- 403 → 权限不足提示
|
|
130
|
-
- 500 → 通用错误提示 + 上报
|
|
131
|
-
- 网络超时 → 超时提示 + 可选重试
|
|
132
|
-
|
|
133
|
-
### 用户可恢复动作
|
|
134
|
-
|
|
135
|
-
每类错误都应对应明确下一步:
|
|
136
|
-
|
|
137
|
-
- `401`:重新登录或静默刷新失败后跳转登录
|
|
138
|
-
- `403`:说明无权限并提供返回或申请权限路径
|
|
139
|
-
- `404`:返回列表、重新搜索或创建入口
|
|
140
|
-
- `409`:展示冲突对象和刷新/覆盖/取消选择
|
|
141
|
-
- `422`:字段级错误回填表单
|
|
142
|
-
- `429`:告知等待时间或稍后重试
|
|
143
|
-
- `5xx` / 网络错误:重试、离线提示或联系支持
|
|
144
|
-
|
|
145
|
-
UI 可显示 request id / trace id 方便支持排查,但不得暴露内部堆栈、SQL、服务名或敏感字段。
|
|
25
|
+
- 请求层统一归一错误形状,组件不直接解析后端异常、token refresh 或重试策略。
|
|
26
|
+
- 每类错误都应对应明确下一步:重试、重新登录、修改输入、返回上级、刷新冲突数据、联系支持或稍后再试。
|
|
27
|
+
- `401`、`403`、`404`、`409`、`422`、`429`、`5xx` 和网络错误应有可区分的用户提示和日志语义。
|
|
28
|
+
- UI 可显示 request id / trace id 方便支持排查,但不得暴露内部堆栈、SQL、服务名、密钥或敏感字段。
|
|
146
29
|
|
|
147
30
|
## 用户体验
|
|
148
31
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
1. **Loading** — 骨架屏或 spinner
|
|
154
|
-
2. **Error** — 错误描述 + 重试按钮
|
|
155
|
-
3. **Empty** — 空状态引导
|
|
156
|
-
4. **Success** — 正常数据展示
|
|
157
|
-
|
|
158
|
-
### 降级 UI 设计
|
|
159
|
-
|
|
160
|
-
- 全局级:显示友好的错误页面,提供"返回首页"和"重试"
|
|
161
|
-
- 模块级:显示该模块的占位错误卡片,页面其他部分正常
|
|
162
|
-
- 操作级:Toast 提示 + 具体的下一步指引
|
|
163
|
-
|
|
164
|
-
### 重试策略
|
|
165
|
-
|
|
166
|
-
- 用户手动重试(按钮)
|
|
167
|
-
- 自动重试(指数退避,最多 3 次)
|
|
168
|
-
- 数据请求库的内置重试(React Query retries 等)
|
|
32
|
+
- 每个数据展示区域处理 Loading、Error、Empty、Success 四种状态。
|
|
33
|
+
- 全局级错误页提供返回首页、刷新或重试路径;模块级降级只影响该模块;操作级错误给出下一步。
|
|
34
|
+
- 重试策略要克制:用户手动重试优先,自动重试需有上限、退避和停止条件。
|
|
35
|
+
- 错误提示应保留用户已输入内容,避免因失败丢失表单或上下文。
|
|
169
36
|
|
|
170
37
|
## 错误上报
|
|
171
38
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
上报内容应包含:
|
|
175
|
-
|
|
176
|
-
- 错误堆栈
|
|
177
|
-
- 用户 ID / 会话 ID
|
|
178
|
-
- 当前页面 URL
|
|
179
|
-
- 浏览器/设备信息
|
|
180
|
-
- 复现上下文(操作步骤、请求参数)
|
|
39
|
+
上报内容应包含错误堆栈、页面 URL、浏览器/设备信息、用户或会话标识、操作上下文、请求标识和版本信息。上报前清理 token、密码、个人敏感字段和大体积 payload。
|
|
181
40
|
|
|
182
41
|
## 反模式
|
|
183
42
|
|
|
184
|
-
- 空 catch
|
|
185
|
-
- 所有错误统一用 `alert()`
|
|
186
|
-
- 接口失败时 UI
|
|
187
|
-
- Error Boundary
|
|
188
|
-
-
|
|
189
|
-
-
|
|
190
|
-
- 用 Error Boundary 承接普通 API 错误,导致用户无法理解或恢复
|
|
191
|
-
- 把后端原始异常、内部错误码或敏感字段直接展示给用户
|
|
43
|
+
- 空 `catch` 块吞掉错误。
|
|
44
|
+
- 所有错误统一用 `alert()` 或一个模糊 toast。
|
|
45
|
+
- 接口失败时 UI 无反馈,或把后端原始异常直接展示给用户。
|
|
46
|
+
- Error Boundary 没有重试或返回路径。
|
|
47
|
+
- 在组件中到处写重复 `try/catch`,而不是统一封装请求边界。
|
|
48
|
+
- 用 Error Boundary 承接普通 API 错误,导致用户无法理解或恢复。
|
|
192
49
|
|
|
193
50
|
## 检查清单
|
|
194
51
|
|
|
195
|
-
- [ ]
|
|
196
|
-
- [ ]
|
|
197
|
-
- [ ] API
|
|
198
|
-
- [ ]
|
|
199
|
-
- [ ]
|
|
200
|
-
- [ ] 错误信息上报到监控平台
|
|
52
|
+
- [ ] 全局未捕获异常和 Promise rejection 已监听。
|
|
53
|
+
- [ ] 关键页面或模块有框架错误边界和局部降级 UI。
|
|
54
|
+
- [ ] API 请求有统一错误归一、分级处理和可恢复动作。
|
|
55
|
+
- [ ] 数据区域覆盖 Loading / Error / Empty / Success。
|
|
56
|
+
- [ ] 错误上报包含足够定位信息且不泄露敏感数据。
|
|
@@ -1,112 +1,64 @@
|
|
|
1
1
|
# 国际化 (i18n) 规则
|
|
2
2
|
|
|
3
|
-
凡是涉及用户可见文案、提示信息、表单标签、错误消息或 UI
|
|
4
|
-
|
|
5
|
-
<!-- 请根据项目实际 i18n 方案修改 locales 路径、库与 key 前缀 -->
|
|
3
|
+
凡是涉及用户可见文案、提示信息、表单标签、错误消息或 UI 文本时,都应用本文件。请根据项目实际 i18n 方案修改 locales 路径、库与 key 前缀。
|
|
6
4
|
|
|
7
5
|
## 适用范围
|
|
8
6
|
|
|
9
|
-
-
|
|
10
|
-
- **遗留 HTML/JS
|
|
7
|
+
- **现代栈(React / Vue / Next / Nuxt 等)**:新增或修改的用户可见文案必须走项目 i18n 方案。
|
|
8
|
+
- **遗留 HTML/JS、渐进迁移或新旧并存**:新代码路径仍须满足核心原则;遗留层遵守迁移约束,避免扩大硬编码和混乱 key。
|
|
11
9
|
|
|
12
|
-
下文用
|
|
10
|
+
下文用 `src/locales/` 指代项目实际文案资源目录,请按仓库约定替换。
|
|
13
11
|
|
|
14
12
|
## 核心原则
|
|
15
13
|
|
|
16
|
-
-
|
|
17
|
-
- i18n key
|
|
18
|
-
- 相同语义的文案复用同一个 key
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
### 命名约定
|
|
23
|
-
|
|
24
|
-
```
|
|
25
|
-
common.confirm → 通用确认
|
|
26
|
-
common.cancel → 通用取消
|
|
27
|
-
user.login.title → 用户登录标题
|
|
28
|
-
order.list.empty → 订单列表空状态
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### 分类
|
|
14
|
+
- 新应用代码中的用户可见文案须使用 i18n,禁止硬编码中文或英文字符串。
|
|
15
|
+
- i18n key 按模块组织,使用点分命名,例如 `order.list.empty`。
|
|
16
|
+
- 相同语义的文案复用同一个 key,避免重复定义。
|
|
17
|
+
- 变量、复数、日期、数字和货币使用 i18n 能力格式化,不用字符串拼接。
|
|
18
|
+
- 修改文案前先检索现有资源,优先复用准确 key。
|
|
32
19
|
|
|
33
|
-
|
|
34
|
-
- `module.component.*` — 模块级文案
|
|
35
|
-
- `validation.*` — 表单校验提示
|
|
36
|
-
- `error.*` — 错误信息
|
|
20
|
+
## 文案与资源规范
|
|
37
21
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
22
|
+
- `common.*` 用于跨模块通用文案,例如确认、取消、提交、加载中。
|
|
23
|
+
- `module.component.*` 用于模块级文案。
|
|
24
|
+
- `validation.*` 用于表单校验提示。
|
|
25
|
+
- `error.*` 用于错误信息。
|
|
26
|
+
- 每种自然语言对应独立资源文件,禁止多种语言混写在同一文件或同一顶层多语言对象内。
|
|
27
|
+
- 文案文件须以 UTF-8 保存;团队有约定时优先 UTF-8 无 BOM,避免中文、日文等非 ASCII 文案乱码。
|
|
28
|
+
- 新增 key 时,同步更新当前功能应覆盖的主要语言文件;若某语言暂缺,必须显式记录缺口。
|
|
42
29
|
|
|
43
30
|
## 遗留代码与迁移场景
|
|
44
31
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
-
|
|
48
|
-
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
- **改动前检索**:改提示、错误、按钮、表单标签前,先在 `src/locales/`(或项目约定目录)中搜索是否已有对应文案。
|
|
52
|
-
- **Key 与文案治理**:
|
|
53
|
-
- key 按**页面 / 模块 / 语义**组织,避免继续沿用历史缩写或无意义分段。
|
|
54
|
-
- 先按当前界面真实含义定 key,再写各语言译文。
|
|
55
|
-
- 旧文案若仅「能用但不准」,优先**重命名 key 并重写译文**,不为劣质命名长期保留并行兼容。
|
|
56
|
-
- 仅当某旧 key 已成为**对外契约**(后端、埋点、外部文档、第三方集成等固定引用)时,才引入映射层或别名过渡;否则不把历史包袱复制进新结构。
|
|
57
|
-
|
|
58
|
-
## 实现指导
|
|
59
|
-
|
|
60
|
-
### Vue(vue-i18n)
|
|
61
|
-
|
|
62
|
-
```vue
|
|
63
|
-
<template>
|
|
64
|
-
<!-- 正确 -->
|
|
65
|
-
<span>{{ $t('order.status.pending') }}</span>
|
|
66
|
-
<!-- 错误:硬编码 -->
|
|
67
|
-
<span>待处理</span>
|
|
68
|
-
</template>
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### React(react-intl / react-i18next)
|
|
72
|
-
|
|
73
|
-
```tsx
|
|
74
|
-
// 正确
|
|
75
|
-
<FormattedMessage id="order.status.pending" />
|
|
76
|
-
// 或
|
|
77
|
-
const { t } = useTranslation();
|
|
78
|
-
<span>{t('order.status.pending')}</span>
|
|
79
|
-
|
|
80
|
-
// 错误:硬编码
|
|
81
|
-
<span>待处理</span>
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
## 检查清单
|
|
32
|
+
- 遗留 HTML 或 JS 中不新增用户可见硬编码,除非该段为纯静态展示且仓库尚无可接入 i18n 路径。
|
|
33
|
+
- React / Vue 等新代码路径新增提示、错误、按钮、表单标签时,必须走 i18n。
|
|
34
|
+
- 新增子应用或模块时,与现有语言文件结构、命名空间和懒加载策略一致。
|
|
35
|
+
- key 按页面、模块和语义组织,避免继续沿用历史缩写或无意义分段。
|
|
36
|
+
- 旧 key 若仅“能用但不准”,优先重命名 key 并重写译文,不长期保留并行兼容。
|
|
37
|
+
- 仅当旧 key 已成为对外契约(后端、埋点、外部文档、第三方集成等固定引用)时,才引入映射层或别名过渡。
|
|
85
38
|
|
|
86
|
-
|
|
39
|
+
## 实现约束
|
|
87
40
|
|
|
88
|
-
-
|
|
89
|
-
-
|
|
90
|
-
-
|
|
91
|
-
-
|
|
92
|
-
- [ ] 包含变量的文案使用插值而非拼接
|
|
93
|
-
- [ ] 复数形式使用 i18n 复数规则而非条件判断
|
|
94
|
-
- [ ] 日期、数字、货币使用 i18n 格式化
|
|
41
|
+
- Vue、React、Next、Nuxt 的具体调用方式以项目现有 i18n 库为准,例如 `vue-i18n`、`react-intl`、`react-i18next` 或框架内置方案。
|
|
42
|
+
- 组件中不要直接写用户可见硬编码;测试可通过 key 或最终文案断言,但应避免与翻译细节过度耦合。
|
|
43
|
+
- 懒加载语言包时,loading、fallback 和缺失 key 行为要可预期。
|
|
44
|
+
- 错误、表单和空状态文案要能表达用户下一步,不只翻译技术错误。
|
|
95
45
|
|
|
96
|
-
|
|
46
|
+
## 检查清单
|
|
97
47
|
|
|
98
|
-
- [ ]
|
|
99
|
-
- [ ]
|
|
100
|
-
- [ ]
|
|
101
|
-
- [ ]
|
|
48
|
+
- [ ] 所有新增用户可见文案使用 i18n key。
|
|
49
|
+
- [ ] 新增 key 已添加到所有应覆盖语言文件,且各语言分文件维护。
|
|
50
|
+
- [ ] 语言资源文件为 UTF-8,打开无乱码。
|
|
51
|
+
- [ ] key 命名符合模块、组件、用途约定,并复用已有语义。
|
|
52
|
+
- [ ] 插值、复数、日期、数字、货币使用 i18n 格式化。
|
|
53
|
+
- [ ] 迁移或混合栈中未扩大用户可见硬编码。
|
|
54
|
+
- [ ] 新代码未破坏现有命名空间、加载方式和子应用边界。
|
|
102
55
|
|
|
103
56
|
## 反模式
|
|
104
57
|
|
|
105
|
-
- 在模板或 JSX
|
|
106
|
-
- 使用字符串拼接代替 i18n
|
|
107
|
-
- 在 JS/TS
|
|
108
|
-
-
|
|
109
|
-
-
|
|
110
|
-
- 用非 UTF-8
|
|
111
|
-
- 为迁就历史缩写或劣质命名长期保留多套并行 key
|
|
112
|
-
- 在非契约场景下继续沿用无意义旧 key,把混乱结构复制到新模块
|
|
58
|
+
- 在模板或 JSX 中直接写用户可见中文或英文字符串。
|
|
59
|
+
- 使用字符串拼接代替 i18n 插值。
|
|
60
|
+
- 在 JS/TS 逻辑中硬编码 toast、错误或确认文案。
|
|
61
|
+
- 不同模块为相同含义创建不同 key。
|
|
62
|
+
- 多语言混写导致 diff、评审和按需加载困难。
|
|
63
|
+
- 用非 UTF-8 或错误编码保存文案文件。
|
|
64
|
+
- 为迁就历史缩写或劣质命名长期保留多套并行 key。
|
|
@@ -28,6 +28,10 @@
|
|
|
28
28
|
- 图片使用原项目资源,无内联 SVG;若原项目用 iconfont/IcoMoon 则继续使用
|
|
29
29
|
- 样式参考原项目效果但不照搬 CSS,优先 flex 布局,无内联样式
|
|
30
30
|
- 对公共 API、路由、事件、埋点、权限、缓存和错误状态建立行为清单,重构前后逐项核对
|
|
31
|
+
- 涉及页面、组件、路由、表单、弹窗、导航或关键用户流程的迁移,必须使用 Playwright 或同等真实浏览器验证方式对关键路径做对比验证
|
|
32
|
+
- 对视觉敏感页面,应补充截图对比或人工截图验收;动态内容、动画、字体和环境差异需明确屏蔽、稳定化或说明
|
|
33
|
+
- 对纯逻辑、类型、构建或无 UI 的迁移,不强制 Playwright,应选择更贴近风险的验证层:type-check、unit test、component test、build 或 lint
|
|
34
|
+
- 验证目标不是像素级完全一致,而是确认业务功能无缺失、关键交互等价、主要视觉布局无非预期偏差,并且代码比旧实现更清晰、可维护
|
|
31
35
|
|
|
32
36
|
## 死代码清理
|
|
33
37
|
|
|
@@ -1,183 +1,40 @@
|
|
|
1
1
|
# 渲染模式选型
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
当项目需要选择或评估 CSR / SSR / SSG / ISR / RSC 时,参考本文件。本文只保留跨框架决策约束;Next.js App Router 细节交给 `fec-nextjs-project-standard`,Nuxt 细节交给 `fec-nuxt-project-standard`,性能证据交给 `fec-performance-optimization`。
|
|
4
4
|
|
|
5
5
|
## 渲染模式概览
|
|
6
6
|
|
|
7
|
-
| 模式
|
|
8
|
-
|
|
|
9
|
-
|
|
|
10
|
-
|
|
|
11
|
-
|
|
|
12
|
-
|
|
|
13
|
-
|
|
|
7
|
+
| 模式 | 生成时机 | 典型适用 |
|
|
8
|
+
| ---- | -------- | -------- |
|
|
9
|
+
| CSR | 浏览器运行时 | 登录后后台、内部工具、高交互 SPA |
|
|
10
|
+
| SSR | 请求时服务端 | SEO 关键且内容实时的公开页 |
|
|
11
|
+
| SSG | 构建时 | 文档、博客、营销页、变化慢的公开内容 |
|
|
12
|
+
| ISR | 构建时 + 按需再生成 | 页面数量多、内容更新频繁但允许延迟 |
|
|
13
|
+
| RSC | 服务端组件渲染 | Next.js App Router 中需要减少客户端 JS 的场景 |
|
|
14
14
|
|
|
15
|
-
##
|
|
15
|
+
## 选型原则
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
- SEO 必须且内容实时:优先 SSR,并明确缓存、超时和错误降级。
|
|
18
|
+
- SEO 必须且内容稳定:优先 SSG;页面数量巨大或更新频繁时考虑 ISR。
|
|
19
|
+
- 登录后后台、强交互工作区、内部工具:优先 CSR,公开登录/注册页可单独 SSG/SSR。
|
|
20
|
+
- 混合产品:公开页与私有页可以采用不同模式,不为统一架构牺牲体验或成本。
|
|
21
|
+
- 页面数量、更新频率、服务器成本、部署平台、缓存策略和团队运维能力必须一起评估。
|
|
22
|
+
- RSC 只在支持的框架和路由体系中使用;客户端交互、浏览器 API 和高频状态仍放在客户端叶子组件。
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
| --------------------- | ---- | ---------------------------------- |
|
|
21
|
-
| **SEO 必须** | 高 | SSR / SSG / ISR |
|
|
22
|
-
| **首屏速度必须 < 1s** | 高 | SSG / ISR |
|
|
23
|
-
| **内容实时性** | 中 | SSR(实时)/ ISR(秒级延迟可接受) |
|
|
24
|
-
| **服务器成本敏感** | 中 | SSG / CSR(无需 Node 服务) |
|
|
25
|
-
| **交互复杂度** | 中 | CSR / RSC |
|
|
26
|
-
| **页面数量 > 10000** | 中 | SSR / ISR(SSG 构建时间过长) |
|
|
27
|
-
| **纯后台管理系统** | 低 | CSR |
|
|
24
|
+
## 实施约束
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
│ └── 内容更新频率高(小时级)→ ISR
|
|
36
|
-
│
|
|
37
|
-
├── 电商 / 社交网络 / 新闻门户
|
|
38
|
-
│ ├── 商品页(SEO + 可缓存)→ SSR + CDN 缓存
|
|
39
|
-
│ ├── 搜索结果(实时)→ SSR
|
|
40
|
-
│ └── 分类页(变化慢)→ ISR
|
|
41
|
-
│
|
|
42
|
-
├── SaaS Dashboard / 后台管理系统
|
|
43
|
-
│ ├── 登录后页面 → CSR
|
|
44
|
-
│ └── 登录/注册页(SEO)→ SSG
|
|
45
|
-
│
|
|
46
|
-
├── 混合场景(公开页 + 私有页)
|
|
47
|
-
│ └── 混合模式:公开页 SSR/SSG,私有页 CSR
|
|
48
|
-
│
|
|
49
|
-
└── 内容密集型(博客 + 商品 + Dashboard)
|
|
50
|
-
└── RSC(Next.js App Router)
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### 详细对比
|
|
54
|
-
|
|
55
|
-
| 维度 | CSR | SSR | SSG | ISR |
|
|
56
|
-
| -------------- | ------------------------ | --------------------- | --------------------- | ----------------------- |
|
|
57
|
-
| **SEO** | ❌ 搜索引擎看到空壳 HTML | ✅ 完整 HTML | ✅ 完整 HTML | ✅ 完整 HTML |
|
|
58
|
-
| **FCP** | ⚠️ 慢(需下载执行 JS) | ✅ 快(服务端已渲染) | ✅ 最快(纯静态文件) | ✅ 最快(同 SSG) |
|
|
59
|
-
| **TTI** | ⚠️ 慢(hydrate 后交互) | ⚠️ 中(hydrate 开销) | ✅ 快 | ✅ 快 |
|
|
60
|
-
| **内容实时性** | ✅ 实时 | ✅ 实时 | ❌ 构建时固定 | ⚠️ 可配置(秒/分钟级) |
|
|
61
|
-
| **服务器成本** | ✅ 无需 Node 服务 | ❌ 需 Node 服务 | ✅ 仅需 CDN | ⚠️ 需 Node 服务(按需) |
|
|
62
|
-
| **构建时间** | ✅ 快 | — | ⚠️ 页面多时慢 | ✅ 增量构建 |
|
|
63
|
-
| **缓存友好** | ⚠️ API 级缓存 | ⚠️ 页面级缓存 | ✅ CDN 全量缓存 | ✅ CDN + 按需失效 |
|
|
64
|
-
| **复杂度** | ✅ 低 | ⚠️ 中 | ✅ 低 | ⚠️ 中 |
|
|
65
|
-
|
|
66
|
-
## 各模式实施要点
|
|
67
|
-
|
|
68
|
-
### CSR(客户端渲染)
|
|
69
|
-
|
|
70
|
-
适用:后台管理系统、内部工具、登录后页面。
|
|
71
|
-
|
|
72
|
-
```tsx
|
|
73
|
-
// 纯 SPA 入口
|
|
74
|
-
import { createRoot } from "react-dom/client";
|
|
75
|
-
import { App } from "./App";
|
|
76
|
-
|
|
77
|
-
createRoot(document.getElementById("root")!).render(<App />);
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
**SEO 补救**:对需要 SEO 的页面使用动态 import 加载预渲染版本,或使用 Prerender SPA Plugin。
|
|
81
|
-
|
|
82
|
-
### SSR(服务端渲染)
|
|
83
|
-
|
|
84
|
-
适用:电商、新闻、社交等 SEO 关键场景。
|
|
85
|
-
|
|
86
|
-
```tsx
|
|
87
|
-
// Next.js Pages Router
|
|
88
|
-
export async function getServerSideProps() {
|
|
89
|
-
const data = await fetchProductData();
|
|
90
|
-
return { props: { data } };
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Next.js App Router (RSC)
|
|
94
|
-
async function ProductPage() {
|
|
95
|
-
const data = await fetchProductData(); // 服务端直接 await
|
|
96
|
-
return <ProductLayout data={data} />;
|
|
97
|
-
}
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
**注意**:
|
|
101
|
-
|
|
102
|
-
- SSR 页面必须考虑服务端兼容性(无 window/document)
|
|
103
|
-
- Hydration 不匹配会导致客户端重新渲染(SSR 水合失败)
|
|
104
|
-
- 服务端数据获取必须有超时和错误降级
|
|
105
|
-
|
|
106
|
-
### SSG(静态站点生成)
|
|
107
|
-
|
|
108
|
-
适用:博客、文档、营销落地页。
|
|
109
|
-
|
|
110
|
-
```tsx
|
|
111
|
-
// Next.js 构建时生成
|
|
112
|
-
export async function getStaticProps() {
|
|
113
|
-
const posts = await fetchPosts();
|
|
114
|
-
return { props: { posts } };
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export async function getStaticPaths() {
|
|
118
|
-
const posts = await fetchPosts();
|
|
119
|
-
return {
|
|
120
|
-
paths: posts.map((p) => `/blog/${p.slug}`),
|
|
121
|
-
fallback: false, // 未预渲染的 404
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### ISR(增量静态再生)
|
|
127
|
-
|
|
128
|
-
适用:页面数量多、内容更新频繁但非实时。
|
|
129
|
-
|
|
130
|
-
```tsx
|
|
131
|
-
export async function getStaticProps() {
|
|
132
|
-
const product = await fetchProduct();
|
|
133
|
-
return {
|
|
134
|
-
props: { product },
|
|
135
|
-
revalidate: 60, // 60 秒内返回缓存版本,后台异步更新
|
|
136
|
-
};
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
## React Server Components(RSC)
|
|
141
|
-
|
|
142
|
-
Next.js App Router 的默认模式,服务端组件不发送 JS 到客户端:
|
|
143
|
-
|
|
144
|
-
```tsx
|
|
145
|
-
// 服务端组件(默认)— 可直接 await 数据库查询
|
|
146
|
-
async function ProductList() {
|
|
147
|
-
const products = await db.products.findMany();
|
|
148
|
-
return (
|
|
149
|
-
<div>
|
|
150
|
-
{products.map((p) => (
|
|
151
|
-
<ProductCard key={p.id} product={p} />
|
|
152
|
-
))}
|
|
153
|
-
</div>
|
|
154
|
-
);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
// 客户端组件 — 需要交互/状态时显式标记
|
|
158
|
-
("use client");
|
|
159
|
-
|
|
160
|
-
function AddToCartButton({ productId }: { productId: string }) {
|
|
161
|
-
const [loading, setLoading] = useState(false);
|
|
162
|
-
return (
|
|
163
|
-
<button onClick={() => addToCart(productId)}>
|
|
164
|
-
{loading ? "..." : "加入购物车"}
|
|
165
|
-
</button>
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
**RSC 优势**:
|
|
171
|
-
|
|
172
|
-
- 服务端组件的 JS 不发送到客户端,减小 bundle
|
|
173
|
-
- 直接 await 数据库/API 调用,无需 useEffect + loading 状态
|
|
174
|
-
- 服务端组件可嵌套客户端组件,按需选择
|
|
26
|
+
- SSR / RSC 路径不得直接依赖 `window`、`document`、localStorage 或浏览器专属库。
|
|
27
|
+
- Hydration 前后的 HTML、时间、随机数、用户偏好和媒体查询结果要保持一致,避免水合不匹配。
|
|
28
|
+
- 服务端数据获取必须有超时、错误降级和缓存策略。
|
|
29
|
+
- SSG / ISR 需要明确未预渲染路径、revalidate / 失效策略和回滚方式。
|
|
30
|
+
- 客户端大型动效库、图表、编辑器、地图、WebGL/Canvas 等应按需加载,不进入根布局同步 bundle。
|
|
31
|
+
- 不在没有响应头、构建输出、trace、路由行为或线上指标证据时断言某路由“已缓存”或“必须动态”。
|
|
175
32
|
|
|
176
33
|
## 检查清单
|
|
177
34
|
|
|
178
|
-
- [ ]
|
|
179
|
-
- [ ]
|
|
180
|
-
- [ ]
|
|
181
|
-
- [ ]
|
|
182
|
-
- [ ] 确认
|
|
183
|
-
- [ ]
|
|
35
|
+
- [ ] 明确公开页与私有页、SEO 需求和实时性需求。
|
|
36
|
+
- [ ] 明确每类页面使用 CSR / SSR / SSG / ISR / RSC 的理由。
|
|
37
|
+
- [ ] 评估页面数量、构建时间、服务器成本和缓存失效策略。
|
|
38
|
+
- [ ] 检查 SSR/RSC 代码没有浏览器 API 依赖和不可序列化 props。
|
|
39
|
+
- [ ] 确认 loading、error、not-found、离线和权限状态不会因渲染模式丢失。
|
|
40
|
+
- [ ] 用构建输出、响应头、trace 或路由行为验证最终模式。
|