@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,141 @@
1
+ ---
2
+ title: Never Use .passive and .prevent Together
3
+ impact: HIGH
4
+ impactDescription: Conflicting modifiers cause .prevent to be ignored and trigger browser warnings
5
+ type: gotcha
6
+ tags: [vue3, events, modifiers, scroll, touch, performance]
7
+ ---
8
+
9
+ # Never Use .passive and .prevent Together
10
+
11
+ **Impact: HIGH** - The `.passive` modifier tells the browser you will NOT call `preventDefault()`, while `.prevent` does exactly that. Using them together causes `.prevent` to be ignored and triggers browser console warnings. This is a logical contradiction that leads to broken event handling.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Never combine `.passive` and `.prevent` on the same event
16
+ - [ ] Use `.passive` for scroll/touch events where you want better performance
17
+ - [ ] Use `.prevent` when you need to stop the default browser action
18
+ - [ ] If you need conditional prevention, handle it in JavaScript without `.passive`
19
+
20
+ **Incorrect:**
21
+ ```html
22
+ <!-- WRONG: Conflicting modifiers -->
23
+ <template>
24
+ <div @scroll.passive.prevent="handleScroll">
25
+ <!-- .prevent will be IGNORED -->
26
+ <!-- Browser shows warning -->
27
+ </div>
28
+ </template>
29
+ ```
30
+
31
+ ```html
32
+ <!-- WRONG: On touch events -->
33
+ <template>
34
+ <div @touchstart.passive.prevent="handleTouch">
35
+ <!-- Cannot prevent default - passive already promised not to -->
36
+ </div>
37
+ </template>
38
+ ```
39
+
40
+ ```html
41
+ <!-- WRONG: On wheel events -->
42
+ <template>
43
+ <div @wheel.passive.prevent="handleWheel">
44
+ <!-- Broken: will scroll anyway despite .prevent -->
45
+ </div>
46
+ </template>
47
+ ```
48
+
49
+ **Correct:**
50
+ ```html
51
+ <!-- CORRECT: Use .passive for performance (no prevention needed) -->
52
+ <template>
53
+ <div @scroll.passive="handleScroll">
54
+ <!-- Good for scroll tracking without blocking -->
55
+ </div>
56
+ </template>
57
+ ```
58
+
59
+ ```html
60
+ <!-- CORRECT: Use .prevent when you need to prevent default -->
61
+ <template>
62
+ <form @submit.prevent="handleSubmit">
63
+ <!-- Correctly prevents form submission -->
64
+ </form>
65
+ </template>
66
+ ```
67
+
68
+ ```html
69
+ <!-- CORRECT: For touch events where you need to prevent -->
70
+ <template>
71
+ <div @touchmove="handleTouchMove">
72
+ <!-- Handle prevention conditionally in JS -->
73
+ </div>
74
+ </template>
75
+
76
+ <script setup>
77
+ function handleTouchMove(event) {
78
+ if (shouldPreventScroll.value) {
79
+ event.preventDefault()
80
+ }
81
+ // ... handle touch
82
+ }
83
+ </script>
84
+ ```
85
+
86
+ ## Understanding .passive
87
+
88
+ ```javascript
89
+ // .passive tells the browser:
90
+ // "I promise I won't call preventDefault()"
91
+
92
+ // This allows the browser to:
93
+ // 1. Start scrolling immediately without waiting for JS
94
+ // 2. Improve scroll performance, especially on mobile
95
+ // 3. Reduce jank and stuttering
96
+
97
+ // Equivalent to:
98
+ element.addEventListener('scroll', handler, { passive: true })
99
+ ```
100
+
101
+ ## When to Use .passive
102
+
103
+ ```html
104
+ <!-- Good use cases for .passive -->
105
+
106
+ <!-- Scroll tracking analytics -->
107
+ <div @scroll.passive="trackScrollPosition">
108
+
109
+ <!-- Touch gesture detection (no prevention needed) -->
110
+ <div @touchmove.passive="detectGesture">
111
+
112
+ <!-- Wheel event monitoring -->
113
+ <div @wheel.passive="monitorWheel">
114
+ ```
115
+
116
+ ## When to Use .prevent (Without .passive)
117
+
118
+ ```html
119
+ <!-- Good use cases for .prevent -->
120
+
121
+ <!-- Form submission -->
122
+ <form @submit.prevent="handleSubmit">
123
+
124
+ <!-- Link clicks with custom navigation -->
125
+ <a @click.prevent="navigate">
126
+
127
+ <!-- Preventing context menu -->
128
+ <div @contextmenu.prevent="showCustomMenu">
129
+ ```
130
+
131
+ ## Browser Warning
132
+
133
+ When you combine `.passive` and `.prevent`, the browser console shows:
134
+ ```
135
+ [Intervention] Unable to preventDefault inside passive event listener
136
+ due to target being treated as passive.
137
+ ```
138
+
139
+ ## Reference
140
+ - [Vue.js Event Handling - Event Modifiers](https://vuejs.org/guide/essentials/event-handling.html#event-modifiers)
141
+ - [MDN - Improving scroll performance with passive listeners](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#improving_scrolling_performance_with_passive_listeners)
@@ -0,0 +1,136 @@
1
+ ---
2
+ title: Never Use v-if and v-for on the Same Element
3
+ impact: HIGH
4
+ impactDescription: Causes confusing precedence issues and Vue 2 to 3 migration bugs
5
+ type: capability
6
+ tags: [vue3, v-if, v-for, conditional-rendering, list-rendering, eslint]
7
+ ---
8
+
9
+ # Never Use v-if and v-for on the Same Element
10
+
11
+ **Impact: HIGH** - Using `v-if` and `v-for` on the same element creates ambiguous precedence that differs between Vue 2 and Vue 3. In Vue 2, `v-for` had higher precedence; in Vue 3, `v-if` has higher precedence. This breaking change causes subtle bugs during migration and makes code intent unclear.
12
+
13
+ The ESLint rule `vue/no-use-v-if-with-v-for` enforces this best practice.
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] Never place v-if and v-for on the same element
18
+ - [ ] For filtering list items: use a computed property that filters the array
19
+ - [ ] For hiding entire list: wrap with `<template v-if>` around the v-for
20
+ - [ ] Enable eslint-plugin-vue rule `vue/no-use-v-if-with-v-for`
21
+
22
+ **Incorrect:**
23
+ ```html
24
+ <!-- WRONG: v-if and v-for on same element - ambiguous precedence -->
25
+ <template>
26
+ <!-- Intent: show only active users -->
27
+ <li v-for="user in users" v-if="user.isActive" :key="user.id">
28
+ {{ user.name }}
29
+ </li>
30
+ </template>
31
+ ```
32
+
33
+ ```html
34
+ <!-- WRONG: Hiding entire list conditionally -->
35
+ <template>
36
+ <li v-for="user in users" v-if="shouldShowList" :key="user.id">
37
+ {{ user.name }}
38
+ </li>
39
+ </template>
40
+ ```
41
+
42
+ ```html
43
+ <!-- WRONG: Vue 3 precedence issue -->
44
+ <template>
45
+ <!-- In Vue 3, v-if runs FIRST, so 'user' is undefined! -->
46
+ <li v-for="user in users" v-if="user.isActive" :key="user.id">
47
+ {{ user.name }}
48
+ </li>
49
+ <!-- Error: Cannot read property 'isActive' of undefined -->
50
+ </template>
51
+ ```
52
+
53
+ **Correct:**
54
+ ```html
55
+ <!-- CORRECT: Filter with computed property -->
56
+ <template>
57
+ <li v-for="user in activeUsers" :key="user.id">
58
+ {{ user.name }}
59
+ </li>
60
+ </template>
61
+
62
+ <script setup>
63
+ import { computed } from 'vue'
64
+
65
+ const props = defineProps(['users'])
66
+
67
+ const activeUsers = computed(() =>
68
+ props.users.filter(user => user.isActive)
69
+ )
70
+ </script>
71
+ ```
72
+
73
+ ```html
74
+ <!-- CORRECT: Wrap with <template v-if> for conditional list -->
75
+ <template>
76
+ <template v-if="shouldShowList">
77
+ <li v-for="user in users" :key="user.id">
78
+ {{ user.name }}
79
+ </li>
80
+ </template>
81
+ </template>
82
+ ```
83
+
84
+ ```html
85
+ <!-- CORRECT: v-if inside the loop (per-item condition) -->
86
+ <template>
87
+ <ul>
88
+ <template v-for="user in users" :key="user.id">
89
+ <li v-if="user.isActive">
90
+ {{ user.name }}
91
+ </li>
92
+ </template>
93
+ </ul>
94
+ </template>
95
+ ```
96
+
97
+ ## Vue 2 vs Vue 3 Precedence Change
98
+
99
+ ```javascript
100
+ // Vue 2: v-for evaluated first
101
+ // <li v-for="user in users" v-if="user.isActive">
102
+ // Equivalent to: users.forEach(user => { if (user.isActive) render(user) })
103
+
104
+ // Vue 3: v-if evaluated first
105
+ // <li v-for="user in users" v-if="user.isActive">
106
+ // Equivalent to: if (user.isActive) users.forEach(user => render(user))
107
+ // Problem: 'user' doesn't exist yet when v-if runs!
108
+ ```
109
+
110
+ ## Why Computed Properties Are Better
111
+
112
+ ```javascript
113
+ // Benefits of filtering via computed:
114
+ // 1. Clear separation of concerns (logic vs template)
115
+ // 2. Cached - only recalculates when dependencies change
116
+ // 3. Reusable - can be used elsewhere in component
117
+ // 4. Testable - can unit test the filtering logic
118
+ // 5. No ambiguity about intent
119
+
120
+ const activeUsers = computed(() =>
121
+ users.value.filter(u => u.isActive)
122
+ )
123
+
124
+ // Can add more complex filtering
125
+ const filteredUsers = computed(() =>
126
+ users.value
127
+ .filter(u => u.isActive)
128
+ .filter(u => u.role === selectedRole.value)
129
+ .sort((a, b) => a.name.localeCompare(b.name))
130
+ )
131
+ ```
132
+
133
+ ## Reference
134
+ - [Vue.js Style Guide - Avoid v-if with v-for](https://vuejs.org/style-guide/rules-essential.html#avoid-v-if-with-v-for)
135
+ - [Vue 3 Migration Guide - v-if vs v-for Precedence](https://v3-migration.vuejs.org/breaking-changes/v-if-v-for)
136
+ - [ESLint Plugin Vue - no-use-v-if-with-v-for](https://eslint.vuejs.org/rules/no-use-v-if-with-v-for)
@@ -0,0 +1,157 @@
1
+ ---
2
+ title: Return Stable Object References from Computed Properties
3
+ impact: MEDIUM
4
+ impactDescription: Computed properties returning new objects trigger effects even when values haven't meaningfully changed
5
+ type: efficiency
6
+ tags: [vue3, computed, performance, reactivity, vue3.4]
7
+ ---
8
+
9
+ # Return Stable Object References from Computed Properties
10
+
11
+ **Impact: MEDIUM** - In Vue 3.4+, computed properties only trigger effects when their value changes. However, if a computed returns a new object each time, Vue cannot detect that the values inside are the same. This causes unnecessary effect re-runs.
12
+
13
+ For primitive values, Vue 3.4+ handles this automatically. For objects, manually compare and return the previous value when nothing meaningful has changed.
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] For computed properties returning primitives, Vue 3.4+ handles stability automatically
18
+ - [ ] For computed properties returning objects, compare with previous value and return old reference if unchanged
19
+ - [ ] Always perform the full computation before comparing (to track dependencies correctly)
20
+ - [ ] Consider if you really need to return an object, or if primitives would suffice
21
+
22
+ **Incorrect:**
23
+ ```vue
24
+ <script setup>
25
+ import { ref, computed, watchEffect } from 'vue'
26
+
27
+ const count = ref(0)
28
+
29
+ // BAD: Returns new object every time, always triggers effects
30
+ const stats = computed(() => {
31
+ return {
32
+ isEven: count.value % 2 === 0,
33
+ doubleValue: count.value * 2
34
+ }
35
+ })
36
+
37
+ watchEffect(() => {
38
+ console.log('Stats changed:', stats.value)
39
+ // Logs on EVERY count change, even when isEven hasn't changed
40
+ // count: 0 -> 2 -> 4: isEven is always true, but effect runs each time
41
+ })
42
+ </script>
43
+ ```
44
+
45
+ **Correct:**
46
+ ```vue
47
+ <script setup>
48
+ import { ref, computed, watchEffect } from 'vue'
49
+
50
+ const count = ref(0)
51
+
52
+ // GOOD (Vue 3.4+): Primitive computed - automatic stability
53
+ const isEven = computed(() => count.value % 2 === 0)
54
+
55
+ watchEffect(() => {
56
+ console.log('isEven:', isEven.value)
57
+ // Only logs when isEven actually changes (0, 2, 4 won't re-trigger)
58
+ })
59
+
60
+ // GOOD (Vue 3.4+): Manual comparison for object returns
61
+ const stats = computed((oldValue) => {
62
+ // Step 1: Always compute the new value first (to track dependencies)
63
+ const newValue = {
64
+ isEven: count.value % 2 === 0,
65
+ category: count.value < 10 ? 'small' : 'large'
66
+ }
67
+
68
+ // Step 2: Compare with previous value
69
+ if (oldValue &&
70
+ oldValue.isEven === newValue.isEven &&
71
+ oldValue.category === newValue.category) {
72
+ return oldValue // Return old reference - no effect triggers
73
+ }
74
+
75
+ return newValue
76
+ })
77
+
78
+ watchEffect(() => {
79
+ console.log('Stats changed:', stats.value)
80
+ // Now only logs when isEven or category actually changes
81
+ })
82
+ </script>
83
+ ```
84
+
85
+ ## Primitive vs Object Computed Behavior (Vue 3.4+)
86
+
87
+ ```javascript
88
+ import { ref, computed, watchEffect } from 'vue'
89
+
90
+ const count = ref(0)
91
+
92
+ // PRIMITIVE: Vue automatically detects value hasn't changed
93
+ const isEven = computed(() => count.value % 2 === 0)
94
+
95
+ watchEffect(() => console.log(isEven.value)) // true
96
+
97
+ count.value = 2 // isEven still true - NO log
98
+ count.value = 4 // isEven still true - NO log
99
+ count.value = 3 // isEven now false - logs: false
100
+
101
+ // OBJECT: New reference every time (without manual comparison)
102
+ const obj = computed(() => ({ isEven: count.value % 2 === 0 }))
103
+
104
+ watchEffect(() => console.log(obj.value)) // { isEven: true }
105
+
106
+ count.value = 2 // Logs again! New object reference
107
+ count.value = 4 // Logs again! New object reference
108
+ ```
109
+
110
+ ## Advanced: Deep Object Comparison
111
+
112
+ ```javascript
113
+ import { ref, computed } from 'vue'
114
+ import { isEqual } from 'lodash-es' // For deep comparison
115
+
116
+ const filters = ref({ category: 'all', sortBy: 'date', page: 1 })
117
+
118
+ // For complex objects, use deep comparison
119
+ const activeFilters = computed((oldValue) => {
120
+ const newValue = {
121
+ ...filters.value,
122
+ hasFilters: filters.value.category !== 'all' || filters.value.sortBy !== 'date'
123
+ }
124
+
125
+ // Deep compare for complex objects
126
+ if (oldValue && isEqual(oldValue, newValue)) {
127
+ return oldValue
128
+ }
129
+
130
+ return newValue
131
+ })
132
+ ```
133
+
134
+ ## Important: Always Compute Before Comparing
135
+
136
+ ```javascript
137
+ // BAD: Early return prevents dependency tracking
138
+ const optimized = computed((oldValue) => {
139
+ if (oldValue && someCondition) {
140
+ return oldValue // Dependencies not tracked!
141
+ }
142
+ return computeExpensiveValue()
143
+ })
144
+
145
+ // GOOD: Compute first, then compare
146
+ const optimized = computed((oldValue) => {
147
+ const newValue = computeExpensiveValue() // Always track dependencies
148
+ if (oldValue && newValue === oldValue) {
149
+ return oldValue
150
+ }
151
+ return newValue
152
+ })
153
+ ```
154
+
155
+ ## Reference
156
+ - [Vue.js Performance - Computed Stability](https://vuejs.org/guide/best-practices/performance.html#computed-stability)
157
+ - [Vue.js Computed Properties](https://vuejs.org/guide/essentials/computed.html)
@@ -0,0 +1,140 @@
1
+ ---
2
+ title: Keep Props Stable to Minimize Child Re-renders
3
+ impact: HIGH
4
+ impactDescription: Passing changing props to list items causes ALL children to re-render unnecessarily
5
+ type: efficiency
6
+ tags: [vue3, performance, props, v-for, re-renders, optimization]
7
+ ---
8
+
9
+ # Keep Props Stable to Minimize Child Re-renders
10
+
11
+ **Impact: HIGH** - When props passed to child components change, Vue must re-render those components. Passing derived values like `activeId` to every list item causes all items to re-render when activeId changes, even if only one item's active state actually changed.
12
+
13
+ Move comparison logic to the parent and pass the boolean result instead. This is one of the most impactful update performance optimizations in Vue.
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] Avoid passing parent-level state that all children compare against (like `activeId`)
18
+ - [ ] Pre-compute derived boolean props in the parent (like `:active="item.id === activeId"`)
19
+ - [ ] Profile re-renders using Vue DevTools to identify prop stability issues
20
+ - [ ] Consider this pattern especially critical for large lists
21
+
22
+ **Incorrect:**
23
+ ```vue
24
+ <template>
25
+ <!-- BAD: activeId changes -> ALL 100 ListItems re-render -->
26
+ <ListItem
27
+ v-for="item in list"
28
+ :key="item.id"
29
+ :id="item.id"
30
+ :active-id="activeId"
31
+ />
32
+ </template>
33
+
34
+ <script setup>
35
+ import { ref } from 'vue'
36
+
37
+ const list = ref([/* 100 items */])
38
+ const activeId = ref(null)
39
+
40
+ // When activeId changes from 1 to 2:
41
+ // - ListItem 1 needs to re-render (was active, now not)
42
+ // - ListItem 2 needs to re-render (was not active, now active)
43
+ // - All other 98 ListItems ALSO re-render because activeId prop changed!
44
+ </script>
45
+ ```
46
+
47
+ ```vue
48
+ <!-- ListItem.vue - receives activeId and compares internally -->
49
+ <template>
50
+ <div :class="{ active: id === activeId }">
51
+ {{ id }}
52
+ </div>
53
+ </template>
54
+
55
+ <script setup>
56
+ defineProps({
57
+ id: Number,
58
+ activeId: Number // This prop changes for ALL items
59
+ })
60
+ </script>
61
+ ```
62
+
63
+ **Correct:**
64
+ ```vue
65
+ <template>
66
+ <!-- GOOD: Only items whose :active actually changed will re-render -->
67
+ <ListItem
68
+ v-for="item in list"
69
+ :key="item.id"
70
+ :id="item.id"
71
+ :active="item.id === activeId"
72
+ />
73
+ </template>
74
+
75
+ <script setup>
76
+ import { ref } from 'vue'
77
+
78
+ const list = ref([/* 100 items */])
79
+ const activeId = ref(null)
80
+
81
+ // When activeId changes from 1 to 2:
82
+ // - ListItem 1: :active changed from true to false -> re-renders
83
+ // - ListItem 2: :active changed from false to true -> re-renders
84
+ // - All other 98 ListItems: :active is still false -> NO re-render!
85
+ </script>
86
+ ```
87
+
88
+ ```vue
89
+ <!-- ListItem.vue - receives pre-computed boolean -->
90
+ <template>
91
+ <div :class="{ active }">
92
+ {{ id }}
93
+ </div>
94
+ </template>
95
+
96
+ <script setup>
97
+ defineProps({
98
+ id: Number,
99
+ active: Boolean // This only changes for items that truly changed
100
+ })
101
+ </script>
102
+ ```
103
+
104
+ ## Common Patterns That Cause Prop Instability
105
+
106
+ ```vue
107
+ <!-- BAD: Passing index that could shift -->
108
+ <Item
109
+ v-for="(item, index) in items"
110
+ :key="item.id"
111
+ :index="index"
112
+ :total="items.length" <!-- Changes when list changes -->
113
+ />
114
+
115
+ <!-- BAD: Passing entire selection set -->
116
+ <Item
117
+ v-for="item in items"
118
+ :key="item.id"
119
+ :selected-ids="selectedIds" <!-- All items re-render on any selection -->
120
+ />
121
+
122
+ <!-- GOOD: Pre-compute the boolean -->
123
+ <Item
124
+ v-for="item in items"
125
+ :key="item.id"
126
+ :selected="selectedIds.includes(item.id)"
127
+ />
128
+ ```
129
+
130
+ ## Performance Impact Example
131
+
132
+ | Scenario | Props Changed | Components Re-rendered |
133
+ |----------|---------------|------------------------|
134
+ | 100 items, pass `activeId` | 100 | 100 (all) |
135
+ | 100 items, pass `:active` boolean | 2 | 2 (only changed) |
136
+ | 1000 items, pass `activeId` | 1000 | 1000 (all) |
137
+ | 1000 items, pass `:active` boolean | 2 | 2 (only changed) |
138
+
139
+ ## Reference
140
+ - [Vue.js Performance - Props Stability](https://vuejs.org/guide/best-practices/performance.html#props-stability)
@@ -0,0 +1,109 @@
1
+ # Use Global Properties Sparingly in Plugins
2
+
3
+ ## Rule
4
+
5
+ When using `app.config.globalProperties` in Vue plugins, use them sparingly and with clear naming conventions. Excessive global properties lead to confusion, naming conflicts, and debugging difficulties.
6
+
7
+ ## Why This Matters
8
+
9
+ 1. **Implicit dependencies**: Global properties make component dependencies invisible, making code harder to understand and maintain.
10
+
11
+ 2. **Naming collisions**: Multiple plugins may try to use the same property name (e.g., `$http`, `$api`), causing silent overwrites.
12
+
13
+ 3. **Debugging difficulty**: When issues arise, tracing back to which plugin provides a global property is challenging.
14
+
15
+ 4. **IDE limitations**: Global properties may not have proper autocomplete or type checking without careful configuration.
16
+
17
+ 5. **Testing complexity**: Global state is harder to mock and isolate in unit tests.
18
+
19
+ ## Bad Practice
20
+
21
+ ```typescript
22
+ // Too many global properties from various plugins
23
+ app.config.globalProperties.$http = axios
24
+ app.config.globalProperties.$api = apiClient
25
+ app.config.globalProperties.$auth = authService
26
+ app.config.globalProperties.$translate = i18n.translate
27
+ app.config.globalProperties.$format = formatters
28
+ app.config.globalProperties.$utils = utilities
29
+ app.config.globalProperties.$config = appConfig
30
+ app.config.globalProperties.$logger = logger
31
+
32
+ // In component - where did all these come from?
33
+ export default {
34
+ mounted() {
35
+ this.$logger.info('Mounted')
36
+ const data = await this.$http.get(this.$config.apiUrl)
37
+ this.$api.process(this.$utils.transform(data))
38
+ }
39
+ }
40
+ ```
41
+
42
+ ## Good Practice
43
+
44
+ ```typescript
45
+ // Use provide/inject for most functionality
46
+ export default {
47
+ install(app, options) {
48
+ // Provide services via injection
49
+ app.provide('api', apiClient)
50
+ app.provide('auth', authService)
51
+ app.provide('i18n', i18n)
52
+
53
+ // Reserve globalProperties for truly global template helpers
54
+ // that are used extensively in templates across the app
55
+ app.config.globalProperties.$t = i18n.translate // Common convention
56
+ }
57
+ }
58
+
59
+ // In component - explicit dependencies
60
+ <script setup>
61
+ import { inject } from 'vue'
62
+
63
+ const api = inject('api')
64
+ const auth = inject('auth')
65
+ </script>
66
+
67
+ <template>
68
+ <!-- $t is acceptable for common template-only usage -->
69
+ <h1>{{ $t('welcome') }}</h1>
70
+ </template>
71
+ ```
72
+
73
+ ## Naming Conventions
74
+
75
+ If you do use globalProperties:
76
+
77
+ 1. **Use `$` prefix**: This is the Vue convention and avoids conflicts with component data/methods
78
+ 2. **Use unique prefixes for your library**: e.g., `$myLib_translate` for third-party plugins
79
+ 3. **Document all global properties**: Keep a central registry of what each plugin provides
80
+
81
+ ```typescript
82
+ // Good: namespaced to avoid conflicts
83
+ app.config.globalProperties.$myPlugin = {
84
+ translate: (key) => /* ... */,
85
+ format: (value) => /* ... */
86
+ }
87
+
88
+ // Usage
89
+ {{ $myPlugin.translate('key') }}
90
+ ```
91
+
92
+ ## Auditing Global Properties
93
+
94
+ You can inspect all global properties for debugging:
95
+
96
+ ```typescript
97
+ console.log(app.config.globalProperties)
98
+ ```
99
+
100
+ ## When Global Properties Are Acceptable
101
+
102
+ 1. **Template-only utilities** used very frequently (like `$t` for translations)
103
+ 2. **Legacy migration** when transitioning from Vue 2
104
+ 3. **Libraries that need Options API compatibility** (but prefer also providing inject)
105
+
106
+ ## References
107
+
108
+ - [Vue.js Plugins Documentation](https://vuejs.org/guide/reusability/plugins.html)
109
+ - [Vue.js Global Properties](https://vuejs.org/api/application.html#app-config-globalproperties)