@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,118 @@
1
+ ---
2
+ title: Checkbox true-value/false-value Not Submitted in Forms
3
+ impact: MEDIUM
4
+ impactDescription: true-value and false-value attributes don't affect form submission - unchecked boxes send nothing
5
+ type: capability
6
+ tags: [vue3, v-model, forms, checkbox, form-submission]
7
+ ---
8
+
9
+ # Checkbox true-value/false-value Not Submitted in Forms
10
+
11
+ **Impact: MEDIUM** - Vue's `true-value` and `false-value` attributes only affect the JavaScript binding, NOT the actual form submission. Unchecked checkboxes are never included in form submissions by browsers, regardless of `false-value`.
12
+
13
+ This is a browser limitation, not a Vue issue. If you need to submit one of two values (like "yes"/"no" or "active"/"inactive"), use radio buttons instead of a checkbox.
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] Don't rely on `false-value` for form submissions - it won't be sent
18
+ - [ ] Use radio buttons when you need to submit one of exactly two values
19
+ - [ ] Remember `true-value`/`false-value` are for JavaScript state only
20
+ - [ ] For form submissions with custom values, handle the transformation server-side or in submit handler
21
+
22
+ **Problem - false-value not submitted:**
23
+ ```html
24
+ <script setup>
25
+ import { ref } from 'vue'
26
+
27
+ const status = ref('no') // JavaScript value works correctly
28
+ </script>
29
+
30
+ <template>
31
+ <form action="/api/update" method="POST">
32
+ <!-- PROBLEM: When unchecked, nothing is submitted for this field -->
33
+ <!-- Server receives no "status" field at all, not "no" -->
34
+ <input
35
+ type="checkbox"
36
+ v-model="status"
37
+ true-value="yes"
38
+ false-value="no"
39
+ name="status"
40
+ >
41
+ <label>Active</label>
42
+
43
+ <!-- status.value correctly shows "yes" or "no" in Vue -->
44
+ <!-- But form submission only sends "status=yes" when checked -->
45
+ <!-- When unchecked, "status" field is completely missing -->
46
+ </form>
47
+ </template>
48
+ ```
49
+
50
+ **Solution 1 - Use radio buttons for two-value submission:**
51
+ ```html
52
+ <script setup>
53
+ import { ref } from 'vue'
54
+
55
+ const status = ref('no')
56
+ </script>
57
+
58
+ <template>
59
+ <form action="/api/update" method="POST">
60
+ <!-- CORRECT: Radio buttons always submit a value -->
61
+ <label>
62
+ <input type="radio" v-model="status" value="yes" name="status">
63
+ Active
64
+ </label>
65
+ <label>
66
+ <input type="radio" v-model="status" value="no" name="status">
67
+ Inactive
68
+ </label>
69
+
70
+ <!-- Form always submits "status=yes" or "status=no" -->
71
+ </form>
72
+ </template>
73
+ ```
74
+
75
+ **Solution 2 - Handle in submit handler (for SPA/AJAX):**
76
+ ```html
77
+ <script setup>
78
+ import { ref } from 'vue'
79
+
80
+ const isActive = ref(false)
81
+
82
+ async function submitForm() {
83
+ // Transform checkbox state to desired value before sending
84
+ const payload = {
85
+ status: isActive.value ? 'yes' : 'no'
86
+ }
87
+
88
+ await fetch('/api/update', {
89
+ method: 'POST',
90
+ body: JSON.stringify(payload)
91
+ })
92
+ }
93
+ </script>
94
+
95
+ <template>
96
+ <!-- For AJAX submission, checkbox is fine - transform in handler -->
97
+ <input type="checkbox" v-model="isActive">
98
+ <label>Active</label>
99
+
100
+ <button @click="submitForm">Save</button>
101
+ </template>
102
+ ```
103
+
104
+ **Solution 3 - Hidden input fallback:**
105
+ ```html
106
+ <template>
107
+ <form action="/api/update" method="POST">
108
+ <!-- Hidden input provides fallback value -->
109
+ <input type="hidden" name="status" value="no">
110
+ <!-- Checkbox overrides with "yes" when checked -->
111
+ <input type="checkbox" name="status" value="yes" v-model="isActive">
112
+ <label>Active</label>
113
+ </form>
114
+ </template>
115
+ ```
116
+
117
+ ## Reference
118
+ - [Vue.js Form Input Bindings - Checkbox](https://vuejs.org/guide/essentials/forms.html#checkbox)
@@ -0,0 +1,172 @@
1
+ ---
2
+ title: Clean Up Event Listeners and Intervals in onUnmounted
3
+ impact: HIGH
4
+ impactDescription: Failing to clean up side effects causes memory leaks and ghost event handlers
5
+ type: capability
6
+ tags: [vue3, lifecycle, memory-leak, event-listeners, intervals, cleanup]
7
+ ---
8
+
9
+ # Clean Up Event Listeners and Intervals in onUnmounted
10
+
11
+ **Impact: HIGH** - Failing to clean up event listeners, intervals, timeouts, and subscriptions when a component unmounts causes memory leaks and ghost handlers that continue running, leading to performance degradation and subtle bugs in Single Page Applications.
12
+
13
+ When using custom events, timers, WebSocket connections, or third-party libraries, always clean up in `onUnmounted` (Composition API) or `unmounted` (Options API).
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] Track all addEventListener calls and remove them in onUnmounted
18
+ - [ ] Clear all setInterval and setTimeout calls in onUnmounted
19
+ - [ ] Unsubscribe from external event emitters and observables
20
+ - [ ] Disconnect WebSocket connections and third-party library instances
21
+ - [ ] Use `onBeforeUnmount` if cleanup must happen before DOM removal
22
+
23
+ **Incorrect:**
24
+ ```javascript
25
+ // Composition API - WRONG: No cleanup
26
+ import { onMounted } from 'vue'
27
+
28
+ export default {
29
+ setup() {
30
+ onMounted(() => {
31
+ // These keep running after component unmounts!
32
+ window.addEventListener('resize', handleResize)
33
+ setInterval(pollServer, 5000)
34
+ socket.on('message', handleMessage)
35
+ })
36
+ }
37
+ }
38
+ ```
39
+
40
+ ```javascript
41
+ // Options API - WRONG: No cleanup
42
+ export default {
43
+ mounted() {
44
+ window.addEventListener('scroll', this.handleScroll)
45
+ this.timer = setInterval(this.refresh, 10000)
46
+ }
47
+ // Component unmounts, but listeners and timers persist!
48
+ }
49
+ ```
50
+
51
+ **Correct:**
52
+ ```javascript
53
+ // Composition API - CORRECT: Proper cleanup
54
+ import { onMounted, onUnmounted, ref } from 'vue'
55
+
56
+ export default {
57
+ setup() {
58
+ const intervalId = ref(null)
59
+
60
+ const handleResize = () => {
61
+ // handle resize
62
+ }
63
+
64
+ const handleMessage = (msg) => {
65
+ // handle message
66
+ }
67
+
68
+ onMounted(() => {
69
+ window.addEventListener('resize', handleResize)
70
+ intervalId.value = setInterval(pollServer, 5000)
71
+ socket.on('message', handleMessage)
72
+ })
73
+
74
+ onUnmounted(() => {
75
+ // Clean up everything!
76
+ window.removeEventListener('resize', handleResize)
77
+
78
+ if (intervalId.value) {
79
+ clearInterval(intervalId.value)
80
+ }
81
+
82
+ socket.off('message', handleMessage)
83
+ })
84
+ }
85
+ }
86
+ ```
87
+
88
+ ```javascript
89
+ // Options API - CORRECT: Proper cleanup
90
+ export default {
91
+ data() {
92
+ return {
93
+ timer: null
94
+ }
95
+ },
96
+ mounted() {
97
+ window.addEventListener('scroll', this.handleScroll)
98
+ this.timer = setInterval(this.refresh, 10000)
99
+ },
100
+ unmounted() {
101
+ window.removeEventListener('scroll', this.handleScroll)
102
+ if (this.timer) {
103
+ clearInterval(this.timer)
104
+ }
105
+ },
106
+ methods: {
107
+ handleScroll() { /* ... */ },
108
+ refresh() { /* ... */ }
109
+ }
110
+ }
111
+ ```
112
+
113
+ ## Using Composable Pattern for Auto-Cleanup
114
+
115
+ ```javascript
116
+ // Reusable composable with automatic cleanup
117
+ import { onMounted, onUnmounted } from 'vue'
118
+
119
+ export function useEventListener(target, event, handler) {
120
+ onMounted(() => {
121
+ target.addEventListener(event, handler)
122
+ })
123
+
124
+ onUnmounted(() => {
125
+ target.removeEventListener(event, handler)
126
+ })
127
+ }
128
+
129
+ export function useInterval(callback, delay) {
130
+ let intervalId = null
131
+
132
+ onMounted(() => {
133
+ intervalId = setInterval(callback, delay)
134
+ })
135
+
136
+ onUnmounted(() => {
137
+ if (intervalId) clearInterval(intervalId)
138
+ })
139
+ }
140
+
141
+ // Usage - cleanup is automatic
142
+ import { useEventListener, useInterval } from './composables'
143
+
144
+ export default {
145
+ setup() {
146
+ useEventListener(window, 'resize', handleResize)
147
+ useInterval(pollServer, 5000)
148
+ // No manual cleanup needed!
149
+ }
150
+ }
151
+ ```
152
+
153
+ ## VueUse Alternative
154
+
155
+ ```javascript
156
+ // VueUse provides cleanup-aware composables
157
+ import { useEventListener, useIntervalFn } from '@vueuse/core'
158
+
159
+ export default {
160
+ setup() {
161
+ // Automatically cleaned up on unmount
162
+ useEventListener(window, 'resize', handleResize)
163
+
164
+ const { pause, resume } = useIntervalFn(pollServer, 5000)
165
+ // Also provides pause/resume controls
166
+ }
167
+ }
168
+ ```
169
+
170
+ ## Reference
171
+ - [Vue.js Lifecycle Hooks](https://vuejs.org/guide/essentials/lifecycle.html)
172
+ - [VueUse - useEventListener](https://vueuse.org/core/useEventListener/)
@@ -0,0 +1,180 @@
1
+ ---
2
+ title: Click Events on Custom Components Require Emit or Fallthrough
3
+ impact: HIGH
4
+ impactDescription: Native click events on custom components won't work without proper emit declaration or attribute fallthrough
5
+ type: gotcha
6
+ tags: [vue3, events, components, emit, click, migration]
7
+ ---
8
+
9
+ # Click Events on Custom Components Require Emit or Fallthrough
10
+
11
+ **Impact: HIGH** - Unlike native HTML elements, custom Vue components don't automatically forward native DOM events like `click`. You must either emit the event explicitly, rely on attribute fallthrough to a single root element, or use the `.native` modifier (Vue 2 only, removed in Vue 3). This is a common source of confusion and migration issues.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Declare emitted events using `defineEmits` in child components
16
+ - [ ] Emit click events from child component when needed
17
+ - [ ] Understand that single-root components automatically forward attrs to root
18
+ - [ ] Remove `.native` modifier when migrating from Vue 2 to Vue 3
19
+ - [ ] For multi-root components, explicitly bind `$attrs` or emit events
20
+
21
+ **Incorrect:**
22
+ ```html
23
+ <!-- WRONG: Expecting native click to work on custom component -->
24
+ <template>
25
+ <MyButton @click="handleClick">Click me</MyButton>
26
+ <!-- This may not work as expected! -->
27
+ </template>
28
+ ```
29
+
30
+ ```html
31
+ <!-- WRONG: Vue 2 .native modifier doesn't exist in Vue 3 -->
32
+ <template>
33
+ <MyButton @click.native="handleClick">Click me</MyButton>
34
+ <!-- Error in Vue 3: .native modifier removed -->
35
+ </template>
36
+ ```
37
+
38
+ ```html
39
+ <!-- WRONG: Multi-root component with no attr binding -->
40
+ <!-- MyButton.vue -->
41
+ <template>
42
+ <span>Icon</span>
43
+ <button>{{ label }}</button>
44
+ <!-- No root element to receive click! -->
45
+ </template>
46
+ ```
47
+
48
+ **Correct:**
49
+ ```html
50
+ <!-- CORRECT: Child component emits the click event -->
51
+ <!-- MyButton.vue -->
52
+ <template>
53
+ <button @click="$emit('click', $event)">
54
+ <slot></slot>
55
+ </button>
56
+ </template>
57
+
58
+ <script setup>
59
+ defineEmits(['click'])
60
+ </script>
61
+
62
+ <!-- Parent.vue -->
63
+ <template>
64
+ <MyButton @click="handleClick">Click me</MyButton>
65
+ </template>
66
+ ```
67
+
68
+ ```html
69
+ <!-- CORRECT: Single root element with automatic fallthrough -->
70
+ <!-- MyButton.vue -->
71
+ <template>
72
+ <button>
73
+ <slot></slot>
74
+ </button>
75
+ <!-- @click from parent automatically falls through to button -->
76
+ </template>
77
+
78
+ <!-- Parent.vue -->
79
+ <template>
80
+ <MyButton @click="handleClick">Click me</MyButton>
81
+ </template>
82
+ ```
83
+
84
+ ```html
85
+ <!-- CORRECT: Multi-root component with explicit $attrs binding -->
86
+ <!-- MyButton.vue -->
87
+ <template>
88
+ <span>Icon</span>
89
+ <button v-bind="$attrs">
90
+ <slot></slot>
91
+ </button>
92
+ </template>
93
+
94
+ <script setup>
95
+ defineOptions({
96
+ inheritAttrs: false
97
+ })
98
+ </script>
99
+ ```
100
+
101
+ ## Component Events Don't Bubble
102
+
103
+ ```javascript
104
+ // Important: Component-emitted events do NOT bubble
105
+ // You can only listen to events from direct children
106
+
107
+ // WRONG: Trying to catch grandchild events
108
+ <GrandParent @child-event="handle"> <!-- Won't receive! -->
109
+ <Parent>
110
+ <Child @click="$emit('child-event')" />
111
+ </Parent>
112
+ </GrandParent>
113
+
114
+ // CORRECT: Each level must relay the event
115
+ <GrandParent @child-event="handle">
116
+ <Parent @child-event="$emit('child-event', $event)">
117
+ <Child @click="$emit('child-event')" />
118
+ </Parent>
119
+ </GrandParent>
120
+ ```
121
+
122
+ ## Vue 3 Native Event Behavior
123
+
124
+ ```javascript
125
+ // In Vue 3, if you declare an event in emits:
126
+ defineEmits(['click'])
127
+
128
+ // Then @click on the component ONLY listens to emitted events
129
+ // NOT native click events
130
+
131
+ // If you don't declare 'click' in emits:
132
+ defineEmits(['custom-event'])
133
+
134
+ // Then @click on single-root component will:
135
+ // 1. Fall through to root element as native listener
136
+ // 2. Fire on native click
137
+ ```
138
+
139
+ ## Composition API Emit Pattern
140
+
141
+ ```vue
142
+ <script setup>
143
+ // Define what events this component emits
144
+ const emit = defineEmits(['click', 'update', 'delete'])
145
+
146
+ function handleClick(event) {
147
+ // Do component logic
148
+ processClick()
149
+
150
+ // Then emit to parent
151
+ emit('click', event)
152
+ }
153
+ </script>
154
+
155
+ <template>
156
+ <button @click="handleClick">
157
+ <slot></slot>
158
+ </button>
159
+ </template>
160
+ ```
161
+
162
+ ## Migration from Vue 2
163
+
164
+ ```html
165
+ <!-- Vue 2: Used .native for native events on components -->
166
+ <MyComponent @click.native="handleClick" />
167
+
168
+ <!-- Vue 3: Remove .native, ensure component handles the event -->
169
+ <MyComponent @click="handleClick" />
170
+
171
+ <!-- Make sure MyComponent either:
172
+ 1. Has single root that receives fallthrough attrs
173
+ 2. Explicitly emits 'click' event
174
+ 3. Uses v-bind="$attrs" on intended element -->
175
+ ```
176
+
177
+ ## Reference
178
+ - [Vue.js Component Events](https://vuejs.org/guide/components/events.html)
179
+ - [Vue.js Fallthrough Attributes](https://vuejs.org/guide/components/attrs.html)
180
+ - [Vue 3 Migration - .native Modifier Removed](https://v3-migration.vuejs.org/breaking-changes/v-on-native-modifier-removed.html)
@@ -0,0 +1,159 @@
1
+ ---
2
+ title: Avoid Component Naming Conflicts Between Global and Local
3
+ impact: HIGH
4
+ impactDescription: Naming conflicts cause unexpected component rendering and hard-to-debug issues
5
+ type: gotcha
6
+ tags: [vue3, component-registration, naming-conflicts, global-local, debugging]
7
+ ---
8
+
9
+ # Avoid Component Naming Conflicts Between Global and Local
10
+
11
+ **Impact: HIGH** - When a global component and a local component have the same name (or resolve to the same name due to casing differences), unexpected behavior occurs. The precedence rules can be confusing, and the wrong component may render silently without any error. This is particularly problematic when using third-party component libraries.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Use unique, prefixed names for global components (e.g., `BaseButton`, `AppHeader`)
16
+ - [ ] Check for naming conflicts when adding global components
17
+ - [ ] Explicitly alias local components if there's potential conflict
18
+ - [ ] When overriding third-party components, document and test thoroughly
19
+
20
+ **Incorrect:**
21
+ ```javascript
22
+ // main.js
23
+ import { createApp } from 'vue'
24
+ import Button from './components/Button.vue'
25
+
26
+ const app = createApp(App)
27
+ app.component('Button', Button) // Global Button
28
+ ```
29
+
30
+ ```vue
31
+ <!-- SomeComponent.vue -->
32
+ <script setup>
33
+ // This local Button might conflict with global Button
34
+ import Button from './local/Button.vue'
35
+ </script>
36
+
37
+ <template>
38
+ <!-- Which Button renders? Behavior may be unexpected -->
39
+ <Button>Click me</Button>
40
+ </template>
41
+ ```
42
+
43
+ ```vue
44
+ <!-- Another confusing scenario -->
45
+ <script setup>
46
+ // Registering with camelCase
47
+ import MyButton from './MyButton.vue'
48
+ </script>
49
+
50
+ <template>
51
+ <!-- Using kebab-case - might match a global 'my-button' instead -->
52
+ <my-button>Click</my-button>
53
+ </template>
54
+ ```
55
+
56
+ **Correct:**
57
+ ```javascript
58
+ // main.js - use prefixes for global components
59
+ import { createApp } from 'vue'
60
+ import BaseButton from './components/BaseButton.vue'
61
+ import BaseIcon from './components/BaseIcon.vue'
62
+
63
+ const app = createApp(App)
64
+ app.component('BaseButton', BaseButton)
65
+ app.component('BaseIcon', BaseIcon)
66
+ ```
67
+
68
+ ```vue
69
+ <!-- SomeComponent.vue -->
70
+ <script setup>
71
+ // Local components have distinct names
72
+ import SubmitButton from './local/SubmitButton.vue'
73
+ </script>
74
+
75
+ <template>
76
+ <!-- No ambiguity - each name is unique -->
77
+ <BaseButton>Generic button</BaseButton>
78
+ <SubmitButton>Submit form</SubmitButton>
79
+ </template>
80
+ ```
81
+
82
+ ## Explicit Aliasing for Clarity
83
+
84
+ When you intentionally want to override or have similar names, use explicit aliasing:
85
+
86
+ ```vue
87
+ <script setup>
88
+ // Explicit alias to avoid confusion
89
+ import { default as LocalButton } from './Button.vue'
90
+ </script>
91
+
92
+ <template>
93
+ <LocalButton>Local version</LocalButton>
94
+ </template>
95
+ ```
96
+
97
+ ```vue
98
+ <!-- Options API with explicit component name -->
99
+ <script>
100
+ import ThirdPartyModal from 'some-library'
101
+ import CustomModal from './CustomModal.vue'
102
+
103
+ export default {
104
+ components: {
105
+ // Explicit names prevent ambiguity
106
+ LibraryModal: ThirdPartyModal,
107
+ CustomModal
108
+ }
109
+ }
110
+ </script>
111
+ ```
112
+
113
+ ## Resolution Order
114
+
115
+ Understanding Vue's component resolution order helps debug issues:
116
+
117
+ 1. **Local registration** takes precedence over global
118
+ 2. **Exact case match** takes precedence over case-insensitive match
119
+ 3. Self-referencing component name (file name) has lowest priority
120
+
121
+ ```vue
122
+ <!-- If all exist: GlobalButton, local Button, and file is Button.vue -->
123
+ <script setup>
124
+ import Button from './Button.vue' // Local registration
125
+ </script>
126
+
127
+ <template>
128
+ <!-- Resolves to locally imported Button, not global -->
129
+ <Button />
130
+ </template>
131
+ ```
132
+
133
+ ## Third-Party Library Conflicts
134
+
135
+ ```vue
136
+ <script setup>
137
+ // Be explicit when using components from multiple libraries
138
+ import { Button as AntButton } from 'ant-design-vue'
139
+ import { Button as ElButton } from 'element-plus'
140
+ </script>
141
+
142
+ <template>
143
+ <AntButton>Ant Design</AntButton>
144
+ <ElButton>Element Plus</ElButton>
145
+ </template>
146
+ ```
147
+
148
+ ## Naming Convention Strategy
149
+
150
+ | Component Type | Naming Pattern | Example |
151
+ |----------------|---------------|---------|
152
+ | Base/Global | `Base*` or `App*` prefix | `BaseButton`, `AppHeader` |
153
+ | Domain-specific | Domain prefix | `UserCard`, `ProductList` |
154
+ | Page components | `*Page` or `*View` suffix | `HomePage`, `UserView` |
155
+ | Layout components | `*Layout` suffix | `DefaultLayout`, `AdminLayout` |
156
+
157
+ ## Reference
158
+ - [Vue.js Component Registration](https://vuejs.org/guide/components/registration.html)
159
+ - [GitHub Issue: Global component naming conflicts](https://github.com/vuejs/vue/issues/4434)