@dianzhong/create-harness-app 0.1.2 → 0.1.4

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.
Files changed (39) hide show
  1. package/dist/index.mjs +4 -0
  2. package/package.json +1 -1
  3. package/templates/harness/full/.claude/agents/code-reviewer.md +1 -1
  4. package/templates/harness/full/.claude/agents/harness-reviewer.md +0 -2
  5. package/templates/harness/full/.claude/rules/skills-mcp.md +2 -3
  6. package/templates/harness/full/.claude/settings.json +1 -1
  7. package/templates/harness/full/docs/ai-harness.md +4 -6
  8. package/templates/harness/full/docs/harness-quick-reference.md +1 -1
  9. package/templates/harness/full/docs/review-checklist.md +1 -1
  10. package/templates/harness/full/scripts/verify-skills.mjs +6 -61
  11. package/templates/harness/full/scripts/verify-skills.test.mjs +1 -11
  12. package/templates/harness/full/.agents/skills/find-skills/SKILL.md +0 -143
  13. package/templates/harness/full/.agents/skills/vue-best-practices/LICENSE.md +0 -21
  14. package/templates/harness/full/.agents/skills/vue-best-practices/SKILL.md +0 -155
  15. package/templates/harness/full/.agents/skills/vue-best-practices/SYNC.md +0 -5
  16. package/templates/harness/full/.agents/skills/vue-best-practices/references/animation-class-based-technique.md +0 -258
  17. package/templates/harness/full/.agents/skills/vue-best-practices/references/animation-state-driven-technique.md +0 -287
  18. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-async.md +0 -99
  19. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-data-flow.md +0 -313
  20. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-fallthrough-attrs.md +0 -179
  21. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-keep-alive.md +0 -139
  22. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-slots.md +0 -226
  23. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-suspense.md +0 -231
  24. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-teleport.md +0 -110
  25. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-transition-group.md +0 -131
  26. package/templates/harness/full/.agents/skills/vue-best-practices/references/component-transition.md +0 -135
  27. package/templates/harness/full/.agents/skills/vue-best-practices/references/composables.md +0 -303
  28. package/templates/harness/full/.agents/skills/vue-best-practices/references/directives.md +0 -168
  29. package/templates/harness/full/.agents/skills/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +0 -177
  30. package/templates/harness/full/.agents/skills/vue-best-practices/references/perf-v-once-v-memo-directives.md +0 -185
  31. package/templates/harness/full/.agents/skills/vue-best-practices/references/perf-virtualize-large-lists.md +0 -182
  32. package/templates/harness/full/.agents/skills/vue-best-practices/references/plugins.md +0 -178
  33. package/templates/harness/full/.agents/skills/vue-best-practices/references/reactivity.md +0 -371
  34. package/templates/harness/full/.agents/skills/vue-best-practices/references/render-functions.md +0 -227
  35. package/templates/harness/full/.agents/skills/vue-best-practices/references/sfc.md +0 -355
  36. package/templates/harness/full/.agents/skills/vue-best-practices/references/state-management.md +0 -138
  37. package/templates/harness/full/.agents/skills/vue-best-practices/references/updated-hook-performance.md +0 -193
  38. package/templates/harness/full/AGENTS.md +0 -3
  39. package/templates/harness/full/GEMINI.md +0 -3
@@ -1,177 +0,0 @@
1
- ---
2
- title: Avoid Excessive Component Abstraction in Large Lists
3
- impact: MEDIUM
4
- impactDescription: Each component instance has memory and render overhead - abstractions multiply this in lists
5
- type: efficiency
6
- tags: [vue3, performance, components, abstraction, lists, optimization]
7
- ---
8
-
9
- # Avoid Excessive Component Abstraction in Large Lists
10
-
11
- **Impact: MEDIUM** - Component instances are more expensive than plain DOM nodes. While abstractions improve code organization, unnecessary nesting creates overhead. In large lists, this overhead multiplies - 100 items with 3 levels of abstraction means 300+ component instances instead of 100.
12
-
13
- Don't avoid abstraction entirely, but be mindful of component depth in frequently-rendered elements like list items.
14
-
15
- ## Task List
16
-
17
- - Review list item components for unnecessary wrapper components
18
- - Consider flattening component hierarchies in hot paths
19
- - Use native elements when a component adds no value
20
- - Profile component counts using Vue DevTools
21
- - Focus optimization efforts on the most-rendered components
22
-
23
- **BAD:**
24
-
25
- ```vue
26
- <!-- BAD: Deep abstraction in list items -->
27
- <template>
28
- <div class="user-list">
29
- <!-- For 100 users: Creates 400 component instances -->
30
- <UserCard v-for="user in users" :key="user.id" :user="user" />
31
- </div>
32
- </template>
33
-
34
- <!-- UserCard.vue -->
35
- <template>
36
- <Card>
37
- <!-- Wrapper component #1 -->
38
- <CardHeader>
39
- <!-- Wrapper component #2 -->
40
- <UserAvatar :src="user.avatar" />
41
- <!-- Wrapper component #3 -->
42
- </CardHeader>
43
- <CardBody>
44
- <!-- Wrapper component #4 -->
45
- <Text>{{ user.name }}</Text>
46
- </CardBody>
47
- </Card>
48
- </template>
49
-
50
- <!-- Each UserCard creates: Card + CardHeader + CardBody + UserAvatar + Text
51
- 100 users = 500+ component instances -->
52
- ```
53
-
54
- **GOOD:**
55
-
56
- ```vue
57
- <!-- GOOD: Flattened structure in list items -->
58
- <script setup>
59
- defineProps({
60
- user: Object,
61
- })
62
- </script>
63
-
64
- <!-- UserCard.vue - Flattened, uses native elements -->
65
- <template>
66
- <div class="user-list">
67
- <!-- For 100 users: Creates 100 component instances -->
68
- <UserCard v-for="user in users" :key="user.id" :user="user" />
69
- </div>
70
- </template>
71
-
72
- <template>
73
- <div class="card">
74
- <div class="card-header">
75
- <img :src="user.avatar" :alt="user.name" class="avatar" />
76
- </div>
77
- <div class="card-body">
78
- <span class="user-name">{{ user.name }}</span>
79
- </div>
80
- </div>
81
- </template>
82
-
83
- <style scoped>
84
- /* Styles that would have been in Card, CardHeader, etc. */
85
- .card {
86
- /* ... */
87
- }
88
- .card-header {
89
- /* ... */
90
- }
91
- .card-body {
92
- /* ... */
93
- }
94
- .avatar {
95
- /* ... */
96
- }
97
- </style>
98
- ```
99
-
100
- ## When Abstraction Is Still Worth It
101
-
102
- ```vue
103
- <!-- Component abstraction is valuable when: -->
104
-
105
- <!-- 1. Complex behavior is encapsulated -->
106
- <UserStatusIndicator :user="user" /> <!-- Has logic, tooltips, etc. -->
107
-
108
- <!-- 2. Reused outside of the hot path -->
109
- <Card> <!-- OK to use in one-off places, not in 100-item lists -->
110
-
111
- <!-- 3. The list itself is small -->
112
- <template v-if="items.length < 20">
113
- <FancyItem v-for="item in items" :key="item.id" />
114
- </template>
115
-
116
- <!-- 4. Virtualization is used (only ~20 items rendered at once) -->
117
- <RecycleScroller :items="items">
118
- <template #default="{ item }">
119
- <ComplexItem :item="item" /> <!-- OK - only 20 instances exist -->
120
- </template>
121
- </RecycleScroller>
122
- ```
123
-
124
- ## Measuring Component Overhead
125
-
126
- ```javascript
127
- // In development, profile component counts
128
- import { getCurrentInstance, onMounted } from 'vue'
129
-
130
- onMounted(() => {
131
- const instance = getCurrentInstance()
132
- let count = 0
133
-
134
- function countComponents(vnode) {
135
- if (vnode.component) count++
136
- if (vnode.children) {
137
- vnode.children.forEach((child) => {
138
- if (child.component || child.children) countComponents(child)
139
- })
140
- }
141
- }
142
-
143
- // Use Vue DevTools instead for accurate counts
144
- console.log('Check Vue DevTools Components tab for instance counts')
145
- })
146
- ```
147
-
148
- ## Alternatives to Wrapper Components
149
-
150
- ```vue
151
- <!-- Instead of a <Button> component for styling: -->
152
- <button class="btn btn-primary">
153
- Click
154
- </button>
155
-
156
- <!-- Instead of a <Text> component: -->
157
- <span class="text-body">
158
- {{ content }}
159
- </span>
160
-
161
- <!-- Instead of layout wrapper components in lists: -->
162
- <div class="flex items-center gap-2">
163
- <!-- content -->
164
- </div>
165
-
166
- <!-- Use CSS classes or Tailwind instead of component abstractions for styling -->
167
- ```
168
-
169
- ## Impact Calculation
170
-
171
- | List Size | Components per Item | Total Instances | Memory Impact |
172
- | ---------- | ------------------- | --------------- | ------------- |
173
- | 100 items | 1 (flat) | 100 | Baseline |
174
- | 100 items | 3 (nested) | 300 | ~3x memory |
175
- | 100 items | 5 (deeply nested) | 500 | ~5x memory |
176
- | 1000 items | 1 (flat) | 1000 | High |
177
- | 1000 items | 5 (deeply nested) | 5000 | Very High |
@@ -1,185 +0,0 @@
1
- ---
2
- title: Use v-once and v-memo to Skip Unnecessary Updates
3
- impact: MEDIUM
4
- impactDescription: v-once skips all future updates for static content; v-memo conditionally memoizes subtrees
5
- type: efficiency
6
- tags: [vue3, performance, v-once, v-memo, optimization, directives]
7
- ---
8
-
9
- # Use v-once and v-memo to Skip Unnecessary Updates
10
-
11
- **Impact: MEDIUM** - Vue re-evaluates templates on every reactive change. For content that never changes or changes infrequently, `v-once` and `v-memo` tell Vue to skip updates, reducing render work.
12
-
13
- Use `v-once` for truly static content and `v-memo` for conditionally-static content in lists.
14
-
15
- ## Task List
16
-
17
- - Apply `v-once` to elements that use runtime data but never need updating
18
- - Apply `v-memo` to list items that should only update on specific condition changes
19
- - Verify memoized content doesn't need to respond to other state changes
20
- - Profile with Vue DevTools to confirm update skipping
21
-
22
- ## v-once: Render Once, Never Update
23
-
24
- **BAD:**
25
-
26
- ```vue
27
- <template>
28
- <!-- BAD: Re-evaluated on every parent re-render -->
29
- <div class="terms-content">
30
- <h1>Terms of Service</h1>
31
- <p>Version: {{ termsVersion }}</p>
32
- <div v-html="termsContent" />
33
- </div>
34
-
35
- <!-- This content NEVER changes, but Vue checks it every render -->
36
- <footer>
37
- <p>Copyright {{ copyrightYear }} {{ companyName }}</p>
38
- </footer>
39
- </template>
40
- ```
41
-
42
- **GOOD:**
43
-
44
- ```vue
45
- <script setup>
46
- // These values are set once at component creation
47
- const termsVersion = '2.1'
48
- const termsContent = fetchedTermsHTML
49
- const copyrightYear = 2024
50
- const companyName = 'Acme Corp'
51
- </script>
52
-
53
- <template>
54
- <!-- GOOD: Rendered once, skipped on all future updates -->
55
- <div v-once class="terms-content">
56
- <h1>Terms of Service</h1>
57
- <p>Version: {{ termsVersion }}</p>
58
- <div v-html="termsContent" />
59
- </div>
60
-
61
- <!-- v-once tells Vue this never needs to update -->
62
- <footer v-once>
63
- <p>Copyright {{ copyrightYear }} {{ companyName }}</p>
64
- </footer>
65
- </template>
66
- ```
67
-
68
- ## v-memo: Conditional Memoization for Lists
69
-
70
- **BAD:**
71
-
72
- ```vue
73
- <template>
74
- <!-- BAD: All items re-render when selectedId changes -->
75
- <div v-for="item in list" :key="item.id">
76
- <div :class="{ selected: item.id === selectedId }">
77
- <ExpensiveComponent :data="item" />
78
- </div>
79
- </div>
80
- </template>
81
- ```
82
-
83
- **GOOD:**
84
-
85
- ```vue
86
- <script setup>
87
- import { ref } from 'vue'
88
-
89
- const list = ref([
90
- /* many items */
91
- ])
92
- const selectedId = ref(null)
93
-
94
- // When selectedId changes:
95
- // - Only the previously-selected item re-renders (selected: true -> false)
96
- // - Only the newly-selected item re-renders (selected: false -> true)
97
- // - All other items are SKIPPED (v-memo values unchanged)
98
- </script>
99
-
100
- <template>
101
- <!-- GOOD: Items only re-render when their selection state changes -->
102
- <div v-for="item in list" :key="item.id" v-memo="[item.id === selectedId]">
103
- <div :class="{ selected: item.id === selectedId }">
104
- <ExpensiveComponent :data="item" />
105
- </div>
106
- </div>
107
- </template>
108
- ```
109
-
110
- ## v-memo with Multiple Dependencies
111
-
112
- ```vue
113
- <script setup>
114
- const selectedId = ref(null)
115
- const editingId = ref(null)
116
- const items = ref([
117
- /* ... */
118
- ])
119
- </script>
120
-
121
- <template>
122
- <!-- Re-render only when item's selection OR editing state changes -->
123
- <div
124
- v-for="item in items"
125
- :key="item.id"
126
- v-memo="[item.id === selectedId, item.id === editingId]"
127
- >
128
- <ItemCard :item="item" :selected="item.id === selectedId" :editing="item.id === editingId" />
129
- </div>
130
- </template>
131
- ```
132
-
133
- ## v-memo with Empty Array = v-once
134
-
135
- ```vue
136
- <template>
137
- <!-- v-memo="[]" is equivalent to v-once -->
138
- <div v-for="item in staticList" :key="item.id" v-memo="[]">
139
- {{ item.name }}
140
- </div>
141
- </template>
142
- ```
143
-
144
- ## When NOT to Use These Directives
145
-
146
- ```vue
147
- <template>
148
- <!-- DON'T: Content that DOES need to update -->
149
- <div v-once>
150
- <span>Count: {{ count }}</span>
151
- <!-- count won't update! -->
152
- </div>
153
-
154
- <!-- DON'T: When child components have their own reactive state -->
155
- <div v-memo="[selected]">
156
- <InputField v-model="item.name" />
157
- <!-- v-model won't work properly -->
158
- </div>
159
-
160
- <!-- DON'T: When the memoization benefit is minimal -->
161
- <span v-once>{{ simpleText }}</span>
162
- <!-- Overhead not worth it -->
163
- </template>
164
- ```
165
-
166
- ## Performance Comparison
167
-
168
- | Scenario | Without Directive | With v-once/v-memo |
169
- | ------------------------------------- | -------------------- | ------------------- |
170
- | Static header, parent re-renders 100x | Re-evaluated 100x | Evaluated 1x |
171
- | 1000 items, selection changes | 1000 items re-render | 2 items re-render |
172
- | Complex child component | Full re-render | Skipped if memoized |
173
-
174
- ## Debugging Memoized Components
175
-
176
- ```vue
177
- <script setup>
178
- import { onUpdated } from 'vue'
179
-
180
- // This won't fire if v-memo prevents update
181
- onUpdated(() => {
182
- console.log('Component updated')
183
- })
184
- </script>
185
- ```
@@ -1,182 +0,0 @@
1
- ---
2
- title: Virtualize Large Lists to Avoid DOM Overload
3
- impact: HIGH
4
- impactDescription: Rendering thousands of list items creates excessive DOM nodes, causing slow renders and high memory usage
5
- type: efficiency
6
- tags: [vue3, performance, virtual-list, large-data, dom, optimization]
7
- ---
8
-
9
- # Virtualize Large Lists to Avoid DOM Overload
10
-
11
- **Impact: HIGH** - Rendering all items in a large list (hundreds or thousands) creates massive amounts of DOM nodes. Each node consumes memory, slows down initial render, and makes updates expensive. List virtualization only renders visible items, dramatically improving performance.
12
-
13
- Use a virtualization library when dealing with lists that could exceed 50-100 items, especially if items have complex content.
14
-
15
- ## Task List
16
-
17
- - Identify lists that render more than 50-100 items
18
- - Install a virtualization library (vue-virtual-scroller, @tanstack/vue-virtual)
19
- - Replace standard `v-for` with virtualized component
20
- - Ensure list items have consistent or estimable heights
21
- - Test with realistic data volumes during development
22
-
23
- ## Recommended Libraries
24
-
25
- | Library | Best For | Notes |
26
- | ------------------------- | ------------------------- | ---------------------------- |
27
- | `vue-virtual-scroller` | General use, easy setup | Most popular, good defaults |
28
- | `@tanstack/vue-virtual` | Complex layouts, headless | Framework-agnostic, flexible |
29
- | `vue-virtual-scroll-grid` | Grid layouts | 2D virtualization |
30
- | `vueuc/VVirtualList` | Naive UI projects | Part of Naive UI ecosystem |
31
-
32
- **BAD:**
33
-
34
- ```vue
35
- <script setup>
36
- import { onMounted, ref } from 'vue'
37
-
38
- import UserCard from './UserCard.vue'
39
-
40
- const users = ref([])
41
-
42
- onMounted(async () => {
43
- // 10,000 DOM nodes created, browser struggles
44
- users.value = await fetchAllUsers()
45
- })
46
- </script>
47
-
48
- <template>
49
- <!-- BAD: Renders ALL 10,000 items immediately -->
50
- <div class="user-list">
51
- <UserCard v-for="user in users" :key="user.id" :user="user" />
52
- </div>
53
- </template>
54
- ```
55
-
56
- **GOOD:**
57
-
58
- ```vue
59
- <script setup>
60
- import { onMounted, ref } from 'vue'
61
- import { RecycleScroller } from 'vue-virtual-scroller'
62
-
63
- import UserCard from './UserCard.vue'
64
-
65
- import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
66
-
67
- const users = ref([])
68
-
69
- onMounted(async () => {
70
- // 10,000 items in memory, but only ~20 DOM nodes
71
- users.value = await fetchAllUsers()
72
- })
73
- </script>
74
-
75
- <template>
76
- <!-- GOOD: Only renders ~20 visible items at a time -->
77
- <RecycleScroller
78
- v-slot="{ item }"
79
- class="user-list"
80
- :items="users"
81
- :item-size="80"
82
- key-field="id"
83
- >
84
- <UserCard :user="item" />
85
- </RecycleScroller>
86
- </template>
87
-
88
- <style scoped>
89
- .user-list {
90
- height: 600px; /* Container must have fixed height */
91
- }
92
- </style>
93
- ```
94
-
95
- ## Using @tanstack/vue-virtual
96
-
97
- ```vue
98
- <script setup>
99
- import { useVirtualizer } from '@tanstack/vue-virtual'
100
- import { ref } from 'vue'
101
-
102
- const users = ref([
103
- /* 10,000 users */
104
- ])
105
- const parentRef = ref(null)
106
-
107
- const rowVirtualizer = useVirtualizer({
108
- count: users.value.length,
109
- getScrollElement: () => parentRef.value,
110
- estimateSize: () => 80, // Estimated row height
111
- overscan: 5, // Render 5 extra items above/below viewport
112
- })
113
- </script>
114
-
115
- <template>
116
- <div ref="parentRef" class="list-container">
117
- <div
118
- :style="{
119
- height: `${rowVirtualizer.getTotalSize()}px`,
120
- position: 'relative',
121
- }"
122
- >
123
- <div
124
- v-for="virtualRow in rowVirtualizer.getVirtualItems()"
125
- :key="virtualRow.key"
126
- :style="{
127
- position: 'absolute',
128
- top: 0,
129
- left: 0,
130
- width: '100%',
131
- height: `${virtualRow.size}px`,
132
- transform: `translateY(${virtualRow.start}px)`,
133
- }"
134
- >
135
- <UserCard :user="users[virtualRow.index]" />
136
- </div>
137
- </div>
138
- </div>
139
- </template>
140
-
141
- <style scoped>
142
- .list-container {
143
- height: 600px;
144
- overflow: auto;
145
- }
146
- </style>
147
- ```
148
-
149
- ## Dynamic Heights with vue-virtual-scroller
150
-
151
- ```vue
152
- <script setup>
153
- import { DynamicScroller, DynamicScrollerItem } from 'vue-virtual-scroller'
154
- </script>
155
-
156
- <template>
157
- <!-- For variable height items, use DynamicScroller -->
158
- <DynamicScroller :items="messages" :min-item-size="54" key-field="id">
159
- <template #default="{ item, index, active }">
160
- <DynamicScrollerItem :item="item" :active="active" :data-index="index">
161
- <ChatMessage :message="item" />
162
- </DynamicScrollerItem>
163
- </template>
164
- </DynamicScroller>
165
- </template>
166
- ```
167
-
168
- ## Performance Comparison
169
-
170
- | Approach | 100 Items | 1,000 Items | 10,000 Items |
171
- | ------------------ | -------------- | ---------------- | ------------------- |
172
- | Regular v-for | ~100 DOM nodes | ~1,000 DOM nodes | ~10,000 DOM nodes |
173
- | Virtualized | ~20 DOM nodes | ~20 DOM nodes | ~20 DOM nodes |
174
- | Initial render | Fast | Slow | Very slow / crashes |
175
- | Virtualized render | Fast | Fast | Fast |
176
-
177
- ## When NOT to Virtualize
178
-
179
- - Lists under 50 items with simple content
180
- - Lists where all items must be accessible to screen readers simultaneously
181
- - Print layouts where all content must render
182
- - SEO-critical content that must be in initial HTML