@pythoughts/vue-skills-mcp 0.1.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.
Files changed (208) hide show
  1. package/README.md +63 -0
  2. package/index.mjs +139 -0
  3. package/package.json +34 -0
  4. package/skills/create-adaptable-composable/SKILL.md +76 -0
  5. package/skills/vue-best-practices/SKILL.md +154 -0
  6. package/skills/vue-best-practices/references/animation-class-based-technique.md +254 -0
  7. package/skills/vue-best-practices/references/animation-state-driven-technique.md +291 -0
  8. package/skills/vue-best-practices/references/component-async.md +97 -0
  9. package/skills/vue-best-practices/references/component-data-flow.md +350 -0
  10. package/skills/vue-best-practices/references/component-fallthrough-attrs.md +174 -0
  11. package/skills/vue-best-practices/references/component-keep-alive.md +137 -0
  12. package/skills/vue-best-practices/references/component-slots.md +216 -0
  13. package/skills/vue-best-practices/references/component-suspense.md +228 -0
  14. package/skills/vue-best-practices/references/component-teleport.md +108 -0
  15. package/skills/vue-best-practices/references/component-transition-group.md +128 -0
  16. package/skills/vue-best-practices/references/component-transition.md +125 -0
  17. package/skills/vue-best-practices/references/composables.md +290 -0
  18. package/skills/vue-best-practices/references/directives.md +162 -0
  19. package/skills/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +159 -0
  20. package/skills/vue-best-practices/references/perf-v-once-v-memo-directives.md +182 -0
  21. package/skills/vue-best-practices/references/perf-virtualize-large-lists.md +187 -0
  22. package/skills/vue-best-practices/references/plugins.md +166 -0
  23. package/skills/vue-best-practices/references/reactivity.md +346 -0
  24. package/skills/vue-best-practices/references/render-functions.md +201 -0
  25. package/skills/vue-best-practices/references/sfc.md +310 -0
  26. package/skills/vue-best-practices/references/state-management.md +135 -0
  27. package/skills/vue-best-practices/references/updated-hook-performance.md +187 -0
  28. package/skills/vue-debug-guides/SKILL.md +205 -0
  29. package/skills/vue-debug-guides/reference/animation-key-for-rerender.md +160 -0
  30. package/skills/vue-debug-guides/reference/animation-transitiongroup-performance.md +241 -0
  31. package/skills/vue-debug-guides/reference/async-component-error-handling.md +115 -0
  32. package/skills/vue-debug-guides/reference/async-component-keepalive-ref-issue.md +112 -0
  33. package/skills/vue-debug-guides/reference/async-component-suspense-control.md +84 -0
  34. package/skills/vue-debug-guides/reference/async-component-vue-router.md +109 -0
  35. package/skills/vue-debug-guides/reference/attrs-event-listener-merging.md +205 -0
  36. package/skills/vue-debug-guides/reference/checkbox-true-false-value-form-submission.md +118 -0
  37. package/skills/vue-debug-guides/reference/cleanup-side-effects.md +172 -0
  38. package/skills/vue-debug-guides/reference/click-events-on-components.md +180 -0
  39. package/skills/vue-debug-guides/reference/component-naming-conflicts.md +159 -0
  40. package/skills/vue-debug-guides/reference/component-ref-requires-defineexpose.md +176 -0
  41. package/skills/vue-debug-guides/reference/composable-avoid-hidden-side-effects.md +208 -0
  42. package/skills/vue-debug-guides/reference/composable-call-location-restrictions.md +141 -0
  43. package/skills/vue-debug-guides/reference/composable-naming-return-pattern.md +139 -0
  44. package/skills/vue-debug-guides/reference/composable-tovalue-inside-watcheffect.md +182 -0
  45. package/skills/vue-debug-guides/reference/composition-api-not-functional-programming.md +120 -0
  46. package/skills/vue-debug-guides/reference/composition-api-script-setup-async-context.md +203 -0
  47. package/skills/vue-debug-guides/reference/composition-api-vs-react-hooks-differences.md +156 -0
  48. package/skills/vue-debug-guides/reference/computed-array-mutation.md +148 -0
  49. package/skills/vue-debug-guides/reference/computed-conditional-dependencies.md +147 -0
  50. package/skills/vue-debug-guides/reference/computed-no-parameters.md +159 -0
  51. package/skills/vue-debug-guides/reference/computed-no-side-effects.md +107 -0
  52. package/skills/vue-debug-guides/reference/computed-return-value-readonly.md +160 -0
  53. package/skills/vue-debug-guides/reference/configure-app-before-mount.md +89 -0
  54. package/skills/vue-debug-guides/reference/declare-emits-for-documentation.md +212 -0
  55. package/skills/vue-debug-guides/reference/define-expose-before-await.md +192 -0
  56. package/skills/vue-debug-guides/reference/define-model-default-value-sync.md +139 -0
  57. package/skills/vue-debug-guides/reference/defineEmits-must-be-top-level.md +164 -0
  58. package/skills/vue-debug-guides/reference/defineEmits-no-runtime-and-type-mixed.md +170 -0
  59. package/skills/vue-debug-guides/reference/definemodel-object-mutation-no-emit.md +148 -0
  60. package/skills/vue-debug-guides/reference/dom-update-timing-nexttick.md +90 -0
  61. package/skills/vue-debug-guides/reference/dynamic-argument-constraints.md +146 -0
  62. package/skills/vue-debug-guides/reference/dynamic-component-registration-vite.md +147 -0
  63. package/skills/vue-debug-guides/reference/event-modifier-order-matters.md +101 -0
  64. package/skills/vue-debug-guides/reference/exact-modifier-for-precise-shortcuts.md +155 -0
  65. package/skills/vue-debug-guides/reference/fallthrough-attrs-overwrite-vue3.md +159 -0
  66. package/skills/vue-debug-guides/reference/in-dom-template-parsing-caveats.md +149 -0
  67. package/skills/vue-debug-guides/reference/inheritattrs-false-for-wrapper-components.md +230 -0
  68. package/skills/vue-debug-guides/reference/keepalive-router-nested-double-mount.md +222 -0
  69. package/skills/vue-debug-guides/reference/keepalive-transition-memory-leak.md +144 -0
  70. package/skills/vue-debug-guides/reference/keyup-modifier-timing.md +137 -0
  71. package/skills/vue-debug-guides/reference/lifecycle-dom-access-timing.md +216 -0
  72. package/skills/vue-debug-guides/reference/lifecycle-hooks-synchronous-registration.md +156 -0
  73. package/skills/vue-debug-guides/reference/lifecycle-ssr-awareness.md +184 -0
  74. package/skills/vue-debug-guides/reference/local-components-not-in-descendants.md +151 -0
  75. package/skills/vue-debug-guides/reference/mount-return-value.md +88 -0
  76. package/skills/vue-debug-guides/reference/multi-root-component-class-attrs.md +93 -0
  77. package/skills/vue-debug-guides/reference/native-event-collision-with-emits.md +162 -0
  78. package/skills/vue-debug-guides/reference/no-passive-with-prevent.md +141 -0
  79. package/skills/vue-debug-guides/reference/no-v-if-with-v-for.md +136 -0
  80. package/skills/vue-debug-guides/reference/perf-computed-object-stability.md +157 -0
  81. package/skills/vue-debug-guides/reference/perf-props-stability-update-optimization.md +140 -0
  82. package/skills/vue-debug-guides/reference/plugin-global-properties-sparingly.md +109 -0
  83. package/skills/vue-debug-guides/reference/plugin-install-before-mount.md +124 -0
  84. package/skills/vue-debug-guides/reference/plugin-prefer-provide-inject-over-global-properties.md +120 -0
  85. package/skills/vue-debug-guides/reference/plugin-typescript-type-augmentation.md +157 -0
  86. package/skills/vue-debug-guides/reference/prop-defineprops-scope-limitation.md +161 -0
  87. package/skills/vue-debug-guides/reference/provide-inject-debugging-challenges.md +203 -0
  88. package/skills/vue-debug-guides/reference/provide-inject-default-value-factory.md +244 -0
  89. package/skills/vue-debug-guides/reference/provide-inject-reactivity-not-automatic.md +226 -0
  90. package/skills/vue-debug-guides/reference/provide-inject-synchronous-setup.md +235 -0
  91. package/skills/vue-debug-guides/reference/reactive-destructuring.md +89 -0
  92. package/skills/vue-debug-guides/reference/reactivity-debugging-hooks.md +132 -0
  93. package/skills/vue-debug-guides/reference/reactivity-markraw-for-non-reactive.md +149 -0
  94. package/skills/vue-debug-guides/reference/reactivity-proxy-identity-hazard.md +96 -0
  95. package/skills/vue-debug-guides/reference/reactivity-same-tick-batching.md +166 -0
  96. package/skills/vue-debug-guides/reference/ref-value-access.md +61 -0
  97. package/skills/vue-debug-guides/reference/refs-in-collections-need-value.md +81 -0
  98. package/skills/vue-debug-guides/reference/render-function-avoid-internal-vnode-properties.md +151 -0
  99. package/skills/vue-debug-guides/reference/render-function-vnodes-must-be-unique.md +133 -0
  100. package/skills/vue-debug-guides/reference/rendering-render-function-h-import-vue3.md +148 -0
  101. package/skills/vue-debug-guides/reference/rendering-render-function-return-from-setup.md +148 -0
  102. package/skills/vue-debug-guides/reference/rendering-render-function-slots-as-functions.md +168 -0
  103. package/skills/vue-debug-guides/reference/rendering-resolve-component-for-string-names.md +231 -0
  104. package/skills/vue-debug-guides/reference/select-initial-value-ios-bug.md +91 -0
  105. package/skills/vue-debug-guides/reference/self-referencing-component-name.md +157 -0
  106. package/skills/vue-debug-guides/reference/sfc-named-exports-forbidden.md +184 -0
  107. package/skills/vue-debug-guides/reference/sfc-scoped-css-child-component-styling.md +156 -0
  108. package/skills/vue-debug-guides/reference/sfc-scoped-css-dynamic-content.md +193 -0
  109. package/skills/vue-debug-guides/reference/sfc-scoped-css-slot-content.md +242 -0
  110. package/skills/vue-debug-guides/reference/sfc-script-setup-reactivity.md +195 -0
  111. package/skills/vue-debug-guides/reference/slot-forwarding-to-child-components.md +143 -0
  112. package/skills/vue-debug-guides/reference/slot-implicit-default-content.md +155 -0
  113. package/skills/vue-debug-guides/reference/slot-name-reserved-prop.md +109 -0
  114. package/skills/vue-debug-guides/reference/slot-named-scoped-explicit-default.md +95 -0
  115. package/skills/vue-debug-guides/reference/slot-render-scope-parent-only.md +135 -0
  116. package/skills/vue-debug-guides/reference/slot-v-slot-on-components-or-templates-only.md +122 -0
  117. package/skills/vue-debug-guides/reference/ssr-hydration-mismatch-causes.md +280 -0
  118. package/skills/vue-debug-guides/reference/ssr-platform-specific-apis.md +256 -0
  119. package/skills/vue-debug-guides/reference/state-ssr-cross-request-pollution.md +276 -0
  120. package/skills/vue-debug-guides/reference/suspense-no-builtin-error-handling.md +127 -0
  121. package/skills/vue-debug-guides/reference/suspense-ssr-hydration-issues.md +159 -0
  122. package/skills/vue-debug-guides/reference/tailwind-dynamic-class-generation.md +144 -0
  123. package/skills/vue-debug-guides/reference/teleport-scoped-styles-limitation.md +191 -0
  124. package/skills/vue-debug-guides/reference/teleport-ssr-hydration.md +152 -0
  125. package/skills/vue-debug-guides/reference/teleport-target-must-exist.md +113 -0
  126. package/skills/vue-debug-guides/reference/template-expressions-restrictions.md +114 -0
  127. package/skills/vue-debug-guides/reference/template-functions-no-side-effects.md +187 -0
  128. package/skills/vue-debug-guides/reference/template-ref-null-with-v-if.md +123 -0
  129. package/skills/vue-debug-guides/reference/template-ref-unwrapping-top-level.md +104 -0
  130. package/skills/vue-debug-guides/reference/template-ref-v-for-order.md +172 -0
  131. package/skills/vue-debug-guides/reference/textarea-no-interpolation.md +72 -0
  132. package/skills/vue-debug-guides/reference/transition-group-flip-inline-elements.md +152 -0
  133. package/skills/vue-debug-guides/reference/transition-group-move-animation-position-absolute.md +130 -0
  134. package/skills/vue-debug-guides/reference/transition-group-no-default-wrapper-vue3.md +152 -0
  135. package/skills/vue-debug-guides/reference/transition-js-hooks-done-callback.md +251 -0
  136. package/skills/vue-debug-guides/reference/transition-nested-duration.md +182 -0
  137. package/skills/vue-debug-guides/reference/transition-reusable-scoped-style.md +245 -0
  138. package/skills/vue-debug-guides/reference/transition-router-view-appear.md +193 -0
  139. package/skills/vue-debug-guides/reference/transition-type-when-mixed.md +172 -0
  140. package/skills/vue-debug-guides/reference/transition-unmount-hook-timing.md +149 -0
  141. package/skills/vue-debug-guides/reference/ts-defineprops-boolean-default-false.md +225 -0
  142. package/skills/vue-debug-guides/reference/ts-defineprops-imported-types-limitations.md +281 -0
  143. package/skills/vue-debug-guides/reference/ts-event-handler-explicit-typing.md +213 -0
  144. package/skills/vue-debug-guides/reference/ts-reactive-no-generic-argument.md +196 -0
  145. package/skills/vue-debug-guides/reference/ts-shallowref-for-dynamic-components.md +218 -0
  146. package/skills/vue-debug-guides/reference/ts-template-ref-null-handling.md +249 -0
  147. package/skills/vue-debug-guides/reference/ts-template-type-casting.md +214 -0
  148. package/skills/vue-debug-guides/reference/ts-withdefaults-mutable-factory-function.md +171 -0
  149. package/skills/vue-debug-guides/reference/undeclared-emits-double-firing.md +195 -0
  150. package/skills/vue-debug-guides/reference/use-template-ref-vue35.md +158 -0
  151. package/skills/vue-debug-guides/reference/v-else-must-follow-v-if.md +136 -0
  152. package/skills/vue-debug-guides/reference/v-for-component-props.md +95 -0
  153. package/skills/vue-debug-guides/reference/v-for-computed-reverse-sort.md +86 -0
  154. package/skills/vue-debug-guides/reference/v-for-key-attribute.md +90 -0
  155. package/skills/vue-debug-guides/reference/v-for-range-starts-at-one.md +66 -0
  156. package/skills/vue-debug-guides/reference/v-if-null-check-order.md +171 -0
  157. package/skills/vue-debug-guides/reference/v-model-ignores-html-attributes.md +83 -0
  158. package/skills/vue-debug-guides/reference/v-model-ime-composition.md +83 -0
  159. package/skills/vue-debug-guides/reference/v-model-number-modifier-behavior.md +124 -0
  160. package/skills/vue-debug-guides/reference/v-show-template-limitation.md +124 -0
  161. package/skills/vue-debug-guides/reference/watch-async-cleanup.md +180 -0
  162. package/skills/vue-debug-guides/reference/watch-async-creation-memory-leak.md +176 -0
  163. package/skills/vue-debug-guides/reference/watch-deep-same-object-reference.md +165 -0
  164. package/skills/vue-debug-guides/reference/watch-flush-timing.md +189 -0
  165. package/skills/vue-debug-guides/reference/watch-reactive-property-getter.md +108 -0
  166. package/skills/vue-debug-guides/reference/watcheffect-async-dependency-tracking.md +173 -0
  167. package/skills/vue-debug-guides/reference/watcheffect-flush-post-for-refs.md +176 -0
  168. package/skills/vue-jsx-best-practices/SKILL.md +12 -0
  169. package/skills/vue-jsx-best-practices/reference/render-function-jsx-vue-vs-react.md +141 -0
  170. package/skills/vue-options-api-best-practices/SKILL.md +23 -0
  171. package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-lifecycle-hooks.md +95 -0
  172. package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-methods.md +68 -0
  173. package/skills/vue-options-api-best-practices/reference/stateful-methods-lifecycle.md +61 -0
  174. package/skills/vue-options-api-best-practices/reference/ts-options-api-arrow-functions-validators.md +141 -0
  175. package/skills/vue-options-api-best-practices/reference/ts-options-api-computed-return-types.md +192 -0
  176. package/skills/vue-options-api-best-practices/reference/ts-options-api-proptype-complex-types.md +212 -0
  177. package/skills/vue-options-api-best-practices/reference/ts-options-api-provide-inject-limitations.md +135 -0
  178. package/skills/vue-options-api-best-practices/reference/ts-options-api-type-event-handlers.md +202 -0
  179. package/skills/vue-options-api-best-practices/reference/ts-options-api-use-definecomponent.md +172 -0
  180. package/skills/vue-options-api-best-practices/reference/ts-strict-mode-options-api.md +197 -0
  181. package/skills/vue-pinia-best-practices/SKILL.md +21 -0
  182. package/skills/vue-pinia-best-practices/reference/pinia-no-active-pinia-error.md +248 -0
  183. package/skills/vue-pinia-best-practices/reference/pinia-setup-store-return-all-state.md +227 -0
  184. package/skills/vue-pinia-best-practices/reference/pinia-store-destructuring-breaks-reactivity.md +193 -0
  185. package/skills/vue-pinia-best-practices/reference/state-url-for-ephemeral-filters.md +238 -0
  186. package/skills/vue-pinia-best-practices/reference/state-use-pinia-for-large-apps.md +262 -0
  187. package/skills/vue-pinia-best-practices/reference/store-method-binding-parentheses.md +191 -0
  188. package/skills/vue-router-best-practices/SKILL.md +23 -0
  189. package/skills/vue-router-best-practices/reference/router-beforeenter-no-param-trigger.md +167 -0
  190. package/skills/vue-router-best-practices/reference/router-beforerouteenter-no-this.md +176 -0
  191. package/skills/vue-router-best-practices/reference/router-guard-async-await-pattern.md +227 -0
  192. package/skills/vue-router-best-practices/reference/router-navigation-guard-infinite-loop.md +187 -0
  193. package/skills/vue-router-best-practices/reference/router-navigation-guard-next-deprecated.md +150 -0
  194. package/skills/vue-router-best-practices/reference/router-param-change-no-lifecycle.md +181 -0
  195. package/skills/vue-router-best-practices/reference/router-simple-routing-cleanup.md +209 -0
  196. package/skills/vue-router-best-practices/reference/router-use-vue-router-for-production.md +183 -0
  197. package/skills/vue-testing-best-practices/SKILL.md +29 -0
  198. package/skills/vue-testing-best-practices/reference/async-component-testing.md +163 -0
  199. package/skills/vue-testing-best-practices/reference/teleport-testing-complexity.md +158 -0
  200. package/skills/vue-testing-best-practices/reference/testing-async-await-flushpromises.md +175 -0
  201. package/skills/vue-testing-best-practices/reference/testing-browser-vs-node-runners.md +208 -0
  202. package/skills/vue-testing-best-practices/reference/testing-component-blackbox-approach.md +144 -0
  203. package/skills/vue-testing-best-practices/reference/testing-composables-helper-wrapper.md +238 -0
  204. package/skills/vue-testing-best-practices/reference/testing-e2e-playwright-recommended.md +242 -0
  205. package/skills/vue-testing-best-practices/reference/testing-no-snapshot-only.md +197 -0
  206. package/skills/vue-testing-best-practices/reference/testing-pinia-store-setup.md +228 -0
  207. package/skills/vue-testing-best-practices/reference/testing-suspense-async-components.md +229 -0
  208. package/skills/vue-testing-best-practices/reference/testing-vitest-recommended-for-vue.md +204 -0
@@ -0,0 +1,171 @@
1
+ ---
2
+ title: Wrap Mutable Default Values in Factory Functions
3
+ impact: HIGH
4
+ impactDescription: Without factory functions, all component instances share the same mutable reference causing cross-contamination bugs
5
+ type: gotcha
6
+ tags: [vue3, typescript, props, withDefaults, mutable-types]
7
+ ---
8
+
9
+ # Wrap Mutable Default Values in Factory Functions
10
+
11
+ **Impact: HIGH** - When using `withDefaults()` with type-based props declaration, default values for mutable types (arrays and objects) MUST be wrapped in factory functions. Without this, all component instances share the same reference, causing bugs where modifying the prop in one instance affects all others.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Always wrap array defaults in factory functions: `() => []`
16
+ - [ ] Always wrap object defaults in factory functions: `() => ({})`
17
+ - [ ] Primitive types (string, number, boolean) do NOT need factory functions
18
+ - [ ] Review existing components for this pattern
19
+
20
+ ## The Problem: Shared Mutable References
21
+
22
+ **WRONG - Shared reference across instances:**
23
+ ```vue
24
+ <script setup lang="ts">
25
+ interface Props {
26
+ items?: string[]
27
+ config?: { theme: string }
28
+ }
29
+
30
+ const props = withDefaults(defineProps<Props>(), {
31
+ items: ['default'], // WRONG! All instances share this array
32
+ config: { theme: 'light' } // WRONG! All instances share this object
33
+ })
34
+ </script>
35
+ ```
36
+
37
+ When you have multiple instances of this component:
38
+ ```vue
39
+ <template>
40
+ <!-- Both share the SAME items array! -->
41
+ <MyComponent ref="comp1" />
42
+ <MyComponent ref="comp2" />
43
+ </template>
44
+
45
+ <script setup>
46
+ // If comp1 modifies its items, comp2's items change too!
47
+ comp1.value.items.push('new item') // comp2 also has 'new item' now
48
+ </script>
49
+ ```
50
+
51
+ ## The Solution: Factory Functions
52
+
53
+ **CORRECT - Unique instance per component:**
54
+ ```vue
55
+ <script setup lang="ts">
56
+ interface Props {
57
+ items?: string[]
58
+ config?: { theme: string }
59
+ nested?: { data: { values: number[] } }
60
+ }
61
+
62
+ const props = withDefaults(defineProps<Props>(), {
63
+ items: () => ['default'], // Factory function!
64
+ config: () => ({ theme: 'light' }), // Factory function!
65
+ nested: () => ({ data: { values: [] } }) // Factory function!
66
+ })
67
+ </script>
68
+ ```
69
+
70
+ ## When Factory Functions Are Required
71
+
72
+ | Type | Factory Required | Example Default |
73
+ |------|-----------------|-----------------|
74
+ | `string` | No | `'hello'` |
75
+ | `number` | No | `42` |
76
+ | `boolean` | No | `false` |
77
+ | `string[]` | **Yes** | `() => []` |
78
+ | `number[]` | **Yes** | `() => [1, 2, 3]` |
79
+ | `object` | **Yes** | `() => ({})` |
80
+ | `Map` | **Yes** | `() => new Map()` |
81
+ | `Set` | **Yes** | `() => new Set()` |
82
+ | `Date` | **Yes** | `() => new Date()` |
83
+
84
+ ## Complete Example
85
+
86
+ ```vue
87
+ <script setup lang="ts">
88
+ interface User {
89
+ id: string
90
+ name: string
91
+ }
92
+
93
+ interface Props {
94
+ // Primitives - no factory needed
95
+ title?: string
96
+ count?: number
97
+ disabled?: boolean
98
+
99
+ // Mutable types - factory required
100
+ items?: string[]
101
+ users?: User[]
102
+ metadata?: Record<string, unknown>
103
+ selectedIds?: Set<string>
104
+ }
105
+
106
+ const props = withDefaults(defineProps<Props>(), {
107
+ // Primitives
108
+ title: 'Default Title',
109
+ count: 0,
110
+ disabled: false,
111
+
112
+ // Mutable types with factory functions
113
+ items: () => [],
114
+ users: () => [],
115
+ metadata: () => ({}),
116
+ selectedIds: () => new Set()
117
+ })
118
+ </script>
119
+ ```
120
+
121
+ ## Vue 3.5+ Reactive Props Destructure
122
+
123
+ Vue 3.5 introduces reactive props destructure, which handles this automatically:
124
+
125
+ ```vue
126
+ <script setup lang="ts">
127
+ interface Props {
128
+ items?: string[]
129
+ config?: { theme: string }
130
+ }
131
+
132
+ // Vue 3.5+ - defaults work correctly without explicit factory functions
133
+ const {
134
+ items = ['default'], // Each instance gets its own array
135
+ config = { theme: 'light' } // Each instance gets its own object
136
+ } = defineProps<Props>()
137
+ </script>
138
+ ```
139
+
140
+ Note: Under the hood, Vue 3.5 handles the instance isolation for you.
141
+
142
+ ## Common Bug Pattern
143
+
144
+ This bug often appears in list/table components:
145
+
146
+ ```vue
147
+ <!-- ListItem.vue - BUGGY -->
148
+ <script setup lang="ts">
149
+ interface Props {
150
+ selectedRows?: number[]
151
+ }
152
+
153
+ // All ListItems share the same selectedRows array!
154
+ const props = withDefaults(defineProps<Props>(), {
155
+ selectedRows: [] // BUG: Missing factory function
156
+ })
157
+ </script>
158
+ ```
159
+
160
+ Users report: "Selecting a row in one table selects it in all tables!"
161
+
162
+ **Fix:**
163
+ ```typescript
164
+ const props = withDefaults(defineProps<Props>(), {
165
+ selectedRows: () => [] // Now each instance has its own array
166
+ })
167
+ ```
168
+
169
+ ## Reference
170
+ - [Vue.js TypeScript with Composition API - Default Props](https://vuejs.org/guide/typescript/composition-api.html#props-default-values)
171
+ - [Vue RFC - Reactive Props Destructure](https://github.com/vuejs/rfcs/discussions/502)
@@ -0,0 +1,195 @@
1
+ ---
2
+ title: Undeclared Emits Cause Double Event Firing
3
+ impact: HIGH
4
+ impactDescription: Native events re-emitted without declaration fire twice - once from emit() and once from native listener on root element
5
+ type: gotcha
6
+ tags: [vue3, emits, defineEmits, events, native-events, fallthrough]
7
+ ---
8
+
9
+ # Undeclared Emits Cause Double Event Firing
10
+
11
+ **Impact: HIGH** - When a component re-emits a native DOM event (like `click`) without declaring it in `emits`, the event can fire twice. This happens because undeclared event listeners become part of `$attrs` and fall through to the root element, where they listen for native events while your `emit()` call also fires.
12
+
13
+ This is a common bug when wrapping native elements or migrating from Vue 2 to Vue 3.
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] Declare all emitted events in `defineEmits()` or `emits` option
18
+ - [ ] Pay special attention when re-emitting native events (click, input, change, etc.)
19
+ - [ ] Check for double firing if component wraps native elements
20
+ - [ ] Understand that undeclared listeners fall through to `$attrs`
21
+
22
+ ## The Problem
23
+
24
+ **Incorrect - Undeclared emit causes double firing:**
25
+ ```vue
26
+ <!-- MyButton.vue -->
27
+ <script setup>
28
+ // NO defineEmits declaration!
29
+ </script>
30
+
31
+ <template>
32
+ <!-- Native click listener from parent falls through to button -->
33
+ <!-- PLUS we re-emit click -->
34
+ <button @click="$emit('click', $event)">
35
+ <slot></slot>
36
+ </button>
37
+ </template>
38
+ ```
39
+
40
+ ```vue
41
+ <!-- Parent.vue -->
42
+ <template>
43
+ <!-- This handler fires TWICE on each click! -->
44
+ <MyButton @click="handleClick">Click me</MyButton>
45
+ </template>
46
+
47
+ <script setup>
48
+ function handleClick() {
49
+ console.log('clicked') // Logs twice!
50
+ }
51
+ </script>
52
+ ```
53
+
54
+ **What happens:**
55
+ 1. User clicks the button
56
+ 2. Native click event fires on the button element
57
+ 3. `@click` falls through to button (because 'click' isn't in emits), triggering `handleClick`
58
+ 4. The button's `@click="$emit('click', $event)"` also fires, emitting a component event
59
+ 5. Parent's `@click="handleClick"` receives the emitted event, triggering `handleClick` again
60
+
61
+ ## The Solution
62
+
63
+ **Correct - Declare the emit:**
64
+ ```vue
65
+ <!-- MyButton.vue -->
66
+ <script setup>
67
+ // Declare 'click' as a component event
68
+ const emit = defineEmits(['click'])
69
+ </script>
70
+
71
+ <template>
72
+ <!-- Now @click="handleClick" in parent only listens to emit() -->
73
+ <button @click="emit('click', $event)">
74
+ <slot></slot>
75
+ </button>
76
+ </template>
77
+ ```
78
+
79
+ ```vue
80
+ <!-- Parent.vue -->
81
+ <template>
82
+ <!-- Now fires only once -->
83
+ <MyButton @click="handleClick">Click me</MyButton>
84
+ </template>
85
+ ```
86
+
87
+ When you declare `click` in `emits`:
88
+ - Vue knows `@click` on the component is listening for a component event
89
+ - The listener does NOT fall through to the root element
90
+ - Only your explicit `emit('click')` triggers the parent's handler
91
+
92
+ ## Options API Version
93
+
94
+ **Correct - Using emits option:**
95
+ ```vue
96
+ <script>
97
+ export default {
98
+ emits: ['click', 'input', 'change'],
99
+
100
+ methods: {
101
+ handleClick(event) {
102
+ this.$emit('click', event)
103
+ }
104
+ }
105
+ }
106
+ </script>
107
+ ```
108
+
109
+ ## Common Scenarios
110
+
111
+ ### Wrapping Form Inputs
112
+
113
+ ```vue
114
+ <!-- CustomInput.vue -->
115
+ <script setup>
116
+ // Declare all events you re-emit
117
+ const emit = defineEmits(['input', 'change', 'focus', 'blur'])
118
+ </script>
119
+
120
+ <template>
121
+ <input
122
+ @input="emit('input', $event)"
123
+ @change="emit('change', $event)"
124
+ @focus="emit('focus', $event)"
125
+ @blur="emit('blur', $event)"
126
+ />
127
+ </template>
128
+ ```
129
+
130
+ ### Wrapper Components
131
+
132
+ ```vue
133
+ <!-- IconButton.vue -->
134
+ <script setup>
135
+ const emit = defineEmits(['click'])
136
+ </script>
137
+
138
+ <template>
139
+ <button @click="emit('click', $event)">
140
+ <Icon :name="icon" />
141
+ <slot></slot>
142
+ </button>
143
+ </template>
144
+ ```
145
+
146
+ ## Alternative: Don't Re-emit, Let It Fall Through
147
+
148
+ If your component has a single root element and you want native event behavior:
149
+
150
+ ```vue
151
+ <!-- MyButton.vue -->
152
+ <script setup>
153
+ // Don't declare 'click' - let it fall through naturally
154
+ const emit = defineEmits(['custom-action'])
155
+ </script>
156
+
157
+ <template>
158
+ <!-- Native @click from parent falls through to this button -->
159
+ <button>
160
+ <slot></slot>
161
+ </button>
162
+ </template>
163
+ ```
164
+
165
+ ```vue
166
+ <!-- Parent.vue -->
167
+ <template>
168
+ <!-- This native click falls through to the button -->
169
+ <MyButton @click="handleClick">Click me</MyButton>
170
+ </template>
171
+ ```
172
+
173
+ This works because:
174
+ - You don't re-emit 'click' explicitly
175
+ - The native click listener falls through to the single root button
176
+ - Native click fires once when button is clicked
177
+
178
+ ## Debugging Double Firing
179
+
180
+ ```vue
181
+ <script setup>
182
+ function handleClick(event) {
183
+ console.log('Event type:', event?.type)
184
+ console.log('Is native:', event instanceof Event)
185
+ console.trace('Click handler called')
186
+ }
187
+ </script>
188
+ ```
189
+
190
+ If you see two stack traces with different origins, you have the double-firing issue.
191
+
192
+ ## Reference
193
+ - [Vue 3 Migration - emits Option](https://v3-migration.vuejs.org/breaking-changes/emits-option)
194
+ - [Vue.js Component Events](https://vuejs.org/guide/components/events.html)
195
+ - [Vue.js Fallthrough Attributes](https://vuejs.org/guide/components/attrs.html)
@@ -0,0 +1,158 @@
1
+ ---
2
+ title: Use useTemplateRef for Template Refs in Vue 3.5+
3
+ impact: MEDIUM
4
+ impactDescription: Legacy ref pattern is error-prone due to name matching requirement
5
+ type: best-practice
6
+ tags: [vue3, vue35, template-refs, useTemplateRef, composition-api]
7
+ ---
8
+
9
+ # Use useTemplateRef for Template Refs in Vue 3.5+
10
+
11
+ **Impact: MEDIUM** - Before Vue 3.5, template refs required declaring a `ref()` with a name exactly matching the template's ref attribute. This fragile connection breaks silently during refactoring. Vue 3.5's `useTemplateRef()` eliminates this issue with explicit binding and better TypeScript support.
12
+
13
+ The legacy pattern causes no errors or warnings when names don't match - the ref simply stays null, leading to confusing debugging sessions.
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] Use `useTemplateRef('ref-name')` in Vue 3.5+ projects
18
+ - [ ] The first argument must exactly match the ref attribute value in the template
19
+ - [ ] IDE support provides auto-completion for available ref names
20
+ - [ ] TypeScript automatically infers the element type
21
+
22
+ **Incorrect (Legacy Pattern):**
23
+ ```vue
24
+ <script setup>
25
+ import { ref, onMounted } from 'vue'
26
+
27
+ // FRAGILE: Variable name MUST match template ref value exactly
28
+ const input = ref(null)
29
+
30
+ // DANGER: After refactoring, names may not match
31
+ const inputElement = ref(null) // Renamed variable...
32
+
33
+ onMounted(() => {
34
+ // NO ERROR - just silently null!
35
+ inputElement.value?.focus() // Does nothing
36
+ })
37
+ </script>
38
+
39
+ <template>
40
+ <!-- But template still uses old name -->
41
+ <input ref="input" />
42
+ </template>
43
+ ```
44
+
45
+ ```vue
46
+ <script setup>
47
+ import { ref } from 'vue'
48
+
49
+ // TYPO: 'inupt' instead of 'input' - no warning!
50
+ const inupt = ref(null)
51
+ </script>
52
+
53
+ <template>
54
+ <input ref="input" />
55
+ <!-- inupt.value will always be null -->
56
+ </template>
57
+ ```
58
+
59
+ **Correct (Vue 3.5+):**
60
+ ```vue
61
+ <script setup>
62
+ import { useTemplateRef, onMounted } from 'vue'
63
+
64
+ // CORRECT: Explicit binding - argument matches template ref
65
+ const inputElement = useTemplateRef('my-input')
66
+
67
+ onMounted(() => {
68
+ inputElement.value?.focus()
69
+ })
70
+ </script>
71
+
72
+ <template>
73
+ <!-- ref name is explicitly connected via useTemplateRef argument -->
74
+ <input ref="my-input" />
75
+ </template>
76
+ ```
77
+
78
+ ```vue
79
+ <script setup>
80
+ import { useTemplateRef, onMounted } from 'vue'
81
+
82
+ // BENEFITS:
83
+ // 1. Variable name is independent of ref attribute
84
+ // 2. IDE auto-completes available ref names
85
+ // 3. TypeScript infers correct element type
86
+ // 4. Typos in argument cause visible errors
87
+
88
+ const searchInput = useTemplateRef('search-box')
89
+ const submitButton = useTemplateRef('submit-btn')
90
+
91
+ onMounted(() => {
92
+ // TypeScript knows these are HTMLInputElement and HTMLButtonElement
93
+ searchInput.value?.focus()
94
+ submitButton.value?.disabled = false
95
+ })
96
+ </script>
97
+
98
+ <template>
99
+ <input ref="search-box" type="search" />
100
+ <button ref="submit-btn">Submit</button>
101
+ </template>
102
+ ```
103
+
104
+ ## Limitation: v-for Refs
105
+
106
+ `useTemplateRef()` does **NOT** work with `v-for` refs. You must use the legacy `ref()` pattern for collecting multiple element references in a loop.
107
+
108
+ ```vue
109
+ <script setup>
110
+ import { ref, onMounted } from 'vue'
111
+
112
+ // CORRECT: Legacy pattern required for v-for refs
113
+ const itemRefs = ref([])
114
+
115
+ onMounted(() => {
116
+ // itemRefs.value is an array of DOM elements
117
+ itemRefs.value.forEach(el => {
118
+ console.log(el.textContent)
119
+ })
120
+ })
121
+ </script>
122
+
123
+ <template>
124
+ <ul>
125
+ <li v-for="item in items" ref="itemRefs" :key="item.id">
126
+ {{ item.text }}
127
+ </li>
128
+ </ul>
129
+ </template>
130
+ ```
131
+
132
+ **Why this limitation exists:** When using `v-for`, Vue populates the ref with an array of elements. The `useTemplateRef()` API was designed for single element references and does not support the array population mechanism that `v-for` requires.
133
+
134
+ ## Migration Guide
135
+
136
+ ```vue
137
+ <!-- BEFORE (Vue < 3.5) -->
138
+ <script setup>
139
+ import { ref } from 'vue'
140
+ const myElement = ref(null) // Name must match template
141
+ </script>
142
+ <template>
143
+ <div ref="myElement"></div>
144
+ </template>
145
+
146
+ <!-- AFTER (Vue 3.5+) -->
147
+ <script setup>
148
+ import { useTemplateRef } from 'vue'
149
+ const element = useTemplateRef('my-element') // Any variable name
150
+ </script>
151
+ <template>
152
+ <div ref="my-element"></div>
153
+ </template>
154
+ ```
155
+
156
+ ## Reference
157
+ - [Vue.js Template Refs - Composition API](https://vuejs.org/guide/essentials/template-refs.html#accessing-the-refs)
158
+ - [Vue 3.5 Release Notes](https://blog.vuejs.org/posts/vue-3-5)
@@ -0,0 +1,136 @@
1
+ ---
2
+ title: v-else Must Immediately Follow v-if or v-else-if
3
+ impact: MEDIUM
4
+ impactDescription: Misplaced v-else causes a compile-time error in SFCs, or renders unconditionally with runtime template compilation
5
+ type: capability
6
+ tags: [vue3, conditional-rendering, v-if, v-else, v-else-if]
7
+ ---
8
+
9
+ # v-else Must Immediately Follow v-if or v-else-if
10
+
11
+ **Impact: MEDIUM** - A `v-else` or `v-else-if` element must immediately follow a `v-if` or `v-else-if` element in the DOM. If there's any element in between:
12
+
13
+ - **SFC compilation (Vite/vue-loader):** Vue throws a **compile-time SyntaxError** - the code won't build at all
14
+ - **Runtime template compilation:** The element renders unconditionally (always visible), losing its conditional behavior
15
+
16
+ In most modern Vue projects using Single File Components, this is caught at build time.
17
+
18
+ ## Task Checklist
19
+
20
+ - [ ] Place v-else immediately after the v-if element (no elements in between)
21
+ - [ ] Place v-else-if immediately after v-if or another v-else-if
22
+ - [ ] Use `<template>` wrapper if you need to group multiple elements within a branch
23
+ - [ ] If you need content between conditions, restructure using nested conditionals or computed
24
+
25
+ **Incorrect:**
26
+ ```html
27
+ <!-- WRONG: v-else not immediately after v-if -->
28
+ <template>
29
+ <div v-if="isLoggedIn">
30
+ Welcome back!
31
+ </div>
32
+
33
+ <p>Some other content in between</p>
34
+
35
+ <div v-else>
36
+ <!-- This v-else is NOT recognized! It will ALWAYS render (unconditionally) -->
37
+ Please log in
38
+ </div>
39
+ </template>
40
+ ```
41
+
42
+ ```html
43
+ <!-- WRONG: Comment or whitespace element between -->
44
+ <template>
45
+ <span v-if="status === 'loading'">Loading...</span>
46
+ <!-- This comment breaks the chain! -->
47
+ <span v-else-if="status === 'error'">Error occurred</span>
48
+ <span v-else>Done</span>
49
+ </template>
50
+ ```
51
+
52
+ ```html
53
+ <!-- WRONG: Text node between conditions -->
54
+ <template>
55
+ <div v-if="showA">A</div>
56
+ Just some text here
57
+ <div v-else>B</div> <!-- Not recognized, always renders -->
58
+ </template>
59
+ ```
60
+
61
+ **Correct:**
62
+ ```html
63
+ <!-- CORRECT: v-else immediately follows v-if -->
64
+ <template>
65
+ <div v-if="isLoggedIn">
66
+ Welcome back!
67
+ </div>
68
+ <div v-else>
69
+ Please log in
70
+ </div>
71
+
72
+ <p>Some other content (placed after the conditional block)</p>
73
+ </template>
74
+ ```
75
+
76
+ ```html
77
+ <!-- CORRECT: Full v-if/v-else-if/v-else chain -->
78
+ <template>
79
+ <span v-if="status === 'loading'">Loading...</span>
80
+ <span v-else-if="status === 'error'">Error: {{ errorMessage }}</span>
81
+ <span v-else-if="status === 'empty'">No data found</span>
82
+ <span v-else>{{ data }}</span>
83
+ </template>
84
+ ```
85
+
86
+ ```html
87
+ <!-- CORRECT: Using <template> for multiple elements per branch -->
88
+ <template>
89
+ <template v-if="isLoggedIn">
90
+ <h1>Welcome back!</h1>
91
+ <p>Your dashboard</p>
92
+ <UserStats />
93
+ </template>
94
+ <template v-else>
95
+ <h1>Please log in</h1>
96
+ <LoginForm />
97
+ </template>
98
+ </template>
99
+ ```
100
+
101
+ ```html
102
+ <!-- CORRECT: Restructure if you need content between conditions -->
103
+ <template>
104
+ <div class="conditional-section">
105
+ <div v-if="isLoggedIn">Welcome back!</div>
106
+ <div v-else>Please log in</div>
107
+ </div>
108
+
109
+ <div class="always-shown">
110
+ Some other content
111
+ </div>
112
+
113
+ <div class="another-conditional">
114
+ <div v-if="showMore">More info</div>
115
+ <div v-else>Click to expand</div>
116
+ </div>
117
+ </template>
118
+ ```
119
+
120
+ ## Debugging Tips
121
+
122
+ ```html
123
+ <!-- If v-else is always visible (rendering unconditionally), check for: -->
124
+
125
+ <!-- 1. Elements between v-if and v-else -->
126
+ <!-- 2. HTML comments that break the chain -->
127
+ <!-- 3. Text nodes (including whitespace in some cases) -->
128
+ <!-- 4. Component tags that render content between -->
129
+
130
+ <!-- SFC compilation throws: "v-else/v-else-if has no adjacent v-if or v-else-if" (build fails) -->
131
+ <!-- Runtime template compilation shows a warning but renders the element unconditionally -->
132
+ <!-- Vue DevTools will show the v-else element as not part of the condition chain -->
133
+ ```
134
+
135
+ ## Reference
136
+ - [Vue.js Conditional Rendering - v-else](https://vuejs.org/guide/essentials/conditional.html#v-else)