ima-claude 2.9.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/LICENSE +21 -0
- package/README.md +463 -0
- package/dist/cli.js +1064 -0
- package/package.json +49 -0
- package/platforms/claude/adapter.ts +115 -0
- package/platforms/junie/adapter.ts +254 -0
- package/platforms/junie/agents-template.md +113 -0
- package/platforms/junie/hook-translations.md +84 -0
- package/platforms/shared/detector.ts +27 -0
- package/platforms/shared/installer.ts +202 -0
- package/platforms/shared/types.ts +78 -0
- package/plugins/ima-claude/.claude-plugin/plugin.json +25 -0
- package/plugins/ima-claude/agents/explorer.md +30 -0
- package/plugins/ima-claude/agents/implementer.md +30 -0
- package/plugins/ima-claude/agents/memory.md +42 -0
- package/plugins/ima-claude/agents/reviewer.md +53 -0
- package/plugins/ima-claude/agents/tester.md +33 -0
- package/plugins/ima-claude/agents/wp-developer.md +46 -0
- package/plugins/ima-claude/hooks/README.md +145 -0
- package/plugins/ima-claude/hooks/atlassian_prereqs.py +112 -0
- package/plugins/ima-claude/hooks/block_sed_edits.py +59 -0
- package/plugins/ima-claude/hooks/bootstrap.sh +90 -0
- package/plugins/ima-claude/hooks/bootstrap_utility_check.py +94 -0
- package/plugins/ima-claude/hooks/composer_autoload_check.py +70 -0
- package/plugins/ima-claude/hooks/docs_organization.py +104 -0
- package/plugins/ima-claude/hooks/enforce_rg_over_grep.py +56 -0
- package/plugins/ima-claude/hooks/fp_utility_check.py +90 -0
- package/plugins/ima-claude/hooks/hook_logger.py +69 -0
- package/plugins/ima-claude/hooks/hooks.json +239 -0
- package/plugins/ima-claude/hooks/jira_issue_fetch.py +79 -0
- package/plugins/ima-claude/hooks/jquery_in_wordpress.py +92 -0
- package/plugins/ima-claude/hooks/memory_bootstrap.py +79 -0
- package/plugins/ima-claude/hooks/memory_store_reminder.py +75 -0
- package/plugins/ima-claude/hooks/prompt_coach.py +125 -0
- package/plugins/ima-claude/hooks/prompt_coach_digest.md +48 -0
- package/plugins/ima-claude/hooks/prompt_coach_system.md +30 -0
- package/plugins/ima-claude/hooks/sequential_thinking_check.py +81 -0
- package/plugins/ima-claude/hooks/serena_over_grep.py +96 -0
- package/plugins/ima-claude/hooks/serena_over_read.py +66 -0
- package/plugins/ima-claude/hooks/serena_project_check.py +133 -0
- package/plugins/ima-claude/hooks/sql_injection_check.py +73 -0
- package/plugins/ima-claude/hooks/task_master_after_plan.py +31 -0
- package/plugins/ima-claude/hooks/task_master_before_impl.py +93 -0
- package/plugins/ima-claude/hooks/tavily_extract_advanced.py +48 -0
- package/plugins/ima-claude/hooks/vestige_before_external.py +86 -0
- package/plugins/ima-claude/hooks/webfetch_to_tavily.py +42 -0
- package/plugins/ima-claude/hooks/websearch_to_tavily.py +41 -0
- package/plugins/ima-claude/hooks/wp_security_check.py +150 -0
- package/plugins/ima-claude/personalities/README.md +45 -0
- package/plugins/ima-claude/personalities/enable-40k.md +69 -0
- package/plugins/ima-claude/personalities/enable-templars.md +69 -0
- package/plugins/ima-claude/skills/.research-summary.md +340 -0
- package/plugins/ima-claude/skills/architect/SKILL.md +304 -0
- package/plugins/ima-claude/skills/compound-bridge/SKILL.md +200 -0
- package/plugins/ima-claude/skills/discourse/SKILL.md +440 -0
- package/plugins/ima-claude/skills/discourse-admin/SKILL.md +192 -0
- package/plugins/ima-claude/skills/discourse-admin/references/api-endpoints.md +441 -0
- package/plugins/ima-claude/skills/discourse-admin/references/gotchas.md +107 -0
- package/plugins/ima-claude/skills/discourse-admin/references/staging-defaults.md +98 -0
- package/plugins/ima-claude/skills/discourse-admin/scripts/discourse-admin.py +319 -0
- package/plugins/ima-claude/skills/docs-organize/SKILL.md +254 -0
- package/plugins/ima-claude/skills/docs-organize/templates/active-README.md +50 -0
- package/plugins/ima-claude/skills/docs-organize/templates/archive-README.md +57 -0
- package/plugins/ima-claude/skills/docs-organize/templates/docs-README.md +43 -0
- package/plugins/ima-claude/skills/docs-organize/templates/phase-archive-README.md +83 -0
- package/plugins/ima-claude/skills/docs-organize/templates/section-README.md +48 -0
- package/plugins/ima-claude/skills/docs-organize/templates/transient-README.md +79 -0
- package/plugins/ima-claude/skills/docs-organize/templates/transient-gitignore +9 -0
- package/plugins/ima-claude/skills/ember-discourse/SKILL.md +496 -0
- package/plugins/ima-claude/skills/functional-programmer/SKILL.md +258 -0
- package/plugins/ima-claude/skills/ima-bootstrap/SKILL.md +278 -0
- package/plugins/ima-claude/skills/ima-bootstrap/references/bootstrap-patterns.md +356 -0
- package/plugins/ima-claude/skills/ima-bootstrap/references/ima-brand.md +273 -0
- package/plugins/ima-claude/skills/ima-bootstrap/references/theme-integration.md +212 -0
- package/plugins/ima-claude/skills/ima-brand/SKILL.md +108 -0
- package/plugins/ima-claude/skills/ima-brand/references/brand-identity.md +140 -0
- package/plugins/ima-claude/skills/ima-brand/references/digital-standards.md +180 -0
- package/plugins/ima-claude/skills/ima-brand/references/visual-system.md +173 -0
- package/plugins/ima-claude/skills/ima-forms-expert/SKILL.md +175 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/container-components.md +154 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/examples.md +328 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/field-components.md +298 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/form-factory.md +193 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/quick-reference.md +153 -0
- package/plugins/ima-claude/skills/ima-forms-expert/references/validation-engine.md +336 -0
- package/plugins/ima-claude/skills/jira-checkpoint/SKILL.md +178 -0
- package/plugins/ima-claude/skills/jquery/SKILL.md +413 -0
- package/plugins/ima-claude/skills/js-fp/SKILL.md +463 -0
- package/plugins/ima-claude/skills/js-fp/core-principles.md +487 -0
- package/plugins/ima-claude/skills/js-fp/examples/pure-functions.js +260 -0
- package/plugins/ima-claude/skills/js-fp/examples/tests/pure-functions.test.js +262 -0
- package/plugins/ima-claude/skills/js-fp/references/anti-patterns.md +120 -0
- package/plugins/ima-claude/skills/js-fp/references/performance-patterns.md +116 -0
- package/plugins/ima-claude/skills/js-fp/references/testing-patterns.md +134 -0
- package/plugins/ima-claude/skills/js-fp-api/SKILL.md +280 -0
- package/plugins/ima-claude/skills/js-fp-api/examples/crud-endpoint.js +258 -0
- package/plugins/ima-claude/skills/js-fp-api/references/middleware-patterns.md +134 -0
- package/plugins/ima-claude/skills/js-fp-api/references/security-sql.md +110 -0
- package/plugins/ima-claude/skills/js-fp-api/references/validation-patterns.md +165 -0
- package/plugins/ima-claude/skills/js-fp-react/SKILL.md +447 -0
- package/plugins/ima-claude/skills/js-fp-react/examples/ProductCard.tsx +65 -0
- package/plugins/ima-claude/skills/js-fp-react/references/hooks-advanced.md +136 -0
- package/plugins/ima-claude/skills/js-fp-react/references/performance-patterns.md +175 -0
- package/plugins/ima-claude/skills/js-fp-vue/SKILL.md +322 -0
- package/plugins/ima-claude/skills/js-fp-vue/references/complete-examples.md +397 -0
- package/plugins/ima-claude/skills/js-fp-vue/references/composables-advanced.md +282 -0
- package/plugins/ima-claude/skills/js-fp-vue/references/reactivity-patterns.md +348 -0
- package/plugins/ima-claude/skills/js-fp-vue/references/testing.md +314 -0
- package/plugins/ima-claude/skills/js-fp-wordpress/SKILL.md +301 -0
- package/plugins/ima-claude/skills/js-fp-wordpress/references/ajax-patterns.md +192 -0
- package/plugins/ima-claude/skills/js-fp-wordpress/references/event-patterns.md +136 -0
- package/plugins/ima-claude/skills/js-fp-wordpress/references/wp-integration.md +248 -0
- package/plugins/ima-claude/skills/livecanvas/SKILL.md +209 -0
- package/plugins/ima-claude/skills/livecanvas/references/livecanvas-features.md +311 -0
- package/plugins/ima-claude/skills/livecanvas/references/loops-and-logic.md +730 -0
- package/plugins/ima-claude/skills/livecanvas/references/picostrap.md +227 -0
- package/plugins/ima-claude/skills/mcp-atlassian/SKILL.md +339 -0
- package/plugins/ima-claude/skills/mcp-context7/SKILL.md +109 -0
- package/plugins/ima-claude/skills/mcp-memory/SKILL.md +182 -0
- package/plugins/ima-claude/skills/mcp-qdrant/SKILL.md +233 -0
- package/plugins/ima-claude/skills/mcp-sequential/SKILL.md +149 -0
- package/plugins/ima-claude/skills/mcp-serena/SKILL.md +174 -0
- package/plugins/ima-claude/skills/mcp-tavily/SKILL.md +118 -0
- package/plugins/ima-claude/skills/mcp-vestige/SKILL.md +259 -0
- package/plugins/ima-claude/skills/php-authnet/SKILL.md +275 -0
- package/plugins/ima-claude/skills/php-authnet/references/api-reference.md +624 -0
- package/plugins/ima-claude/skills/php-authnet/references/sandbox-testing.md +424 -0
- package/plugins/ima-claude/skills/php-fp/SKILL.md +333 -0
- package/plugins/ima-claude/skills/php-fp/examples/pure-functions.php +403 -0
- package/plugins/ima-claude/skills/php-fp/examples/tests/PureFunctionsTest.php +515 -0
- package/plugins/ima-claude/skills/php-fp/references/core-principles.md +277 -0
- package/plugins/ima-claude/skills/php-fp/references/testing-patterns.md +374 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/SKILL.md +216 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/references/fp-patterns.md +275 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/references/plugin-architecture.md +295 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/references/security-examples.md +203 -0
- package/plugins/ima-claude/skills/php-fp-wordpress/references/testing-strategy.md +259 -0
- package/plugins/ima-claude/skills/phpunit-wp/SKILL.md +716 -0
- package/plugins/ima-claude/skills/playwright/SKILL.md +434 -0
- package/plugins/ima-claude/skills/playwright/references/accessibility-testing.md +153 -0
- package/plugins/ima-claude/skills/playwright/references/ci-cd.md +268 -0
- package/plugins/ima-claude/skills/playwright/references/network-mocking.md +270 -0
- package/plugins/ima-claude/skills/playwright/references/visual-regression.md +215 -0
- package/plugins/ima-claude/skills/py-fp/SKILL.md +663 -0
- package/plugins/ima-claude/skills/py-fp/examples/pure-functions.py +185 -0
- package/plugins/ima-claude/skills/py-fp/examples/tests/test_pure_functions.py +244 -0
- package/plugins/ima-claude/skills/py-fp/references/core-principles.md +381 -0
- package/plugins/ima-claude/skills/py-fp/references/testing-patterns.md +283 -0
- package/plugins/ima-claude/skills/quasar-fp/SKILL.md +327 -0
- package/plugins/ima-claude/skills/quasar-fp/metadata.json +85 -0
- package/plugins/ima-claude/skills/quasar-fp/references/component-patterns.md +257 -0
- package/plugins/ima-claude/skills/quasar-fp/references/theme-integration.md +233 -0
- package/plugins/ima-claude/skills/quasar-fp/references/utility-classes.md +237 -0
- package/plugins/ima-claude/skills/quickstart/SKILL.md +129 -0
- package/plugins/ima-claude/skills/rails/SKILL.md +359 -0
- package/plugins/ima-claude/skills/resume-session/SKILL.md +68 -0
- package/plugins/ima-claude/skills/rg/SKILL.md +205 -0
- package/plugins/ima-claude/skills/ruby-fp/SKILL.md +336 -0
- package/plugins/ima-claude/skills/save-session/SKILL.md +81 -0
- package/plugins/ima-claude/skills/scorecard/SKILL.md +96 -0
- package/plugins/ima-claude/skills/skill-analyzer/SKILL.md +127 -0
- package/plugins/ima-claude/skills/skill-analyzer/references/advanced-checklist.md +44 -0
- package/plugins/ima-claude/skills/skill-analyzer/references/core-checklist.md +60 -0
- package/plugins/ima-claude/skills/skill-analyzer/scripts/analyze_skill.py +418 -0
- package/plugins/ima-claude/skills/skill-creator/LICENSE.txt +202 -0
- package/plugins/ima-claude/skills/skill-creator/SKILL.md +343 -0
- package/plugins/ima-claude/skills/skill-creator/references/output-patterns.md +82 -0
- package/plugins/ima-claude/skills/skill-creator/references/workflows.md +28 -0
- package/plugins/ima-claude/skills/skill-creator/scripts/init_skill.py +303 -0
- package/plugins/ima-claude/skills/skill-creator/scripts/package_skill.py +110 -0
- package/plugins/ima-claude/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/plugins/ima-claude/skills/task-master/SKILL.md +51 -0
- package/plugins/ima-claude/skills/task-planner/SKILL.md +228 -0
- package/plugins/ima-claude/skills/task-runner/SKILL.md +192 -0
- package/plugins/ima-claude/skills/unit-testing/SKILL.md +198 -0
- package/plugins/ima-claude/skills/unit-testing/references/mock-patterns.md +181 -0
- package/plugins/ima-claude/skills/unit-testing/references/tdd-workflow.md +177 -0
- package/plugins/ima-claude/skills/unit-testing/references/test-strategy.md +126 -0
- package/plugins/ima-claude/skills/wp-local/SKILL.md +246 -0
- package/plugins/ima-claude/skills/wp-local/references/configuration.md +198 -0
- package/plugins/ima-claude/skills/wp-local/references/wp-cli-reference.md +406 -0
- package/plugins/ima-claude/skills/wp-local/scripts/wp-local.sh +61 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# React Performance Patterns
|
|
2
|
+
|
|
3
|
+
Performance optimization strategies: measure first, optimize with evidence.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
1. [When to Optimize](#when-to-optimize)
|
|
8
|
+
2. [React.memo Strategies](#reactmemo-strategies)
|
|
9
|
+
3. [Virtualization](#virtualization)
|
|
10
|
+
4. [Code Splitting](#code-splitting)
|
|
11
|
+
5. [Render Optimization](#render-optimization)
|
|
12
|
+
|
|
13
|
+
## When to Optimize
|
|
14
|
+
|
|
15
|
+
**Rule**: Optimize only with evidence. Use React DevTools Profiler first.
|
|
16
|
+
|
|
17
|
+
### Signs You Need Optimization
|
|
18
|
+
|
|
19
|
+
- Janky scrolling in lists (> 100 items)
|
|
20
|
+
- Input lag when typing
|
|
21
|
+
- High "Render Duration" in Profiler (> 16ms)
|
|
22
|
+
|
|
23
|
+
### Signs You Do NOT Need Optimization
|
|
24
|
+
|
|
25
|
+
- Small component counts (< 50 on screen)
|
|
26
|
+
- Simple prop structures
|
|
27
|
+
- No user-reported performance issues
|
|
28
|
+
|
|
29
|
+
## React.memo Strategies
|
|
30
|
+
|
|
31
|
+
### When memo() Helps
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
// Good: Expensive child with stable parent
|
|
35
|
+
const ExpensiveChart = memo(({ data }: { data: DataPoint[] }) => (
|
|
36
|
+
<svg>{/* expensive rendering */}</svg>
|
|
37
|
+
))
|
|
38
|
+
|
|
39
|
+
// Good: Child in frequently-updating parent
|
|
40
|
+
const Parent = () => {
|
|
41
|
+
const [count, setCount] = useState(0)
|
|
42
|
+
return (
|
|
43
|
+
<div>
|
|
44
|
+
<button onClick={() => setCount(c => c + 1)}>{count}</button>
|
|
45
|
+
<MemoizedSidebar /> {/* Doesn't need count */}
|
|
46
|
+
</div>
|
|
47
|
+
)
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### When memo() Does NOT Help
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// Bad: Simple component (overhead > benefit)
|
|
55
|
+
const Label = memo(({ text }: { text: string }) => <span>{text}</span>)
|
|
56
|
+
|
|
57
|
+
// Bad: Props change every render anyway
|
|
58
|
+
const BadExample = () => {
|
|
59
|
+
const data = { value: 1 } // New object every render
|
|
60
|
+
return <MemoizedChild data={data} /> // memo is useless
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Fix: Stabilize props
|
|
64
|
+
const GoodExample = () => {
|
|
65
|
+
const data = useMemo(() => ({ value: 1 }), [])
|
|
66
|
+
return <MemoizedChild data={data} />
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Virtualization
|
|
71
|
+
|
|
72
|
+
For lists > 100 items, render only visible items.
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { FixedSizeList } from 'react-window'
|
|
76
|
+
|
|
77
|
+
const Row = memo(({ index, style, data }: RowProps) => (
|
|
78
|
+
<div style={style}>{data[index].name}</div>
|
|
79
|
+
))
|
|
80
|
+
|
|
81
|
+
const VirtualizedList = ({ items }: { items: Item[] }) => (
|
|
82
|
+
<FixedSizeList
|
|
83
|
+
height={400}
|
|
84
|
+
width="100%"
|
|
85
|
+
itemCount={items.length}
|
|
86
|
+
itemSize={50}
|
|
87
|
+
itemData={items}
|
|
88
|
+
>
|
|
89
|
+
{Row}
|
|
90
|
+
</FixedSizeList>
|
|
91
|
+
)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Code Splitting
|
|
95
|
+
|
|
96
|
+
### Route-Based Splitting
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { lazy, Suspense } from 'react'
|
|
100
|
+
|
|
101
|
+
const Dashboard = lazy(() => import('./pages/Dashboard'))
|
|
102
|
+
const Settings = lazy(() => import('./pages/Settings'))
|
|
103
|
+
|
|
104
|
+
const App = () => (
|
|
105
|
+
<Suspense fallback={<LoadingSpinner />}>
|
|
106
|
+
<Routes>
|
|
107
|
+
<Route path="/" element={<Dashboard />} />
|
|
108
|
+
<Route path="/settings" element={<Settings />} />
|
|
109
|
+
</Routes>
|
|
110
|
+
</Suspense>
|
|
111
|
+
)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Preloading
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
const preloadEditor = () => import('./HeavyEditor')
|
|
118
|
+
|
|
119
|
+
const EditButton = ({ onClick }: { onClick: () => void }) => (
|
|
120
|
+
<button onClick={onClick} onMouseEnter={preloadEditor}>
|
|
121
|
+
Edit
|
|
122
|
+
</button>
|
|
123
|
+
)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Render Optimization
|
|
127
|
+
|
|
128
|
+
### State Colocation
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
// Bad: State too high
|
|
132
|
+
const Parent = () => {
|
|
133
|
+
const [inputValue, setInputValue] = useState('')
|
|
134
|
+
return (
|
|
135
|
+
<div>
|
|
136
|
+
<ExpensiveTree /> {/* Re-renders on every keystroke */}
|
|
137
|
+
<input value={inputValue} onChange={e => setInputValue(e.target.value)} />
|
|
138
|
+
</div>
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Good: State colocated
|
|
143
|
+
const Parent = () => (
|
|
144
|
+
<div>
|
|
145
|
+
<ExpensiveTree />
|
|
146
|
+
<SearchInput /> {/* State lives here */}
|
|
147
|
+
</div>
|
|
148
|
+
)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Children as Props Pattern
|
|
152
|
+
|
|
153
|
+
```typescript
|
|
154
|
+
const ScrollContainer = ({ children }: { children: React.ReactNode }) => {
|
|
155
|
+
const [scrollY, setScrollY] = useState(0)
|
|
156
|
+
// children does NOT re-render when scrollY changes
|
|
157
|
+
return (
|
|
158
|
+
<div>
|
|
159
|
+
<ScrollIndicator position={scrollY} />
|
|
160
|
+
{children}
|
|
161
|
+
</div>
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Quick Reference
|
|
167
|
+
|
|
168
|
+
| Problem | Solution |
|
|
169
|
+
|---------|----------|
|
|
170
|
+
| Component re-renders too often | `React.memo()` + stable props |
|
|
171
|
+
| Expensive computation | `useMemo()` |
|
|
172
|
+
| Callback causes child re-render | `useCallback()` |
|
|
173
|
+
| Long list (>100 items) | Virtualization |
|
|
174
|
+
| Large bundle size | Code splitting |
|
|
175
|
+
| State causes sibling re-render | State colocation |
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: "js-fp-vue"
|
|
3
|
+
description: "FP patterns for Vue.js with composables, wrappers, and pure components - references js-fp core"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# JavaScript FP - Vue.js
|
|
7
|
+
|
|
8
|
+
Functional programming patterns for Vue.js components with composables, wrapper patterns, and pure component architecture.
|
|
9
|
+
|
|
10
|
+
## When to Use This Skill
|
|
11
|
+
|
|
12
|
+
- Building Vue.js 3+ components
|
|
13
|
+
- Need pure, testable component logic
|
|
14
|
+
- Implementing composables with FP principles
|
|
15
|
+
- Wrapper patterns for external dependencies
|
|
16
|
+
- Performance optimization without over-engineering
|
|
17
|
+
|
|
18
|
+
## Core Philosophy
|
|
19
|
+
|
|
20
|
+
**Pure components** with **business logic in composables**, **wrapper pattern for side effects**, and **simple state management** (composables > stores for 95% of use cases).
|
|
21
|
+
|
|
22
|
+
**Foundation**: This skill builds on `js-fp` core principles. Reference `../js-fp/SKILL.md` for purity, composition, dependency injection, and testing patterns.
|
|
23
|
+
|
|
24
|
+
## Pure Component with Composable Pattern
|
|
25
|
+
|
|
26
|
+
**Rule**: Separate business logic (composables) from presentation (components).
|
|
27
|
+
|
|
28
|
+
```vue
|
|
29
|
+
<script setup lang="ts">
|
|
30
|
+
/**
|
|
31
|
+
* Business logic in composables, presentation in component
|
|
32
|
+
* - Zero side effects in component
|
|
33
|
+
* - All logic in composables
|
|
34
|
+
* - 100% testable through dependency injection
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
import type { Ref } from 'vue'
|
|
38
|
+
import { computed, readonly, toRef } from 'vue'
|
|
39
|
+
|
|
40
|
+
interface UserData {
|
|
41
|
+
id: string
|
|
42
|
+
name: string
|
|
43
|
+
email: string
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface UserConfig {
|
|
47
|
+
showEmail: boolean
|
|
48
|
+
variant: 'compact' | 'detailed'
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// ───── Composable with pure business logic ─────
|
|
52
|
+
const useUserLogic = (
|
|
53
|
+
userData: Readonly<Ref<UserData>>,
|
|
54
|
+
config: Readonly<Ref<UserConfig>>
|
|
55
|
+
) => {
|
|
56
|
+
// Pure computation - no side effects
|
|
57
|
+
const displayData = computed(() => {
|
|
58
|
+
const user = userData.value
|
|
59
|
+
const cfg = config.value
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
...user,
|
|
63
|
+
displayName: user.name.trim(),
|
|
64
|
+
...(cfg.showEmail ? {} : { email: undefined })
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
// Pre-compiled CSS for performance
|
|
69
|
+
const cssClasses = computed(() => ({
|
|
70
|
+
card: `user-card user-card--${config.value.variant}`,
|
|
71
|
+
name: `user-card__name user-card__name--${config.value.variant}`
|
|
72
|
+
}))
|
|
73
|
+
|
|
74
|
+
return { displayData, cssClasses }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// ───── Component props ─────
|
|
78
|
+
const props = defineProps<{
|
|
79
|
+
userData: UserData
|
|
80
|
+
config: UserConfig
|
|
81
|
+
}>()
|
|
82
|
+
|
|
83
|
+
// ───── Use composable ─────
|
|
84
|
+
const { displayData, cssClasses } = useUserLogic(
|
|
85
|
+
readonly(toRef(props, 'userData')),
|
|
86
|
+
readonly(toRef(props, 'config'))
|
|
87
|
+
)
|
|
88
|
+
</script>
|
|
89
|
+
|
|
90
|
+
<template>
|
|
91
|
+
<div :class="cssClasses.card">
|
|
92
|
+
<h3 :class="cssClasses.name">{{ displayData.displayName }}</h3>
|
|
93
|
+
<p v-if="config.showEmail && displayData.email">{{ displayData.email }}</p>
|
|
94
|
+
</div>
|
|
95
|
+
</template>
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Wrapper Pattern for External Dependencies
|
|
99
|
+
|
|
100
|
+
**Rule**: Isolate side effects in wrapper layer, keep inner component pure.
|
|
101
|
+
|
|
102
|
+
```vue
|
|
103
|
+
<!-- UserDisplayPure.vue - Pure Inner Component -->
|
|
104
|
+
<script setup lang="ts">
|
|
105
|
+
const props = defineProps<{
|
|
106
|
+
user: UserData
|
|
107
|
+
}>()
|
|
108
|
+
|
|
109
|
+
const emit = defineEmits<{
|
|
110
|
+
update: [user: UserData]
|
|
111
|
+
}>()
|
|
112
|
+
|
|
113
|
+
const handleUpdate = (updates: Partial<UserData>) => {
|
|
114
|
+
const updatedUser = { ...props.user, ...updates }
|
|
115
|
+
emit('update', updatedUser)
|
|
116
|
+
}
|
|
117
|
+
</script>
|
|
118
|
+
|
|
119
|
+
<template>
|
|
120
|
+
<div class="user-display">
|
|
121
|
+
<h3>{{ user.name }}</h3>
|
|
122
|
+
<button @click="handleUpdate({ name: 'Updated' })">Update</button>
|
|
123
|
+
</div>
|
|
124
|
+
</template>
|
|
125
|
+
|
|
126
|
+
<!-- UserDisplayWrapper.vue - Wrapper with Side Effects -->
|
|
127
|
+
<script setup lang="ts">
|
|
128
|
+
import { ref } from 'vue'
|
|
129
|
+
import UserDisplayPure from './UserDisplayPure.vue'
|
|
130
|
+
|
|
131
|
+
const props = defineProps<{
|
|
132
|
+
userId: string
|
|
133
|
+
}>()
|
|
134
|
+
|
|
135
|
+
// Side effect: External API call
|
|
136
|
+
const user = ref<UserData | null>(null)
|
|
137
|
+
const loading = ref(true)
|
|
138
|
+
const error = ref<Error | null>(null)
|
|
139
|
+
|
|
140
|
+
const fetchUser = async () => {
|
|
141
|
+
try {
|
|
142
|
+
loading.value = true
|
|
143
|
+
user.value = await userApi.getUser(props.userId)
|
|
144
|
+
} catch (e) {
|
|
145
|
+
error.value = e as Error
|
|
146
|
+
} finally {
|
|
147
|
+
loading.value = false
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Side effect isolated to wrapper
|
|
152
|
+
const handleUpdate = async (updatedUser: UserData) => {
|
|
153
|
+
await userApi.updateUser(updatedUser)
|
|
154
|
+
await fetchUser() // Refresh
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Initial load
|
|
158
|
+
fetchUser()
|
|
159
|
+
</script>
|
|
160
|
+
|
|
161
|
+
<template>
|
|
162
|
+
<UserDisplayPure
|
|
163
|
+
v-if="user && !loading"
|
|
164
|
+
:user="user"
|
|
165
|
+
@update="handleUpdate"
|
|
166
|
+
/>
|
|
167
|
+
<div v-else-if="loading">Loading...</div>
|
|
168
|
+
<div v-else-if="error">Error: {{ error.message }}</div>
|
|
169
|
+
</template>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## Vue 3 Composition API Best Practices
|
|
173
|
+
|
|
174
|
+
### Reactive vs. Ref
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
// Use ref for primitives and simple objects
|
|
178
|
+
const count = ref(0)
|
|
179
|
+
const user = ref<UserData>({ id: '1', name: 'Alice', email: 'alice@test.com' })
|
|
180
|
+
|
|
181
|
+
// Use reactive sparingly (only for complex nested objects)
|
|
182
|
+
const state = reactive({
|
|
183
|
+
users: [],
|
|
184
|
+
filters: { search: '', minAge: 0 }
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
// Prefer computed over watch
|
|
188
|
+
const filteredUsers = computed(() =>
|
|
189
|
+
state.users.filter(u => u.name.includes(state.filters.search))
|
|
190
|
+
)
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Lifecycle Hooks
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
import { onMounted, onUnmounted } from 'vue'
|
|
197
|
+
|
|
198
|
+
// Side effects in lifecycle hooks
|
|
199
|
+
onMounted(() => {
|
|
200
|
+
fetchData()
|
|
201
|
+
const interval = setInterval(refreshData, 60000)
|
|
202
|
+
|
|
203
|
+
onUnmounted(() => {
|
|
204
|
+
clearInterval(interval)
|
|
205
|
+
})
|
|
206
|
+
})
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Anti-Patterns (AVOID)
|
|
210
|
+
|
|
211
|
+
### Pinia/Vuex Over-Usage
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
// BAD: Complex store for simple state
|
|
215
|
+
const useUserStore = defineStore('users', {
|
|
216
|
+
state: () => ({ users: [], loading: false }),
|
|
217
|
+
actions: {
|
|
218
|
+
async fetchUsers() { /* complex async logic */ }
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
// GOOD: Simple composable (covers 95% of use cases)
|
|
223
|
+
const useUsers = () => {
|
|
224
|
+
const users = ref<UserData[]>([])
|
|
225
|
+
const loading = ref(false)
|
|
226
|
+
|
|
227
|
+
const fetchUsers = async () => {
|
|
228
|
+
loading.value = true
|
|
229
|
+
users.value = await userApi.getUsers()
|
|
230
|
+
loading.value = false
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return { users: readonly(users), loading: readonly(loading), fetchUsers }
|
|
234
|
+
}
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Reactive Over-Engineering
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
// BAD: Unnecessary reactive complexity
|
|
241
|
+
const user = reactive({
|
|
242
|
+
profile: reactive({
|
|
243
|
+
settings: reactive({
|
|
244
|
+
theme: 'dark'
|
|
245
|
+
})
|
|
246
|
+
})
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
// GOOD: Simple ref with computed when needed
|
|
250
|
+
const userSettings = ref({ theme: 'dark', notifications: true })
|
|
251
|
+
const isDarkTheme = computed(() => userSettings.value.theme === 'dark')
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Watch Over-Usage
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
// BAD: Watch for derived state
|
|
258
|
+
const fullName = ref('')
|
|
259
|
+
watch([firstName, lastName], () => {
|
|
260
|
+
fullName.value = `${firstName.value} ${lastName.value}`
|
|
261
|
+
})
|
|
262
|
+
|
|
263
|
+
// GOOD: Computed for derived state
|
|
264
|
+
const fullName = computed(() => `${firstName.value} ${lastName.value}`)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## Quality Gates
|
|
268
|
+
|
|
269
|
+
Before implementing any Vue component:
|
|
270
|
+
|
|
271
|
+
1. **Pure composable**: Business logic separated from presentation?
|
|
272
|
+
2. **Wrapper pattern**: Side effects isolated to wrapper component?
|
|
273
|
+
3. **Reactive optimization**: Using computed over watch?
|
|
274
|
+
4. **State management**: Using composables instead of store (unless truly global)?
|
|
275
|
+
5. **Testability**: Can inject mocks for all dependencies?
|
|
276
|
+
6. **FP principles**: Pure functions, immutable updates?
|
|
277
|
+
7. **Performance**: Pre-compiled configurations when appropriate?
|
|
278
|
+
|
|
279
|
+
## When to Load Additional Content
|
|
280
|
+
|
|
281
|
+
### Composables Advanced
|
|
282
|
+
**File**: `references/composables-advanced.md`
|
|
283
|
+
**When**: Complex composable patterns, factory patterns, provide/inject DI
|
|
284
|
+
**Contains**: Composable factory, state management, lifecycle integration, composition patterns
|
|
285
|
+
|
|
286
|
+
### Reactivity Patterns
|
|
287
|
+
**File**: `references/reactivity-patterns.md`
|
|
288
|
+
**When**: Performance optimization, reactivity issues, memory management
|
|
289
|
+
**Contains**: Deep reactive vs ref patterns, shallowRef, computed optimization, cleanup patterns
|
|
290
|
+
|
|
291
|
+
### Testing
|
|
292
|
+
**File**: `references/testing.md`
|
|
293
|
+
**When**: Writing tests for Vue FP components
|
|
294
|
+
**Contains**: Testing pure composables, component tests, wrapper tests, mocking patterns
|
|
295
|
+
|
|
296
|
+
### Complete Examples
|
|
297
|
+
**File**: `references/complete-examples.md`
|
|
298
|
+
**When**: Need full working component examples
|
|
299
|
+
**Contains**: Product card, user dashboard with wrapper, form with validation
|
|
300
|
+
|
|
301
|
+
## Foundation Reference
|
|
302
|
+
|
|
303
|
+
**Core FP Principles**: `../js-fp/SKILL.md`
|
|
304
|
+
- Purity and side effect isolation
|
|
305
|
+
- Composition patterns
|
|
306
|
+
- Dependency injection
|
|
307
|
+
- Immutability
|
|
308
|
+
- Testing strategies
|
|
309
|
+
|
|
310
|
+
**Deep Dive**: `../js-fp/core-principles.md` for complete FP philosophy
|
|
311
|
+
|
|
312
|
+
## Success Metrics
|
|
313
|
+
|
|
314
|
+
- **Testability**: 100% testable composables
|
|
315
|
+
- **Performance**: Pre-compiled configurations, reactive optimization
|
|
316
|
+
- **Maintainability**: Clear separation of concerns
|
|
317
|
+
- **Code Quality**: Simple, readable component logic
|
|
318
|
+
- **Bundle Size**: Minimal overhead, tree-shakeable composables
|
|
319
|
+
|
|
320
|
+
## Philosophy
|
|
321
|
+
|
|
322
|
+
*"Pure component architecture through composables, wrapper patterns for side effects, and simple state management - optimize for testability and simplicity over clever reactivity."*
|