@bovinphang/frontend-craft 2.6.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 +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +38 -1
- package/CHANGELOG.zh-CN.md +37 -1
- package/README.md +10 -6
- package/README.openclaw.md +3 -1
- package/README.openclaw.zh-CN.md +3 -1
- package/README.zh-CN.md +10 -6
- package/agents/fec-typescript-reviewer.md +1 -1
- package/docs/example-prompts.md +81 -69
- package/docs/ja-JP/README.md +56 -52
- package/docs/ko-KR/README.md +45 -41
- package/docs/project-structure.md +8 -4
- package/docs/superpowers/plans/2026-05-29-fec-debug.md +491 -0
- package/docs/superpowers/specs/2026-05-29-fec-debug-design.md +340 -0
- package/docs/zh-CN/example-prompts.md +81 -69
- package/docs/zh-CN/project-structure.md +8 -4
- package/docs/zh-TW/README.md +33 -29
- package/openclaw.plugin.json +1 -1
- package/package.json +3 -3
- package/skills/eval_queries.json +154 -56
- package/skills/fec-backend-requirements-handoff/SKILL.md +45 -0
- package/skills/fec-code-review/SKILL.md +1 -1
- 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 +3 -1
- 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-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 +7 -0
- package/skills/fec-legacy-to-modern-migration/SKILL.md +24 -168
- 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-motion-interaction/SKILL.md +7 -0
- package/skills/fec-nextjs-project-standard/SKILL.md +7 -1
- package/skills/fec-performance-optimization/SKILL.md +5 -1
- package/skills/fec-performance-optimization/references/framework-performance-patterns.md +38 -0
- package/skills/fec-performance-optimization/references/report-template.md +6 -0
- package/skills/fec-react-project-standard/SKILL.md +11 -3
- 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-responsive-layout/references/responsive-layout-patterns.md +11 -0
- package/skills/fec-source-driven-development/SKILL.md +26 -0
- 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-vue3-project-standard/SKILL.md +11 -2
- 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/metadata.json +340 -164
- package/skills/relations.json +116 -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
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# React quality patterns
|
|
2
|
+
|
|
3
|
+
## 样式接入
|
|
4
|
+
|
|
5
|
+
本 skill 不强制具体样式方案,默认遵循仓库现状。
|
|
6
|
+
|
|
7
|
+
适配时注意:
|
|
8
|
+
|
|
9
|
+
- Tailwind 项目继续使用 Tailwind
|
|
10
|
+
- CSS Modules 项目保持命名与文件组织一致
|
|
11
|
+
- styled-components 项目继续沿用其模式
|
|
12
|
+
- 主题、颜色、字号、间距等优先复用仓库 token / CSS 变量
|
|
13
|
+
- 避免在组件内硬编码大量视觉常量
|
|
14
|
+
- 禁止内联样式(除动态值外)
|
|
15
|
+
- 响应式处理需与项目断点约定一致
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## 注释规范
|
|
20
|
+
|
|
21
|
+
- **优先使用中文**:解释「为什么这样做」、业务约束、边界情况、非显而易见的权衡时,优先用中文撰写注释,便于团队与业务方阅读。
|
|
22
|
+
- **与代码语言一致时的例外**:对接第三方协议字段名、HTTP 头、规范中的英文术语时,注释里可保留英文专有名词,必要时中英文并列说明。
|
|
23
|
+
- **少而精**:能通过清晰命名与类型表达清楚的逻辑不写废话注释;复杂分支、临时兼容、性能取舍必须写清意图。
|
|
24
|
+
- **公开 API**:模块或 hooks 的对外契约可用 JSDoc(`@param` / `@returns` / `@example`),说明用中文即可,除非仓库统一要求英文。
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## TypeScript 规范
|
|
29
|
+
|
|
30
|
+
通用 TypeScript 工程规则由 `fec-typescript-project-standard` 负责,包括 `tsconfig`、strictness、DTO / view model 边界、`unknown` 收窄、public API 类型、声明产物和类型测试。
|
|
31
|
+
|
|
32
|
+
React 规范只补充组件、Props、事件和 TSX 泛型写法;复杂类型建模或跨框架类型契约先分流到 `fec-typescript-project-standard`。
|
|
33
|
+
|
|
34
|
+
### React 项目补充约定
|
|
35
|
+
|
|
36
|
+
- Props interface 命名: `ComponentNameProps`
|
|
37
|
+
- 事件处理函数: `handle` 前缀(如 `handleClick`)
|
|
38
|
+
- 回调 Props: `on` 前缀(如 `onChange`、`onSubmit`)
|
|
39
|
+
- 组件优先写显式 props 与返回值类型(`JSX.Element` / `React.ReactElement`),避免依赖 `React.FC` 的隐式 `children` 等行为差异
|
|
40
|
+
- 泛型组件使用 `<T>` 约束,保持调用处类型推导;回调与事件类型优先使用 DOM / React 自带类型(如 `React.ChangeEvent<HTMLInputElement>`)
|
|
41
|
+
|
|
42
|
+
```tsx
|
|
43
|
+
interface TableProps<T extends Record<string, unknown>> {
|
|
44
|
+
data: T[];
|
|
45
|
+
columns: ColumnDef<T>[];
|
|
46
|
+
onRowClick?: (row: T) => void;
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 测试规范
|
|
53
|
+
|
|
54
|
+
### 应优先覆盖的内容
|
|
55
|
+
|
|
56
|
+
- 核心交互行为(点击、输入、提交)
|
|
57
|
+
- 条件渲染(loading / error / empty / data)
|
|
58
|
+
- 关键 hooks 的返回值和副作用
|
|
59
|
+
- API 调用 mock 与模块级集成测试
|
|
60
|
+
|
|
61
|
+
### 推荐风格
|
|
62
|
+
|
|
63
|
+
- 测试用户行为,而不是实现细节
|
|
64
|
+
- 优先使用 `screen.getByRole`、`getByLabelText`
|
|
65
|
+
- 避免围绕内部 state 写脆弱测试
|
|
66
|
+
- 只测关键行为,不机械追求覆盖率数字
|
|
67
|
+
|
|
68
|
+
### 示例
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
describe("UserForm", () => {
|
|
72
|
+
it("should submit with valid data", async () => {
|
|
73
|
+
const onSubmit = vi.fn();
|
|
74
|
+
render(<UserForm onSubmit={onSubmit} />);
|
|
75
|
+
|
|
76
|
+
await userEvent.type(screen.getByLabelText("用户名"), "test");
|
|
77
|
+
await userEvent.click(screen.getByRole("button", { name: "提交" }));
|
|
78
|
+
|
|
79
|
+
expect(onSubmit).toHaveBeenCalledWith({ username: "test" });
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("should show error on invalid input", async () => {
|
|
83
|
+
render(<UserForm onSubmit={vi.fn()} />);
|
|
84
|
+
await userEvent.click(screen.getByRole("button", { name: "提交" }));
|
|
85
|
+
expect(screen.getByText("用户名不能为空")).toBeInTheDocument();
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
## 常见反模式
|
|
94
|
+
|
|
95
|
+
避免:
|
|
96
|
+
|
|
97
|
+
- prop drilling 过深却不考虑组合或局部封装
|
|
98
|
+
- 对局部问题过度使用 context
|
|
99
|
+
- 把数据请求、视图渲染、命令式 DOM 操作全塞进一个文件
|
|
100
|
+
- 在 useEffect 中做可以在事件处理函数中完成的事
|
|
101
|
+
- 用 `useEffect + setState` 模拟本可直接计算的派生值
|
|
102
|
+
- 将所有状态都推进全局 store
|
|
103
|
+
- 在 `components/` 中放业务耦合组件
|
|
104
|
+
- 直接绕过模块出口,从 feature 深层路径导入
|
|
105
|
+
- 没有明显收益却提前做复杂优化
|
|
106
|
+
- **新增类组件**或手写类式 Error Boundary(应函数组件 + `react-error-boundary` 等)
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## 输出检查清单
|
|
111
|
+
|
|
112
|
+
输出 React 代码或方案时,至少检查:
|
|
113
|
+
|
|
114
|
+
- [ ] 是否先对齐了仓库现有约定
|
|
115
|
+
- [ ] 页面 / feature / 通用组件边界是否清晰
|
|
116
|
+
- [ ] 目录结构是否与模块复杂度匹配
|
|
117
|
+
- [ ] Props 类型完整且明确
|
|
118
|
+
- [ ] 解释性注释是否优先使用中文且点到要害
|
|
119
|
+
- [ ] 可复用逻辑是否已提取为 hooks
|
|
120
|
+
- [ ] loading / error / empty / data 状态是否齐全
|
|
121
|
+
- [ ] API 层是否具备类型约束和统一错误处理
|
|
122
|
+
- [ ] 复杂 DTO、外部数据收窄、公共类型或 `tsconfig` 问题是否已分流到 `fec-typescript-project-standard`
|
|
123
|
+
- [ ] 状态管理是否符合就近原则
|
|
124
|
+
- [ ] 路由级或重型模块是否考虑懒加载
|
|
125
|
+
- [ ] 样式方案是否与仓库保持一致
|
|
126
|
+
- [ ] 关键行为是否有测试覆盖
|
|
127
|
+
- [ ] 关键模块已用 **`react-error-boundary`**(等)包裹,且未手写类组件式 Boundary
|
|
128
|
+
- [ ] 超长列表是否评估虚拟化;弹窗/复合组件是否具备键盘与焦点约定
|
|
129
|
+
- [ ] 是否引入了不必要的新依赖或新范式
|
|
130
|
+
|
|
131
|
+
---
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# React runtime patterns
|
|
2
|
+
|
|
3
|
+
## 常用 UI 与状态模式
|
|
4
|
+
|
|
5
|
+
以下模式可与本 skill 其他章节(Hooks、状态管理、性能优化、错误处理)对照使用;**按业务复杂度与团队熟悉度选用**,避免为模式而模式。思路参考业界常见的 React 前端模式实践(如组件组合、复合组件、性能与无障碍等)。
|
|
6
|
+
|
|
7
|
+
### 组合优于继承
|
|
8
|
+
|
|
9
|
+
- 用**小颗粒子组件** + `children` / 显式 props 拼装界面,而不是在 React 中搭建类继承层次。
|
|
10
|
+
- 示例:`Card` + `CardHeader` + `CardBody`,由使用方组合,而不是一个巨型 `Card` 用大量布尔 props 分支。
|
|
11
|
+
|
|
12
|
+
### 复合组件(Compound Components)
|
|
13
|
+
|
|
14
|
+
- 根组件通过 **Context** 向子组件提供内部状态(如当前 Tab、打开/关闭)。
|
|
15
|
+
- 子组件在 `useContext` 为空时**抛错或断言**,明确「必须在 Provider 树内使用」。
|
|
16
|
+
- API 表面保持可读:`<Tabs><TabList><Tab /></TabList></Tabs>`。
|
|
17
|
+
|
|
18
|
+
### Render Props / 函数子
|
|
19
|
+
|
|
20
|
+
- 适用:封装**数据获取与三态**(loading / error / data),把**渲染决策**交给父级。
|
|
21
|
+
- 与 **自定义 Hook** 二选一即可:多数场景 `useXxx()` + 普通组件更直观;仅在需要强约束「同层渲染逻辑」时保留 Render Props。
|
|
22
|
+
|
|
23
|
+
### Context + useReducer
|
|
24
|
+
|
|
25
|
+
- 适合**中等复杂度、多子树共享**的客户端状态,且更新可归约为明确 `action`。
|
|
26
|
+
- 避免把高频变化的大对象塞进顶层 Context;服务端数据仍优先 **React Query / SWR**。
|
|
27
|
+
- 大型全局业务状态继续用仓库已选的 **Zustand / Redux Toolkit / Jotai**。
|
|
28
|
+
|
|
29
|
+
### 表单
|
|
30
|
+
|
|
31
|
+
- 受控字段 + 校验错误对象是一类可行实现;中大型表单优先 **React Hook Form**(或 Formik)+ **Zod**,复杂表单值、DTO 和校验类型契约分流到 `fec-typescript-project-standard`。
|
|
32
|
+
- 避免单组件内巨型 `useState` 表单对象与重复校验逻辑,可拆字段子组件或抽 `useFormSchema`。
|
|
33
|
+
|
|
34
|
+
### Error Boundary
|
|
35
|
+
|
|
36
|
+
- **不要**在业务代码中手写 React **类组件**形式的 Error Boundary;统一使用 **`react-error-boundary`**(或团队认可的同类库)在**模块边界**兜底渲染失败(与本章「错误处理」、`error-handling.md` 一致)。
|
|
37
|
+
- 用 `FallbackComponent` 与 `resetErrorBoundary` 提供「重试」;**日志上报**放在库的 **`onError`**(等回调)中,生产代码避免长期依赖 `console.log`(见 TypeScript 规则)。
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
### 动画与过渡
|
|
41
|
+
|
|
42
|
+
- 列表进出场可用 **Framer Motion** 的 `AnimatePresence` + `key`,或 CSS `transition`;注意减少布局抖动与 `prefers-reduced-motion`(与无障碍策略一致时)。
|
|
43
|
+
|
|
44
|
+
### 无障碍与焦点
|
|
45
|
+
|
|
46
|
+
- 自定义下拉、标签页等:**`role` / `aria-*`**、**方向键 / Enter / Escape** 行为与焦点环可见。
|
|
47
|
+
- 弹窗:打开时将焦点移入对话框,关闭时**恢复**触发元素焦点;可用 **`focus-trap-react`** 或类似方案,与 `fec-accessibility-check` skill 互补。
|
|
48
|
+
|
|
49
|
+
### Next.js 与服务端组件
|
|
50
|
+
|
|
51
|
+
- **App Router、Server Components、服务端数据获取与缓存**见 **`fec-nextjs-project-standard`**;客户端交互模式仍以本章与 Hooks 规范为准。
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
## Hooks 设计模式
|
|
57
|
+
|
|
58
|
+
### 适合抽为自定义 Hook 的场景
|
|
59
|
+
|
|
60
|
+
- 数据获取与三态管理
|
|
61
|
+
- 表单状态逻辑
|
|
62
|
+
- 分页、筛选、排序编排
|
|
63
|
+
- 事件监听与副作用清理
|
|
64
|
+
- 可在多个组件复用的交互逻辑
|
|
65
|
+
|
|
66
|
+
### 推荐原则
|
|
67
|
+
|
|
68
|
+
- 统一使用 `use` 前缀命名
|
|
69
|
+
- 返回对象而非数组,方便按需解构,增强可读性和扩展性
|
|
70
|
+
- 状态和行为封装在一起
|
|
71
|
+
- Hook 内部处理 `loading / error / data`
|
|
72
|
+
- 对外暴露清晰的最小接口,不泄漏无关内部细节
|
|
73
|
+
|
|
74
|
+
### 示例
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
function useUserList(params: QueryParams) {
|
|
78
|
+
const [data, setData] = useState<User[]>([]);
|
|
79
|
+
const [loading, setLoading] = useState(false);
|
|
80
|
+
const [error, setError] = useState<Error | null>(null);
|
|
81
|
+
|
|
82
|
+
const fetch = useCallback(async () => {
|
|
83
|
+
setLoading(true);
|
|
84
|
+
setError(null);
|
|
85
|
+
try {
|
|
86
|
+
const res = await getUserList(params);
|
|
87
|
+
setData(res.list);
|
|
88
|
+
} catch (e) {
|
|
89
|
+
setError(e as Error);
|
|
90
|
+
} finally {
|
|
91
|
+
setLoading(false);
|
|
92
|
+
}
|
|
93
|
+
}, [params]);
|
|
94
|
+
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
fetch();
|
|
97
|
+
}, [fetch]);
|
|
98
|
+
|
|
99
|
+
return { data, loading, error, refetch: fetch };
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Hook 使用原则
|
|
104
|
+
|
|
105
|
+
- `useEffect` 必须有正确依赖和清理逻辑
|
|
106
|
+
- `useMemo` / `useCallback` 不要滥用,只有在稳定引用确实重要时再加
|
|
107
|
+
- 不在条件分支或循环中调用 hooks
|
|
108
|
+
- 已引入 React Query / SWR 时,数据请求优先走这些库,而不是自己重复造一套缓存层
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## 路由组织
|
|
113
|
+
|
|
114
|
+
### 推荐方式
|
|
115
|
+
|
|
116
|
+
- 路由配置集中管理
|
|
117
|
+
- 路径常量化
|
|
118
|
+
- 页面组件按需懒加载
|
|
119
|
+
- 权限控制放在 guard 层,而不是散落在页面组件内
|
|
120
|
+
- 分页、筛选、排序等 URL 驱动状态优先与地址栏同步
|
|
121
|
+
|
|
122
|
+
### 示例
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
const routes: RouteObject[] = [
|
|
126
|
+
{
|
|
127
|
+
path: "/",
|
|
128
|
+
element: <MainLayout />,
|
|
129
|
+
children: [
|
|
130
|
+
{ index: true, element: <DashboardPage /> },
|
|
131
|
+
{ path: "users", element: <UserListPage /> },
|
|
132
|
+
{ path: "users/:id", element: <UserDetailPage /> },
|
|
133
|
+
{ path: "settings", element: <SettingsPage /> },
|
|
134
|
+
],
|
|
135
|
+
},
|
|
136
|
+
{ path: "/login", element: <LoginPage /> },
|
|
137
|
+
{ path: "*", element: <NotFoundPage /> },
|
|
138
|
+
];
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
const UserListPage = lazy(() => import("@/pages/UserList/UserListPage"));
|
|
143
|
+
|
|
144
|
+
function ProtectedRoute({ children }: { children: React.ReactNode }) {
|
|
145
|
+
const { isAuthenticated } = useAuth();
|
|
146
|
+
if (!isAuthenticated) return <Navigate to="/login" replace />;
|
|
147
|
+
return <>{children}</>;
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 状态管理选型
|
|
154
|
+
|
|
155
|
+
| 状态类型 | 推荐方案 |
|
|
156
|
+
| ------------------ | ------------------------------------------------- |
|
|
157
|
+
| 组件内临时 UI 状态 | `useState` / `useReducer` |
|
|
158
|
+
| 跨组件共享业务状态 | Zustand / Redux Toolkit / Jotai(按仓库实际选择) |
|
|
159
|
+
| 服务端数据缓存 | React Query / SWR |
|
|
160
|
+
| URL 驱动状态 | 路由参数 / `useSearchParams` |
|
|
161
|
+
| 表单状态 | React Hook Form / Formik |
|
|
162
|
+
|
|
163
|
+
### 核心原则
|
|
164
|
+
|
|
165
|
+
- 就近管理:状态尽量放在最近的公共祖先
|
|
166
|
+
- 单一数据源:同一份数据不要维护多份
|
|
167
|
+
- 派生优于同步:可计算值优先在渲染期计算
|
|
168
|
+
- 服务端数据优先交给请求库管理,不手动塞进全局 store
|
|
169
|
+
- 不要因为“以后可能会用到”就把局部状态提前升级为全局状态
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## API 层规范
|
|
174
|
+
|
|
175
|
+
### 设计原则
|
|
176
|
+
|
|
177
|
+
- 请求基础设施集中在 `services/`
|
|
178
|
+
- 业务 API 按 feature 拆分,而不是全部堆在一个文件
|
|
179
|
+
- 请求参数和响应结果都应有明确类型
|
|
180
|
+
- 认证、错误格式化、通用拦截放在请求层统一处理
|
|
181
|
+
- 页面和组件不要直接散落拼接请求细节
|
|
182
|
+
|
|
183
|
+
### 示例
|
|
184
|
+
|
|
185
|
+
```ts
|
|
186
|
+
// services/request.ts
|
|
187
|
+
const request = axios.create({
|
|
188
|
+
baseURL: import.meta.env.VITE_API_BASE_URL,
|
|
189
|
+
timeout: 10000,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
request.interceptors.response.use(
|
|
193
|
+
(res) => res.data,
|
|
194
|
+
(error) => {
|
|
195
|
+
if (error.response?.status === 401) {
|
|
196
|
+
redirectToLogin();
|
|
197
|
+
}
|
|
198
|
+
return Promise.reject(normalizeError(error));
|
|
199
|
+
},
|
|
200
|
+
);
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
```ts
|
|
204
|
+
// features/user/api.ts
|
|
205
|
+
export function getUserList(
|
|
206
|
+
params: UserQueryParams,
|
|
207
|
+
): Promise<PageResult<User>> {
|
|
208
|
+
return request.get("/users", { params });
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function updateUser(id: string, data: UpdateUserDTO): Promise<User> {
|
|
212
|
+
return request.put(`/users/${id}`, data);
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## 错误处理
|
|
219
|
+
|
|
220
|
+
### 必须覆盖的状态
|
|
221
|
+
|
|
222
|
+
- Loading
|
|
223
|
+
- Error
|
|
224
|
+
- Empty
|
|
225
|
+
- Data
|
|
226
|
+
|
|
227
|
+
### 推荐做法
|
|
228
|
+
|
|
229
|
+
- 关键功能模块使用 Error Boundary 包裹,避免局部异常导致全页白屏
|
|
230
|
+
- 异步请求失败时必须给用户可见反馈
|
|
231
|
+
- 重要操作提供重试能力
|
|
232
|
+
- 不要吞错,不写空 `catch`
|
|
233
|
+
|
|
234
|
+
### 示例(`react-error-boundary`,函数式 Fallback)
|
|
235
|
+
|
|
236
|
+
```tsx
|
|
237
|
+
import { ErrorBoundary } from "react-error-boundary";
|
|
238
|
+
|
|
239
|
+
function ModuleErrorFallback({
|
|
240
|
+
resetErrorBoundary,
|
|
241
|
+
}: {
|
|
242
|
+
resetErrorBoundary: () => void;
|
|
243
|
+
}) {
|
|
244
|
+
return (
|
|
245
|
+
<div>
|
|
246
|
+
模块加载失败
|
|
247
|
+
<button type="button" onClick={resetErrorBoundary}>
|
|
248
|
+
重试
|
|
249
|
+
</button>
|
|
250
|
+
</div>
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export function UserDashboardSection() {
|
|
255
|
+
return (
|
|
256
|
+
<ErrorBoundary FallbackComponent={ModuleErrorFallback}>
|
|
257
|
+
<UserDashboard />
|
|
258
|
+
</ErrorBoundary>
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
---
|
|
264
|
+
|
|
265
|
+
## Suspense 与懒加载
|
|
266
|
+
|
|
267
|
+
适用场景:
|
|
268
|
+
|
|
269
|
+
- 路由级页面
|
|
270
|
+
- 图表、富文本编辑器、地图、重型表格等大体积组件
|
|
271
|
+
- 初始化成本较高的模块
|
|
272
|
+
|
|
273
|
+
示例:
|
|
274
|
+
|
|
275
|
+
```tsx
|
|
276
|
+
const HeavyChart = lazy(() => import("./components/HeavyChart"));
|
|
277
|
+
|
|
278
|
+
function Dashboard() {
|
|
279
|
+
return (
|
|
280
|
+
<Suspense fallback={<ChartSkeleton />}>
|
|
281
|
+
<HeavyChart data={chartData} />
|
|
282
|
+
</Suspense>
|
|
283
|
+
);
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
建议:
|
|
288
|
+
|
|
289
|
+
- 路由级优先 `lazy + Suspense`
|
|
290
|
+
- `fallback` 优先使用 Skeleton 或更贴近内容的占位态,而不是纯 spinner
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
@@ -41,6 +41,14 @@
|
|
|
41
41
|
- 低优先级元数据移入详情行、抽屉或可展开面板。
|
|
42
42
|
- 小屏仍要保留排序、筛选、分页和选择能力。
|
|
43
43
|
- 虚拟滚动只解决 DOM 数量问题,不能解决信息层级问题。
|
|
44
|
+
- 表格可以局部横向滚动,但页面整体不应出现无意水平溢出。
|
|
45
|
+
|
|
46
|
+
## 响应式媒体
|
|
47
|
+
|
|
48
|
+
- 图片和视频要有稳定尺寸、`aspect-ratio` 或容器约束,避免加载后推挤布局。
|
|
49
|
+
- 需要多尺寸资源时使用 `srcset`、`sizes` 或 `<picture>`,不要让移动端下载桌面大图。
|
|
50
|
+
- 非首屏图片默认懒加载;首屏主体图按框架能力设置明确优先级。
|
|
51
|
+
- 媒体裁切必须保留主体信息;不要为了填满卡片裁掉产品、人物、图表关键区域。
|
|
44
52
|
|
|
45
53
|
## 触控与视口检查
|
|
46
54
|
|
|
@@ -49,6 +57,8 @@
|
|
|
49
57
|
- 固定底部栏和操作条必须考虑 `env(safe-area-inset-bottom)`。
|
|
50
58
|
- 对话框和抽屉需要适配虚拟键盘导致的视口变化。
|
|
51
59
|
- 只在 hover 时出现的内容必须提供点击、焦点或常驻可见替代方案。
|
|
60
|
+
- iOS/Android 横竖屏切换后,主操作、焦点位置和滚动容器仍应可达。
|
|
61
|
+
- 需要局部滚动的区域应明确最大高度和滚动边界,避免页面和内部容器互相抢滚动。
|
|
52
62
|
|
|
53
63
|
## 验证清单
|
|
54
64
|
|
|
@@ -57,3 +67,4 @@
|
|
|
57
67
|
- 1024-1440px:内容宽度有约束,扫描路径清晰。
|
|
58
68
|
- 长标签、翻译文本、数字以及 empty/error/loading 状态不会撑坏固定格式控件。
|
|
59
69
|
- 横竖屏切换不会困住焦点或隐藏主操作。
|
|
70
|
+
- 虚拟键盘弹出时,输入框、提交按钮和错误提示不被遮挡。
|
|
@@ -20,6 +20,7 @@ description: Use when frontend decisions depend on framework, library, browser,
|
|
|
20
20
|
- 首选官方文档、规范、源码、release notes、migration guide、类型定义和项目内测试。
|
|
21
21
|
- 第三方文章只能作为线索,不能作为最终依据。
|
|
22
22
|
- 对快速变化的库记录包名、版本、文档日期或页面标题。
|
|
23
|
+
- 当用户要求从本地知识库、项目资料库或 `knowledge/` 目录回答问题时,先走本地知识检索,不使用网络搜索补事实。
|
|
23
24
|
|
|
24
25
|
3. 提炼决策
|
|
25
26
|
- 写清当前版本推荐做法、弃用做法、限制条件和迁移注意事项。
|
|
@@ -38,6 +39,31 @@ description: Use when frontend decisions depend on framework, library, browser,
|
|
|
38
39
|
6. 留下轻量决策记录
|
|
39
40
|
- 当结论会影响公共接口、依赖版本、目录规范或团队工作流时,补充 ADR/变更记录或交给文档同步流程。
|
|
40
41
|
|
|
42
|
+
## Local Knowledge Retrieval
|
|
43
|
+
|
|
44
|
+
当用户指定本地知识库路径,或默认 `knowledge/` 目录存在时,可用本流程回答资料库问题、抽取证据或辅助决策。
|
|
45
|
+
|
|
46
|
+
1. 定位根目录
|
|
47
|
+
- 用户明确指定路径时使用该路径。
|
|
48
|
+
- 否则检查当前项目下 `knowledge/` 是否存在;不存在时说明未找到默认知识库并请求路径。
|
|
49
|
+
- 不用文件 glob 判断目录是否存在。
|
|
50
|
+
|
|
51
|
+
2. 分层导航
|
|
52
|
+
- 优先读取根目录和子目录中的 `data_structure.md`。
|
|
53
|
+
- 根据目录说明选择最相关的少量分支,不一次性遍历整个知识库。
|
|
54
|
+
- 记录候选文件、主题、时间/版本范围和为什么相关。
|
|
55
|
+
|
|
56
|
+
3. 渐进检索
|
|
57
|
+
- Markdown、文本、日志:先用关键词搜索,再局部读取命中上下文。
|
|
58
|
+
- PDF:处理前先确认可用工具和提取路线,优先提取到临时文本后再检索,避免把整份 PDF 打进上下文。
|
|
59
|
+
- Excel:处理前先确认读取/分析路线,先看工作表、列名和少量样例,再按字段过滤或聚合。
|
|
60
|
+
- 默认最多 5 轮关键词迭代;每轮根据已找到证据调整同义词、缩写和范围。
|
|
61
|
+
|
|
62
|
+
4. 回答与溯源
|
|
63
|
+
- 先给结论,再列文件路径、章节、页码、工作表或行号附近作为依据。
|
|
64
|
+
- 证据不足时说明查过哪些路径、缺什么信息,以及用户如何缩小范围。
|
|
65
|
+
- 不把知识库外的网络信息混入答案,除非用户另行要求查外部来源。
|
|
66
|
+
|
|
41
67
|
## Source Priority
|
|
42
68
|
|
|
43
69
|
| Priority | Source | Use |
|
|
@@ -35,9 +35,13 @@ const toneClass = {
|
|
|
35
35
|
## 暗色模式
|
|
36
36
|
|
|
37
37
|
- 优先选择单一的项目级策略:`class`、`data-theme` 或 CSS 变量。
|
|
38
|
-
- 如果应用支持手动切换主题,在 body
|
|
38
|
+
- 如果应用支持手动切换主题,在 body 绘制前初始化已选主题,避免首屏先亮后暗或先暗后亮的主题闪烁。
|
|
39
39
|
- 在亮色和暗色主题下都测试 disabled、focus、selected、invalid、chart 和 skeleton 状态。
|
|
40
40
|
- 不要把降低透明度作为 disabled 的唯一提示;要保留对比度和可感知性。
|
|
41
|
+
- Tailwind 项目使用 `darkMode: "class"` 或等价配置时,主题切换逻辑应同时维护根节点 class / data attribute,并持久化用户偏好。
|
|
42
|
+
- CSS 变量方案中,Tailwind token 应引用语义变量;不要为亮色和暗色分别散落两套工具类字面量。
|
|
43
|
+
- 在 `<head>` 或框架等价入口中放置极小同步初始化脚本时,只读取本地主题偏好和系统偏好,不执行业务逻辑、不访问服务端数据。
|
|
44
|
+
- 暗色模式需复核图片亮度、阴影层级、表单控件、第三方组件、图表色板和 focus ring;不要只补背景色。
|
|
41
45
|
|
|
42
46
|
## 响应式工具类
|
|
43
47
|
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: fec-typescript-project-standard
|
|
3
|
+
description: Use when creating, configuring, reviewing, or debugging TypeScript project standards across frontend apps, libraries, SDKs, CLIs, monorepo packages, tsconfig, strictness, module/moduleResolution, path aliases, project references, declaration files, package exports, public API types, DTOs, advanced generics, discriminated unions, type guards, type narrowing, or type-level regressions. Prefer framework project skills for React/Vue/Next/Nuxt component architecture; Chinese triggers include TypeScript 项目规范, TS 项目规范, TypeScript 类型安全, 类型建模, 泛型, 判别联合, 类型收窄, tsconfig, 声明文件.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# TypeScript 项目规范
|
|
7
|
+
|
|
8
|
+
## Purpose
|
|
9
|
+
|
|
10
|
+
统一 TypeScript 层的工程配置、类型边界和发布产物规则。适用于前端应用、组件库、SDK、CLI、monorepo package 和纯 TypeScript 工具库,但不接管 React、Vue、Next.js、Nuxt 或 Vite 的框架架构职责。
|
|
11
|
+
|
|
12
|
+
## Procedure
|
|
13
|
+
|
|
14
|
+
1. 识别 TypeScript 上下文
|
|
15
|
+
- 应用项目:优先检查 `tsconfig` 分层、strictness、路径别名、类型检查脚本和框架生成类型。
|
|
16
|
+
- 组件库或 SDK:优先检查 public API、声明文件、package exports、peer dependencies 类型边界和发布前 pack 校验。
|
|
17
|
+
- CLI 或 Node 工具:优先检查 Node 目标版本、ESM/CJS 策略、`moduleResolution`、shebang 产物和 `process.env` 类型边界。
|
|
18
|
+
- Monorepo package:优先检查 project references、composite build、包间导入边界和 workspace 路径别名是否泄漏到发布产物。
|
|
19
|
+
- React、Vue、Next.js、Nuxt 等框架的组件架构、路由组织和状态管理归对应框架 skill;本流程只处理跨框架 TypeScript 契约和工程边界。
|
|
20
|
+
|
|
21
|
+
2. 收敛 `tsconfig`
|
|
22
|
+
- 默认开启 `strict`,不要为通过构建关闭 `noImplicitAny`、`strictNullChecks` 或 `exactOptionalPropertyTypes` 等关键约束。
|
|
23
|
+
- 按运行环境选择 `target`、`lib`、`module` 和 `moduleResolution`;浏览器应用、Node 脚本、库包不要共用一份含混配置。
|
|
24
|
+
- 将基础配置、应用配置、测试配置和构建声明配置拆开,避免测试全局类型污染生产代码。
|
|
25
|
+
- 路径别名必须同时被 TypeScript、bundler、test runner 和发布产物理解;库包不得发布无法解析的源码别名。
|
|
26
|
+
|
|
27
|
+
3. 设计类型边界
|
|
28
|
+
- 外部输入、DTO、领域模型、UI view model、组件 props 和工具函数 API 分层命名。
|
|
29
|
+
- public API 的参数和返回值显式标注,内部局部变量优先依赖推断。
|
|
30
|
+
- 外部数据先以 `unknown` 接收,再通过 schema 或 type guard 收窄。
|
|
31
|
+
- 复杂泛型、判别联合、DTO 映射、类型守卫和类型测试加载 [类型安全参考](references/type-safety.md);需要高级模式时加载 [类型安全模式](references/type-safety-patterns.md)。
|
|
32
|
+
|
|
33
|
+
4. 固定发布与声明产物
|
|
34
|
+
- 库包必须确认 `package.json` 的 `exports`、`types`、`files` 和实际构建产物一致。
|
|
35
|
+
- 不默认双包发布;只有明确消费方需要时才同时产出 ESM/CJS,并验证类型入口不分叉。
|
|
36
|
+
- 通过 `tsc --emitDeclarationOnly`、构建工具声明插件或 API extractor 产出 `.d.ts`,并在发布前检查声明文件可被消费方解析。
|
|
37
|
+
- 不把测试、fixture、内部工具、未稳定类型或私有路径暴露到 package exports。
|
|
38
|
+
|
|
39
|
+
5. 验证 TypeScript 质量
|
|
40
|
+
- 优先使用仓库已有脚本,如 `typecheck`、`build`、`test`、`lint` 和 package pack dry-run。
|
|
41
|
+
- Vite、Next、Nuxt 等构建不等于完整类型检查;CI 必须有独立 typecheck 或等效验证。
|
|
42
|
+
- 类型改动影响 public API 时补类型测试、编译期断言或消费方 fixture。
|
|
43
|
+
|
|
44
|
+
## Constraints
|
|
45
|
+
|
|
46
|
+
- 不用 `skipLibCheck`、`any`、无守卫非空断言或宽泛 `as` 掩盖真实边界问题。
|
|
47
|
+
- 不在应用代码中依赖发布包私有深层路径。
|
|
48
|
+
- 不把框架目录结构、组件分层、路由组织或状态管理决策放进本流程;这些交给对应框架或专项流程。
|
|
49
|
+
- 不让生成类型、测试类型或 Node-only 类型污染浏览器运行代码。
|
|
50
|
+
- 不发布只能在源码仓库内解析的路径别名、ambient 声明或隐式全局类型。
|
|
51
|
+
|
|
52
|
+
## Expected Output
|
|
53
|
+
|
|
54
|
+
输出应包含 TypeScript 上下文判断、关键 `tsconfig`/package 类型入口建议、类型边界方案、声明文件或 public API 风险、验证命令。完成后项目应能独立 typecheck,公开类型可被消费方解析,类型安全问题有明确收窄或建模方案。
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: fec-typescript-type-safety
|
|
3
|
-
description: Use when designing, implementing, or reviewing TypeScript type contracts, advanced generics, discriminated unions, type guards, API DTOs, component props, public utility types, or type-level regressions in frontend projects. Prefer code review for broad PR review; Chinese triggers include TypeScript 类型安全, 类型建模, 泛型, 判别联合, 类型收窄.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
1
|
# TypeScript 类型安全
|
|
7
2
|
|
|
8
3
|
## Purpose
|
|
9
4
|
|
|
10
|
-
|
|
5
|
+
为前端和 TypeScript 工程建立可演进的类型契约,减少 `any`、断言和运行时形状漂移。
|
|
11
6
|
|
|
12
7
|
## Procedure
|
|
13
8
|
|
|
@@ -140,10 +135,6 @@ type UserStatus = UserViewModel["status"];
|
|
|
140
135
|
type _UserStatusTest = Expect<Equal<UserStatus, "active" | "disabled">>;
|
|
141
136
|
```
|
|
142
137
|
|
|
143
|
-
## 详细参考
|
|
144
|
-
|
|
145
|
-
涉及高级泛型约束、映射类型、模板字面量类型、类型测试、DTO 映射或类型审查清单时,加载 [references/type-safety-patterns.md](references/type-safety-patterns.md)。
|
|
146
|
-
|
|
147
138
|
## Constraints
|
|
148
139
|
|
|
149
140
|
- 避免 `any`、无守卫的非空断言和不相关类型之间的强制 `as`。
|