ccg-workflow 1.8.2 → 2.0.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/dist/cli.mjs +1 -1
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +1 -1
- package/dist/shared/{ccg-workflow.B1RHp04H.mjs → ccg-workflow.iK6lgCG3.mjs} +204 -6
- package/package.json +1 -1
- package/templates/commands/agents/team-architect.md +97 -0
- package/templates/commands/agents/team-qa.md +121 -0
- package/templates/commands/agents/team-reviewer.md +112 -0
- package/templates/output-styles/abyss-command.md +56 -0
- package/templates/output-styles/abyss-concise.md +89 -0
- package/templates/output-styles/abyss-ritual.md +70 -0
- package/templates/rules/ccg-skill-routing.md +83 -0
- package/templates/skills/domains/ai/SKILL.md +34 -0
- package/templates/skills/domains/ai/agent-dev.md +242 -0
- package/templates/skills/domains/ai/llm-security.md +288 -0
- package/templates/skills/domains/ai/prompt-and-eval.md +279 -0
- package/templates/skills/domains/ai/rag-system.md +542 -0
- package/templates/skills/domains/architecture/SKILL.md +42 -0
- package/templates/skills/domains/architecture/api-design.md +225 -0
- package/templates/skills/domains/architecture/caching.md +299 -0
- package/templates/skills/domains/architecture/cloud-native.md +285 -0
- package/templates/skills/domains/architecture/message-queue.md +329 -0
- package/templates/skills/domains/architecture/security-arch.md +297 -0
- package/templates/skills/domains/data-engineering/SKILL.md +207 -0
- package/templates/skills/domains/development/SKILL.md +46 -0
- package/templates/skills/domains/development/cpp.md +246 -0
- package/templates/skills/domains/development/go.md +323 -0
- package/templates/skills/domains/development/java.md +277 -0
- package/templates/skills/domains/development/python.md +288 -0
- package/templates/skills/domains/development/rust.md +313 -0
- package/templates/skills/domains/development/shell.md +313 -0
- package/templates/skills/domains/development/typescript.md +277 -0
- package/templates/skills/domains/devops/SKILL.md +39 -0
- package/templates/skills/domains/devops/cost-optimization.md +272 -0
- package/templates/skills/domains/devops/database.md +217 -0
- package/templates/skills/domains/devops/devsecops.md +198 -0
- package/templates/skills/domains/devops/git-workflow.md +181 -0
- package/templates/skills/domains/devops/observability.md +280 -0
- package/templates/skills/domains/devops/performance.md +336 -0
- package/templates/skills/domains/devops/testing.md +283 -0
- package/templates/skills/domains/frontend-design/SKILL.md +242 -0
- package/templates/skills/domains/frontend-design/agents/openai.yaml +4 -0
- package/templates/skills/domains/frontend-design/claymorphism/SKILL.md +119 -0
- package/templates/skills/domains/frontend-design/claymorphism/references/tokens.css +52 -0
- package/templates/skills/domains/frontend-design/component-patterns.md +202 -0
- package/templates/skills/domains/frontend-design/engineering.md +287 -0
- package/templates/skills/domains/frontend-design/glassmorphism/SKILL.md +140 -0
- package/templates/skills/domains/frontend-design/glassmorphism/references/tokens.css +32 -0
- package/templates/skills/domains/frontend-design/liquid-glass/SKILL.md +137 -0
- package/templates/skills/domains/frontend-design/liquid-glass/references/tokens.css +81 -0
- package/templates/skills/domains/frontend-design/neubrutalism/SKILL.md +143 -0
- package/templates/skills/domains/frontend-design/neubrutalism/references/tokens.css +44 -0
- package/templates/skills/domains/frontend-design/reference/color-and-contrast.md +132 -0
- package/templates/skills/domains/frontend-design/reference/interaction-design.md +195 -0
- package/templates/skills/domains/frontend-design/reference/motion-design.md +99 -0
- package/templates/skills/domains/frontend-design/reference/responsive-design.md +114 -0
- package/templates/skills/domains/frontend-design/reference/spatial-design.md +100 -0
- package/templates/skills/domains/frontend-design/reference/typography.md +133 -0
- package/templates/skills/domains/frontend-design/reference/ux-writing.md +107 -0
- package/templates/skills/domains/frontend-design/state-management.md +680 -0
- package/templates/skills/domains/frontend-design/ui-aesthetics.md +110 -0
- package/templates/skills/domains/frontend-design/ux-principles.md +156 -0
- package/templates/skills/domains/infrastructure/SKILL.md +200 -0
- package/templates/skills/domains/mobile/SKILL.md +224 -0
- package/templates/skills/domains/orchestration/SKILL.md +29 -0
- package/templates/skills/domains/orchestration/multi-agent.md +263 -0
- package/templates/skills/domains/security/SKILL.md +72 -0
- package/templates/skills/domains/security/blue-team.md +436 -0
- package/templates/skills/domains/security/code-audit.md +265 -0
- package/templates/skills/domains/security/pentest.md +226 -0
- package/templates/skills/domains/security/red-team.md +374 -0
- package/templates/skills/domains/security/threat-intel.md +372 -0
- package/templates/skills/domains/security/vuln-research.md +369 -0
- package/templates/skills/impeccable/adapt/SKILL.md +199 -0
- package/templates/skills/impeccable/animate/SKILL.md +174 -0
- package/templates/skills/impeccable/arrange/SKILL.md +124 -0
- package/templates/skills/impeccable/audit/SKILL.md +147 -0
- package/templates/skills/impeccable/bolder/SKILL.md +116 -0
- package/templates/skills/impeccable/clarify/SKILL.md +183 -0
- package/templates/skills/impeccable/colorize/SKILL.md +142 -0
- package/templates/skills/impeccable/critique/SKILL.md +201 -0
- package/templates/skills/impeccable/critique/reference/cognitive-load.md +106 -0
- package/templates/skills/impeccable/critique/reference/heuristics-scoring.md +234 -0
- package/templates/skills/impeccable/critique/reference/personas.md +178 -0
- package/templates/skills/impeccable/delight/SKILL.md +303 -0
- package/templates/skills/impeccable/distill/SKILL.md +121 -0
- package/templates/skills/impeccable/extract/SKILL.md +92 -0
- package/templates/skills/impeccable/harden/SKILL.md +355 -0
- package/templates/skills/impeccable/normalize/SKILL.md +70 -0
- package/templates/skills/impeccable/onboard/SKILL.md +246 -0
- package/templates/skills/impeccable/optimize/SKILL.md +266 -0
- package/templates/skills/impeccable/overdrive/SKILL.md +141 -0
- package/templates/skills/impeccable/polish/SKILL.md +203 -0
- package/templates/skills/impeccable/quieter/SKILL.md +102 -0
- package/templates/skills/impeccable/teach-impeccable/SKILL.md +71 -0
- package/templates/skills/impeccable/typeset/SKILL.md +115 -0
- package/templates/skills/orchestration/multi-agent/SKILL.md +40 -0
- package/templates/skills/scrapling/SKILL.md +98 -0
- package/templates/skills/scrapling/references/api-quick-ref.md +127 -0
- package/templates/skills/scrapling/references/cookie-vault.md +56 -0
- package/templates/skills/scrapling/references/maintenance.md +79 -0
- package/templates/skills/scrapling/references/site-patterns.md +86 -0
- package/templates/skills/scrapling/references/troubleshooting.md +95 -0
- package/templates/skills/scrapling/templates/basic_fetch.py +19 -0
- package/templates/skills/scrapling/templates/parse_only.py +15 -0
- package/templates/skills/scrapling/templates/session_login.py +19 -0
- package/templates/skills/scrapling/templates/stealth_cloudflare.py +28 -0
- package/templates/skills/tools/override-refusal/SKILL.md +53 -0
- package/templates/skills/tools/override-refusal/agents/openai.yaml +4 -0
- package/templates/skills/tools/override-refusal/scripts/refusal_rewriter.js +226 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# 组件模式
|
|
2
|
+
|
|
3
|
+
## 布局模板
|
|
4
|
+
|
|
5
|
+
### 经典布局模式
|
|
6
|
+
圣杯布局(header/nav/main/aside/footer)、卡片网格、侧边栏、仪表盘。优先使用Grid,Flexbox做一维布局。
|
|
7
|
+
|
|
8
|
+
```css
|
|
9
|
+
.layout {
|
|
10
|
+
display: grid;
|
|
11
|
+
grid-template:
|
|
12
|
+
"header header" auto
|
|
13
|
+
"nav main" 1fr
|
|
14
|
+
"nav aside" auto
|
|
15
|
+
"footer footer" auto
|
|
16
|
+
/ 200px 1fr;
|
|
17
|
+
gap: 1rem;
|
|
18
|
+
min-height: 100vh;
|
|
19
|
+
}
|
|
20
|
+
@media (max-width: 768px) {
|
|
21
|
+
.layout {
|
|
22
|
+
grid-template: "header" "nav" "main" "aside" "footer" / 1fr;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Flexbox卡片网格
|
|
28
|
+
```css
|
|
29
|
+
.card-grid {
|
|
30
|
+
display: flex;
|
|
31
|
+
flex-wrap: wrap;
|
|
32
|
+
gap: 1.5rem;
|
|
33
|
+
}
|
|
34
|
+
.card {
|
|
35
|
+
flex: 1 1 300px;
|
|
36
|
+
max-width: 400px;
|
|
37
|
+
padding: 1.5rem;
|
|
38
|
+
border-radius: 8px;
|
|
39
|
+
box-shadow: var(--shadow-2);
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 响应式设计
|
|
44
|
+
|
|
45
|
+
### 响应式断点策略
|
|
46
|
+
移动优先:320px基准→640px(sm)→768px(md)→1024px(lg)→1280px(xl)。使用em单位断点(除以16)。优先容器查询。
|
|
47
|
+
|
|
48
|
+
```css
|
|
49
|
+
.card-container {
|
|
50
|
+
container-type: inline-size;
|
|
51
|
+
}
|
|
52
|
+
.card {
|
|
53
|
+
padding: 1rem;
|
|
54
|
+
}
|
|
55
|
+
@container (min-width: 400px) {
|
|
56
|
+
.card {
|
|
57
|
+
display: grid;
|
|
58
|
+
grid-template-columns: 150px 1fr;
|
|
59
|
+
gap: 1rem;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 交互模式
|
|
65
|
+
|
|
66
|
+
### 微交互设计原则
|
|
67
|
+
反馈即时(<100ms)、过渡流畅(200-300ms)、状态清晰(hover/active/focus)、减少认知负担。
|
|
68
|
+
|
|
69
|
+
```css
|
|
70
|
+
.btn {
|
|
71
|
+
transition: all 0.2s ease;
|
|
72
|
+
}
|
|
73
|
+
.btn:hover {
|
|
74
|
+
transform: translateY(-2px);
|
|
75
|
+
box-shadow: var(--shadow-3);
|
|
76
|
+
}
|
|
77
|
+
.btn:active {
|
|
78
|
+
transform: translateY(0);
|
|
79
|
+
}
|
|
80
|
+
.btn:focus-visible {
|
|
81
|
+
outline: 2px solid var(--primary);
|
|
82
|
+
outline-offset: 2px;
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## 动画
|
|
87
|
+
|
|
88
|
+
### CSS关键帧动画
|
|
89
|
+
```css
|
|
90
|
+
@keyframes fadeInUp {
|
|
91
|
+
from {
|
|
92
|
+
opacity: 0;
|
|
93
|
+
transform: translateY(20px);
|
|
94
|
+
}
|
|
95
|
+
to {
|
|
96
|
+
opacity: 1;
|
|
97
|
+
transform: translateY(0);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
.animate-in {
|
|
101
|
+
animation: fadeInUp 0.4s ease-out;
|
|
102
|
+
}
|
|
103
|
+
@media (prefers-reduced-motion: reduce) {
|
|
104
|
+
.animate-in {
|
|
105
|
+
animation: none;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Framer Motion模板
|
|
111
|
+
```javascript
|
|
112
|
+
const fadeInUp = {
|
|
113
|
+
initial: { opacity: 0, y: 20 },
|
|
114
|
+
animate: { opacity: 1, y: 0 },
|
|
115
|
+
transition: { duration: 0.4, ease: "easeOut" }
|
|
116
|
+
};
|
|
117
|
+
const stagger = {
|
|
118
|
+
animate: { transition: { staggerChildren: 0.1 } }
|
|
119
|
+
};
|
|
120
|
+
<motion.div variants={stagger}>
|
|
121
|
+
<motion.div variants={fadeInUp} />
|
|
122
|
+
</motion.div>
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## 表单设计
|
|
126
|
+
|
|
127
|
+
### 表单UX模式
|
|
128
|
+
标签上置、内联验证、清晰错误提示、禁用状态明显、必填标记、合理分组、自动聚焦首字段。
|
|
129
|
+
|
|
130
|
+
```css
|
|
131
|
+
.form-field {
|
|
132
|
+
display: flex;
|
|
133
|
+
flex-direction: column;
|
|
134
|
+
gap: 0.5rem;
|
|
135
|
+
}
|
|
136
|
+
.input {
|
|
137
|
+
padding: 0.75rem;
|
|
138
|
+
border: 1px solid #d1d5db;
|
|
139
|
+
border-radius: 6px;
|
|
140
|
+
font-size: 1rem;
|
|
141
|
+
transition: border-color 0.2s;
|
|
142
|
+
}
|
|
143
|
+
.input:focus {
|
|
144
|
+
outline: none;
|
|
145
|
+
border-color: var(--primary);
|
|
146
|
+
box-shadow: 0 0 0 3px rgba(59,130,246,0.1);
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## 卡片组件
|
|
151
|
+
|
|
152
|
+
### 玻璃拟态卡片
|
|
153
|
+
```css
|
|
154
|
+
.glass-card {
|
|
155
|
+
background: rgba(255, 255, 255, 0.1);
|
|
156
|
+
backdrop-filter: blur(10px);
|
|
157
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
158
|
+
border-radius: 12px;
|
|
159
|
+
padding: 1.5rem;
|
|
160
|
+
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## 导航模式
|
|
165
|
+
|
|
166
|
+
### 响应式导航栏
|
|
167
|
+
```css
|
|
168
|
+
.nav {
|
|
169
|
+
display: flex;
|
|
170
|
+
justify-content: space-between;
|
|
171
|
+
align-items: center;
|
|
172
|
+
padding: 1rem;
|
|
173
|
+
}
|
|
174
|
+
.nav-links {
|
|
175
|
+
display: flex;
|
|
176
|
+
gap: 2rem;
|
|
177
|
+
}
|
|
178
|
+
@media (max-width: 768px) {
|
|
179
|
+
.nav-links {
|
|
180
|
+
display: none;
|
|
181
|
+
}
|
|
182
|
+
.nav-links.open {
|
|
183
|
+
display: flex;
|
|
184
|
+
flex-direction: column;
|
|
185
|
+
position: absolute;
|
|
186
|
+
top: 100%;
|
|
187
|
+
left: 0;
|
|
188
|
+
right: 0;
|
|
189
|
+
background: white;
|
|
190
|
+
padding: 1rem;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## 审查清单
|
|
196
|
+
|
|
197
|
+
- [ ] 响应式适配
|
|
198
|
+
- [ ] 交互状态完整
|
|
199
|
+
- [ ] 无障碍支持
|
|
200
|
+
- [ ] 性能优化
|
|
201
|
+
- [ ] 浏览器兼容
|
|
202
|
+
- [ ] 动画流畅
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: frontend-engineering
|
|
3
|
+
description: 前端工程化。性能优化(Web Vitals、懒加载、虚拟滚动)、测试(Vitest、Playwright、MSW)、构建工具(Vite、Webpack、esbuild)。当用户提到性能优化、前端测试、构建工具、代码分割时使用。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 前端工程化 · Frontend Engineering
|
|
7
|
+
|
|
8
|
+
## 一、性能优化
|
|
9
|
+
|
|
10
|
+
### Core Web Vitals
|
|
11
|
+
|
|
12
|
+
| 指标 | 含义 | 目标值 |
|
|
13
|
+
|------|------|--------|
|
|
14
|
+
| LCP | Largest Contentful Paint | < 2.5s |
|
|
15
|
+
| FID | First Input Delay | < 100ms |
|
|
16
|
+
| CLS | Cumulative Layout Shift | < 0.1 |
|
|
17
|
+
| FCP | First Contentful Paint | < 1.8s |
|
|
18
|
+
| TTI | Time to Interactive | < 3.8s |
|
|
19
|
+
|
|
20
|
+
### 性能决策树
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
加载慢 → Bundle 大?代码分割 + Tree Shaking | 资源多?懒加载 + 预加载 | 网络慢?CDN + 压缩
|
|
24
|
+
渲染慢 → 列表长?虚拟滚动 | 重渲染?React.memo + useMemo | 布局抖动?固定尺寸
|
|
25
|
+
交互慢 → JS 阻塞?Web Worker + startTransition | 动画卡顿?CSS 动画 + rAF
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 代码分割
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
// 路由级别 — React.lazy + Suspense
|
|
32
|
+
const Dashboard = lazy(() => import('./pages/Dashboard'))
|
|
33
|
+
|
|
34
|
+
// 组件级别 — 按需加载重量级组件
|
|
35
|
+
const HeavyChart = lazy(() => import('./components/HeavyChart'))
|
|
36
|
+
|
|
37
|
+
// Vite manualChunks
|
|
38
|
+
export default defineConfig({
|
|
39
|
+
build: {
|
|
40
|
+
rollupOptions: {
|
|
41
|
+
output: {
|
|
42
|
+
manualChunks: {
|
|
43
|
+
'react-vendor': ['react', 'react-dom'],
|
|
44
|
+
'ui': ['@mui/material'],
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 虚拟滚动
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { FixedSizeList } from 'react-window'
|
|
56
|
+
|
|
57
|
+
function VirtualList({ items }: { items: Item[] }) {
|
|
58
|
+
return (
|
|
59
|
+
<FixedSizeList height={600} itemCount={items.length} itemSize={50} width="100%">
|
|
60
|
+
{({ index, style }) => <div style={style}>{items[index].name}</div>}
|
|
61
|
+
</FixedSizeList>
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### React 性能要点
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
// memo 避免重渲染
|
|
70
|
+
const Row = memo(function Row({ item, onClick }: Props) {
|
|
71
|
+
return <div onClick={() => onClick(item.id)}>{item.name}</div>
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
// useMemo 缓存计算 + useCallback 缓存回调
|
|
75
|
+
const filtered = useMemo(() => data.filter(x => x.name.includes(q)), [data, q])
|
|
76
|
+
const handleClick = useCallback((id: string) => select(id), [])
|
|
77
|
+
|
|
78
|
+
// startTransition 低优先级更新
|
|
79
|
+
startTransition(() => setResults(heavySearch(query)))
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 资源优化 Checklist
|
|
83
|
+
|
|
84
|
+
- 图片:WebP 格式 + `loading="lazy"` + 响应式 `<picture>`
|
|
85
|
+
- 字体:`font-display: swap` + `preload` woff2
|
|
86
|
+
- 预加载:`dns-prefetch` → `preconnect` → `preload` → `prefetch`
|
|
87
|
+
- 压缩:Gzip/Brotli + HTTP/2
|
|
88
|
+
|
|
89
|
+
### 性能监控
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { onCLS, onFID, onLCP } from 'web-vitals'
|
|
93
|
+
onCLS(sendToAnalytics)
|
|
94
|
+
onFID(sendToAnalytics)
|
|
95
|
+
onLCP(sendToAnalytics)
|
|
96
|
+
|
|
97
|
+
// 自定义指标
|
|
98
|
+
performance.mark('start')
|
|
99
|
+
doWork()
|
|
100
|
+
performance.mark('end')
|
|
101
|
+
performance.measure('work', 'start', 'end')
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## 二、测试
|
|
105
|
+
|
|
106
|
+
### 测试金字塔
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
/\ E2E (10%) — Playwright
|
|
110
|
+
/--\ 集成 (20%) — Testing Library + MSW
|
|
111
|
+
/----\ 单元 (70%) — Vitest
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Vitest 配置
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// vitest.config.ts
|
|
118
|
+
export default defineConfig({
|
|
119
|
+
test: {
|
|
120
|
+
globals: true,
|
|
121
|
+
environment: 'jsdom',
|
|
122
|
+
setupFiles: './src/test/setup.ts',
|
|
123
|
+
coverage: {
|
|
124
|
+
provider: 'v8',
|
|
125
|
+
thresholds: { lines: 80, functions: 80, branches: 75 },
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
})
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 单元测试
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
describe('formatCurrency', () => {
|
|
135
|
+
it('formats number', () => expect(formatCurrency(1234.56)).toBe('$1,234.56'))
|
|
136
|
+
it('handles zero', () => expect(formatCurrency(0)).toBe('$0.00'))
|
|
137
|
+
})
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 组件测试
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
import { render, screen, fireEvent } from '@testing-library/react'
|
|
144
|
+
|
|
145
|
+
it('calls onClick', () => {
|
|
146
|
+
const fn = vi.fn()
|
|
147
|
+
render(<Button onClick={fn}>Click</Button>)
|
|
148
|
+
fireEvent.click(screen.getByText('Click'))
|
|
149
|
+
expect(fn).toHaveBeenCalledTimes(1)
|
|
150
|
+
})
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### MSW Mock
|
|
154
|
+
|
|
155
|
+
```typescript
|
|
156
|
+
import { http, HttpResponse } from 'msw'
|
|
157
|
+
import { setupServer } from 'msw/node'
|
|
158
|
+
|
|
159
|
+
const server = setupServer(
|
|
160
|
+
http.get('/api/users/:id', ({ params }) =>
|
|
161
|
+
HttpResponse.json({ id: params.id, name: 'John' })
|
|
162
|
+
),
|
|
163
|
+
)
|
|
164
|
+
beforeAll(() => server.listen())
|
|
165
|
+
afterEach(() => server.resetHandlers())
|
|
166
|
+
afterAll(() => server.close())
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Playwright E2E
|
|
170
|
+
|
|
171
|
+
```typescript
|
|
172
|
+
// playwright.config.ts 核心
|
|
173
|
+
export default defineConfig({
|
|
174
|
+
testDir: './e2e',
|
|
175
|
+
use: { baseURL: 'http://localhost:3000', trace: 'on-first-retry' },
|
|
176
|
+
webServer: { command: 'npm run dev', url: 'http://localhost:3000' },
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
// Page Object 模式
|
|
180
|
+
class LoginPage {
|
|
181
|
+
constructor(private page: Page) {}
|
|
182
|
+
async login(email: string, password: string) {
|
|
183
|
+
await this.page.fill('[name="email"]', email)
|
|
184
|
+
await this.page.fill('[name="password"]', password)
|
|
185
|
+
await this.page.click('[type="submit"]')
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 测试 Checklist
|
|
191
|
+
|
|
192
|
+
- 遵循 AAA 模式(Arrange / Act / Assert)
|
|
193
|
+
- 测试行为而非实现
|
|
194
|
+
- Mock 外部依赖(API、时间)
|
|
195
|
+
- 测试边界条件和错误路径
|
|
196
|
+
- CI 中自动运行 + 覆盖率门禁 80%+
|
|
197
|
+
|
|
198
|
+
## 三、构建工具
|
|
199
|
+
|
|
200
|
+
### 选型决策
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
新项目 React/Vue → Vite | Next.js → Turbopack | 零配置 → Parcel
|
|
204
|
+
库开发 → Rollup / esbuild
|
|
205
|
+
老项目复杂配置 → 保持 Webpack | 可迁移 → Vite
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### 工具对比
|
|
209
|
+
|
|
210
|
+
| 工具 | 冷启动 | HMR | 生产构建 | 生态 |
|
|
211
|
+
|------|--------|-----|----------|------|
|
|
212
|
+
| Vite | < 1s | < 100ms | 10-30s | 成熟 |
|
|
213
|
+
| Webpack | 10-30s | 1-3s | 30-60s | 最丰富 |
|
|
214
|
+
| Turbopack | < 1s | < 100ms | 10-20s | 新兴 |
|
|
215
|
+
| esbuild | < 1s | N/A | 5-10s | 基础 |
|
|
216
|
+
|
|
217
|
+
### Vite 核心配置
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
export default defineConfig({
|
|
221
|
+
plugins: [react()],
|
|
222
|
+
resolve: { alias: { '@': path.resolve(__dirname, './src') } },
|
|
223
|
+
server: {
|
|
224
|
+
port: 3000,
|
|
225
|
+
proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true } },
|
|
226
|
+
},
|
|
227
|
+
build: {
|
|
228
|
+
minify: 'terser',
|
|
229
|
+
terserOptions: { compress: { drop_console: true } },
|
|
230
|
+
rollupOptions: {
|
|
231
|
+
output: {
|
|
232
|
+
manualChunks: { 'react-vendor': ['react', 'react-dom'] },
|
|
233
|
+
entryFileNames: 'assets/[name].[hash].js',
|
|
234
|
+
},
|
|
235
|
+
},
|
|
236
|
+
},
|
|
237
|
+
optimizeDeps: { include: ['react', 'react-dom'] },
|
|
238
|
+
})
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Webpack 生产优化要点
|
|
242
|
+
|
|
243
|
+
```javascript
|
|
244
|
+
optimization: {
|
|
245
|
+
minimize: true,
|
|
246
|
+
minimizer: [new TerserPlugin(), new CssMinimizerPlugin()],
|
|
247
|
+
splitChunks: {
|
|
248
|
+
chunks: 'all',
|
|
249
|
+
cacheGroups: {
|
|
250
|
+
react: { test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/, priority: 20 },
|
|
251
|
+
vendor: { test: /[\\/]node_modules[\\/]/, priority: 10 },
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
runtimeChunk: 'single',
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Webpack → Vite 迁移要点
|
|
259
|
+
|
|
260
|
+
1. `npm install -D vite @vitejs/plugin-react`
|
|
261
|
+
2. `index.html` 移到根目录,加 `<script type="module" src="/src/main.tsx">`
|
|
262
|
+
3. `REACT_APP_*` → `VITE_*`,`process.env` → `import.meta.env`
|
|
263
|
+
4. `require()` → `import`
|
|
264
|
+
|
|
265
|
+
### 构建 Checklist
|
|
266
|
+
|
|
267
|
+
- 合理代码分割(路由级 + 第三方库分组)
|
|
268
|
+
- Tree Shaking + 压缩(terser / esbuild)
|
|
269
|
+
- 文件名哈希实现长期缓存
|
|
270
|
+
- Source map 仅 dev 或 hidden
|
|
271
|
+
- 定期 `webpack-bundle-analyzer` / `rollup-plugin-visualizer` 审计
|
|
272
|
+
- CI 缓存 `node_modules` + 构建产物
|
|
273
|
+
|
|
274
|
+
## 工具速查
|
|
275
|
+
|
|
276
|
+
| 类别 | 推荐工具 |
|
|
277
|
+
|------|----------|
|
|
278
|
+
| 构建 | Vite (新项目) / Webpack (复杂项目) |
|
|
279
|
+
| 单元测试 | Vitest |
|
|
280
|
+
| 组件测试 | Testing Library |
|
|
281
|
+
| E2E | Playwright |
|
|
282
|
+
| API Mock | MSW |
|
|
283
|
+
| 性能监控 | web-vitals + Lighthouse |
|
|
284
|
+
| Bundle 分析 | webpack-bundle-analyzer / rollup-plugin-visualizer |
|
|
285
|
+
| 视觉回归 | Playwright screenshots / Chromatic |
|
|
286
|
+
|
|
287
|
+
---
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: glassmorphism
|
|
3
|
+
description: Glassmorphism design system skill. Use when building frosted-glass UI components with blur, transparency, and layered depth effects.
|
|
4
|
+
license: MIT
|
|
5
|
+
user-invocable: false
|
|
6
|
+
disable-model-invocation: false
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Glassmorphism Design Spec
|
|
10
|
+
|
|
11
|
+
## 4 Core Elements
|
|
12
|
+
|
|
13
|
+
1. **Transparency** — Semi-transparent backgrounds using `rgba()` or `hsla()` with alpha `0.05–0.4`
|
|
14
|
+
2. **Blur** — `backdrop-filter: blur()` ranging 8–40px for frosted-glass effect
|
|
15
|
+
3. **Border** — Subtle semi-transparent borders (`1px solid rgba(255,255,255,0.18)`) to define edges
|
|
16
|
+
4. **Shadow** — Soft layered `box-shadow` for depth separation from background
|
|
17
|
+
|
|
18
|
+
## CSS Tokens
|
|
19
|
+
|
|
20
|
+
Reference: [references/tokens.css](references/tokens.css)
|
|
21
|
+
|
|
22
|
+
Use CSS custom properties from `tokens.css` for consistent theming:
|
|
23
|
+
|
|
24
|
+
```css
|
|
25
|
+
@import 'references/tokens.css';
|
|
26
|
+
|
|
27
|
+
.glass-card {
|
|
28
|
+
background: var(--glass-bg);
|
|
29
|
+
backdrop-filter: var(--glass-blur);
|
|
30
|
+
-webkit-backdrop-filter: var(--glass-blur);
|
|
31
|
+
border: var(--glass-border);
|
|
32
|
+
border-radius: var(--glass-radius);
|
|
33
|
+
box-shadow: var(--glass-shadow);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Component Examples
|
|
38
|
+
|
|
39
|
+
### Card
|
|
40
|
+
```css
|
|
41
|
+
.glass-card {
|
|
42
|
+
background: var(--glass-bg);
|
|
43
|
+
backdrop-filter: var(--glass-blur);
|
|
44
|
+
-webkit-backdrop-filter: var(--glass-blur);
|
|
45
|
+
border: var(--glass-border);
|
|
46
|
+
border-radius: var(--glass-radius);
|
|
47
|
+
box-shadow: var(--glass-shadow);
|
|
48
|
+
padding: 1.5rem;
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Navbar
|
|
53
|
+
```css
|
|
54
|
+
.glass-nav {
|
|
55
|
+
background: var(--glass-bg-heavy);
|
|
56
|
+
backdrop-filter: var(--glass-blur-strong);
|
|
57
|
+
-webkit-backdrop-filter: var(--glass-blur-strong);
|
|
58
|
+
border-bottom: var(--glass-border);
|
|
59
|
+
box-shadow: var(--glass-shadow);
|
|
60
|
+
position: sticky;
|
|
61
|
+
top: 0;
|
|
62
|
+
z-index: 100;
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Modal Overlay
|
|
67
|
+
```css
|
|
68
|
+
.glass-modal-backdrop {
|
|
69
|
+
background: rgba(0, 0, 0, 0.4);
|
|
70
|
+
backdrop-filter: blur(4px);
|
|
71
|
+
}
|
|
72
|
+
.glass-modal {
|
|
73
|
+
background: var(--glass-bg-heavy);
|
|
74
|
+
backdrop-filter: var(--glass-blur-strong);
|
|
75
|
+
-webkit-backdrop-filter: var(--glass-blur-strong);
|
|
76
|
+
border: var(--glass-border);
|
|
77
|
+
border-radius: var(--glass-radius-lg);
|
|
78
|
+
box-shadow: var(--glass-shadow-elevated);
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Button
|
|
83
|
+
```css
|
|
84
|
+
.glass-btn {
|
|
85
|
+
background: var(--glass-bg-light);
|
|
86
|
+
backdrop-filter: var(--glass-blur-light);
|
|
87
|
+
-webkit-backdrop-filter: var(--glass-blur-light);
|
|
88
|
+
border: var(--glass-border);
|
|
89
|
+
border-radius: var(--glass-radius);
|
|
90
|
+
transition: background 0.2s;
|
|
91
|
+
}
|
|
92
|
+
.glass-btn:hover {
|
|
93
|
+
background: var(--glass-bg);
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Browser Compatibility
|
|
98
|
+
|
|
99
|
+
| Feature | Chrome | Firefox | Safari | Edge |
|
|
100
|
+
|---------|--------|---------|--------|------|
|
|
101
|
+
| `backdrop-filter` | 76+ | 103+ | 9+ (`-webkit-`) | 79+ |
|
|
102
|
+
| `rgba()` backgrounds | All | All | All | All |
|
|
103
|
+
|
|
104
|
+
- Always include `-webkit-backdrop-filter` for Safari support
|
|
105
|
+
- Firefox <103: use `@supports` fallback with solid semi-transparent bg
|
|
106
|
+
- Fallback pattern:
|
|
107
|
+
|
|
108
|
+
```css
|
|
109
|
+
.glass-card {
|
|
110
|
+
background: rgba(255, 255, 255, 0.85); /* fallback */
|
|
111
|
+
}
|
|
112
|
+
@supports (backdrop-filter: blur(1px)) {
|
|
113
|
+
.glass-card {
|
|
114
|
+
background: var(--glass-bg);
|
|
115
|
+
backdrop-filter: var(--glass-blur);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Accessibility Notes
|
|
121
|
+
|
|
122
|
+
- Ensure **contrast ratio ≥ 4.5:1** for text over glass surfaces — test against all possible backgrounds
|
|
123
|
+
- Provide `prefers-reduced-transparency` media query to disable blur/transparency for users who need it
|
|
124
|
+
- Avoid placing critical text on highly transparent surfaces without a fallback
|
|
125
|
+
- Use `prefers-contrast: more` to increase border opacity and reduce transparency
|
|
126
|
+
|
|
127
|
+
```css
|
|
128
|
+
@media (prefers-reduced-transparency: reduce) {
|
|
129
|
+
.glass-card {
|
|
130
|
+
background: rgba(255, 255, 255, 0.92);
|
|
131
|
+
backdrop-filter: none;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
@media (prefers-contrast: more) {
|
|
135
|
+
.glass-card {
|
|
136
|
+
background: rgba(255, 255, 255, 0.85);
|
|
137
|
+
border: 1px solid rgba(0, 0, 0, 0.3);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
/* Backgrounds */
|
|
3
|
+
--glass-bg-light: rgba(255, 255, 255, 0.08);
|
|
4
|
+
--glass-bg: rgba(255, 255, 255, 0.15);
|
|
5
|
+
--glass-bg-heavy: rgba(255, 255, 255, 0.25);
|
|
6
|
+
|
|
7
|
+
/* Blur */
|
|
8
|
+
--glass-blur-light: blur(8px);
|
|
9
|
+
--glass-blur: blur(16px);
|
|
10
|
+
--glass-blur-strong: blur(32px);
|
|
11
|
+
|
|
12
|
+
/* Border */
|
|
13
|
+
--glass-border: 1px solid rgba(255, 255, 255, 0.18);
|
|
14
|
+
|
|
15
|
+
/* Radius */
|
|
16
|
+
--glass-radius: 12px;
|
|
17
|
+
--glass-radius-lg: 20px;
|
|
18
|
+
|
|
19
|
+
/* Shadow */
|
|
20
|
+
--glass-shadow: 0 4px 30px rgba(0, 0, 0, 0.1);
|
|
21
|
+
--glass-shadow-elevated: 0 8px 40px rgba(0, 0, 0, 0.15);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/* Dark theme overrides */
|
|
25
|
+
[data-theme="dark"] {
|
|
26
|
+
--glass-bg-light: rgba(255, 255, 255, 0.04);
|
|
27
|
+
--glass-bg: rgba(255, 255, 255, 0.08);
|
|
28
|
+
--glass-bg-heavy: rgba(255, 255, 255, 0.14);
|
|
29
|
+
--glass-border: 1px solid rgba(255, 255, 255, 0.12);
|
|
30
|
+
--glass-shadow: 0 4px 30px rgba(0, 0, 0, 0.3);
|
|
31
|
+
--glass-shadow-elevated: 0 8px 40px rgba(0, 0, 0, 0.4);
|
|
32
|
+
}
|