@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,160 @@
1
+ ---
2
+ title: Never Mutate Computed Property Return Values
3
+ impact: HIGH
4
+ impactDescription: Mutating computed values causes silent failures and lost changes
5
+ type: capability
6
+ tags: [vue3, computed, reactivity, immutability, common-mistake]
7
+ ---
8
+
9
+ # Never Mutate Computed Property Return Values
10
+
11
+ **Impact: HIGH** - The returned value from a computed property is derived state - a temporary snapshot. Mutating this value leads to bugs that are difficult to debug.
12
+
13
+ **Important:** Mutations DO persist while the computed cache remains valid, but are lost when recomputation occurs. The danger lies in unpredictable cache invalidation timing - any change to the computed's dependencies triggers recomputation, silently discarding your mutations. This makes bugs intermittent and hard to reproduce.
14
+
15
+ Every time the source state changes, a new snapshot is created. Mutating a snapshot is meaningless because it will be discarded on the next recalculation.
16
+
17
+ ## Task Checklist
18
+
19
+ - [ ] Treat computed return values as read-only
20
+ - [ ] Update the source state instead of the computed value
21
+ - [ ] Use writable computed properties if bidirectional binding is needed
22
+ - [ ] Avoid array mutating methods (push, pop, splice, reverse, sort) on computed arrays
23
+
24
+ **Incorrect:**
25
+ ```vue
26
+ <script setup>
27
+ import { ref, computed } from 'vue'
28
+
29
+ const books = ref(['Vue Guide', 'React Handbook'])
30
+
31
+ const publishedBooks = computed(() => {
32
+ return books.value.filter(book => book.includes('Guide'))
33
+ })
34
+
35
+ function addBook() {
36
+ // BAD: Mutating computed value - change will be lost!
37
+ publishedBooks.value.push('New Book')
38
+ }
39
+
40
+ // BAD: Mutating computed array
41
+ const sortedBooks = computed(() => books.value.filter(b => b))
42
+
43
+ function reverseBooks() {
44
+ // BAD: This mutates the computed snapshot
45
+ sortedBooks.value.reverse()
46
+ }
47
+ </script>
48
+ ```
49
+
50
+ ```vue
51
+ <script>
52
+ export default {
53
+ data() {
54
+ return {
55
+ author: {
56
+ name: 'John',
57
+ books: ['Book A', 'Book B']
58
+ }
59
+ }
60
+ },
61
+ computed: {
62
+ authorBooks() {
63
+ return this.author.books
64
+ }
65
+ },
66
+ methods: {
67
+ addBook() {
68
+ // BAD: Mutating computed value
69
+ this.authorBooks.push('New Book')
70
+ }
71
+ }
72
+ }
73
+ </script>
74
+ ```
75
+
76
+ **Correct:**
77
+ ```vue
78
+ <script setup>
79
+ import { ref, computed } from 'vue'
80
+
81
+ const books = ref(['Vue Guide', 'React Handbook'])
82
+
83
+ const publishedBooks = computed(() => {
84
+ return books.value.filter(book => book.includes('Guide'))
85
+ })
86
+
87
+ function addBook(bookName) {
88
+ // GOOD: Update the source state
89
+ books.value.push(bookName)
90
+ }
91
+
92
+ // GOOD: Create a copy before mutating for display
93
+ const sortedBooks = computed(() => {
94
+ return [...books.value].sort() // Spread to create copy before sort
95
+ })
96
+
97
+ const reversedBooks = computed(() => {
98
+ return [...books.value].reverse() // Spread to create copy before reverse
99
+ })
100
+ </script>
101
+ ```
102
+
103
+ ```vue
104
+ <script>
105
+ export default {
106
+ data() {
107
+ return {
108
+ author: {
109
+ name: 'John',
110
+ books: ['Book A', 'Book B']
111
+ }
112
+ }
113
+ },
114
+ computed: {
115
+ authorBooks() {
116
+ return this.author.books
117
+ }
118
+ },
119
+ methods: {
120
+ addBook(bookName) {
121
+ // GOOD: Update source state
122
+ this.author.books.push(bookName)
123
+ }
124
+ }
125
+ }
126
+ </script>
127
+ ```
128
+
129
+ ## Writable Computed for Bidirectional Binding
130
+
131
+ If you genuinely need to "set" a computed value, use a writable computed property:
132
+
133
+ ```vue
134
+ <script setup>
135
+ import { ref, computed } from 'vue'
136
+
137
+ const firstName = ref('John')
138
+ const lastName = ref('Doe')
139
+
140
+ // Writable computed with getter and setter
141
+ const fullName = computed({
142
+ get() {
143
+ return `${firstName.value} ${lastName.value}`
144
+ },
145
+ set(newValue) {
146
+ // Update source state based on the new value
147
+ const parts = newValue.split(' ')
148
+ firstName.value = parts[0] || ''
149
+ lastName.value = parts[1] || ''
150
+ }
151
+ })
152
+
153
+ // Now this is valid:
154
+ fullName.value = 'Jane Smith' // Updates firstName and lastName
155
+ </script>
156
+ ```
157
+
158
+ ## Reference
159
+ - [Vue.js Computed Properties - Avoid Mutating Computed Value](https://vuejs.org/guide/essentials/computed.html#avoid-mutating-computed-value)
160
+ - [Vue.js Computed Properties - Writable Computed](https://vuejs.org/guide/essentials/computed.html#writable-computed)
@@ -0,0 +1,89 @@
1
+ ---
2
+ title: Configure Vue App Before Calling mount()
3
+ impact: HIGH
4
+ impactDescription: App configurations after mount() are silently ignored, causing missing plugins and handlers
5
+ type: capability
6
+ tags: [vue3, createApp, mount, configuration, setup]
7
+ ---
8
+
9
+ # Configure Vue App Before Calling mount()
10
+
11
+ **Impact: HIGH** - Any app configurations applied after `.mount()` is called are silently ignored. This includes error handlers, global components, directives, and plugins, leading to mysterious missing functionality.
12
+
13
+ The `.mount()` method should always be called after all app configurations and asset registrations are done. This is a critical ordering requirement that, when violated, produces no errors but causes features to silently fail.
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] Register all plugins (router, store, etc.) before mount()
18
+ - [ ] Configure error handlers before mount()
19
+ - [ ] Register global components and directives before mount()
20
+ - [ ] Set all `app.config` properties before mount()
21
+ - [ ] Call `.mount()` as the final step in app initialization
22
+
23
+ **Incorrect:**
24
+ ```javascript
25
+ import { createApp } from 'vue'
26
+ import App from './App.vue'
27
+ import router from './router'
28
+
29
+ const app = createApp(App)
30
+
31
+ // WRONG: Mounting first, then configuring
32
+ app.mount('#app')
33
+
34
+ // These are silently IGNORED - app is already mounted!
35
+ app.use(router)
36
+ app.config.errorHandler = (err) => {
37
+ console.error('Global error:', err)
38
+ }
39
+ app.component('GlobalButton', GlobalButton)
40
+ ```
41
+
42
+ **Correct:**
43
+ ```javascript
44
+ import { createApp } from 'vue'
45
+ import App from './App.vue'
46
+ import router from './router'
47
+ import { createPinia } from 'pinia'
48
+ import GlobalButton from './components/GlobalButton.vue'
49
+
50
+ const app = createApp(App)
51
+
52
+ // Configure everything FIRST
53
+ app.use(router)
54
+ app.use(createPinia())
55
+
56
+ // Set up error handling
57
+ app.config.errorHandler = (err, instance, info) => {
58
+ console.error('Global error:', err)
59
+ console.log('Component:', instance)
60
+ console.log('Error info:', info)
61
+ }
62
+
63
+ // Register global components
64
+ app.component('GlobalButton', GlobalButton)
65
+
66
+ // Mount LAST - after all configuration is complete
67
+ app.mount('#app')
68
+ ```
69
+
70
+ ## Common Mistake: Chaining with Mount
71
+
72
+ ```javascript
73
+ // WRONG: Chaining mount in the middle of configuration
74
+ createApp(App)
75
+ .use(router)
76
+ .mount('#app') // Everything after this line is a problem
77
+ .use(pinia) // This doesn't even work - mount returns component instance!
78
+
79
+ // CORRECT: Either complete chain before mount, or use intermediate variable
80
+ createApp(App)
81
+ .use(router)
82
+ .use(pinia)
83
+ .component('GlobalButton', GlobalButton)
84
+ .mount('#app') // Mount at the very end
85
+ ```
86
+
87
+ ## Reference
88
+ - [Vue.js - Creating a Vue Application](https://vuejs.org/guide/essentials/application.html)
89
+ - [Vue.js Application API](https://vuejs.org/api/application.html)
@@ -0,0 +1,212 @@
1
+ ---
2
+ title: Always Declare Emits for Documentation and Validation
3
+ impact: MEDIUM
4
+ impactDescription: Undeclared emits cause warnings, break TypeScript inference, and prevent event validation
5
+ type: best-practice
6
+ tags: [vue3, emits, defineEmits, component-events, typescript, documentation]
7
+ ---
8
+
9
+ # Always Declare Emits for Documentation and Validation
10
+
11
+ **Impact: MEDIUM** - Declaring emitted events with `defineEmits()` or the `emits` option is technically optional, but strongly recommended. Without declarations, Vue shows runtime warnings, TypeScript can't infer event types, and you lose the ability to validate event payloads.
12
+
13
+ Declared emits also serve as self-documentation, making it immediately clear what events a component can emit.
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] Use `defineEmits()` in `<script setup>` to declare all events
18
+ - [ ] Use `emits` option when not using `<script setup>`
19
+ - [ ] Add TypeScript types for event payloads
20
+ - [ ] Consider adding validation functions for complex payloads
21
+ - [ ] Document the purpose of each event
22
+
23
+ ## The Warning
24
+
25
+ When you emit without declaring:
26
+
27
+ ```vue
28
+ <script setup>
29
+ // No defineEmits declaration
30
+ function handleClick() {
31
+ emit('select', item) // Vue warns in dev mode
32
+ }
33
+ </script>
34
+ ```
35
+
36
+ Vue warns:
37
+ ```
38
+ [Vue warn]: Component emitted event "select" but it is neither declared
39
+ in the emits option nor as an "onSelect" prop.
40
+ ```
41
+
42
+ ## Basic Declaration
43
+
44
+ **Correct - Array syntax:**
45
+ ```vue
46
+ <script setup>
47
+ const emit = defineEmits(['submit', 'cancel', 'update'])
48
+
49
+ function handleSubmit() {
50
+ emit('submit', formData)
51
+ }
52
+
53
+ function handleCancel() {
54
+ emit('cancel')
55
+ }
56
+ </script>
57
+ ```
58
+
59
+ **Correct - Options API:**
60
+ ```js
61
+ export default {
62
+ emits: ['submit', 'cancel', 'update'],
63
+
64
+ methods: {
65
+ handleSubmit() {
66
+ this.$emit('submit', this.formData)
67
+ }
68
+ }
69
+ }
70
+ ```
71
+
72
+ ## TypeScript Typed Emits
73
+
74
+ **Correct - Type-based declaration (recommended for TypeScript):**
75
+ ```vue
76
+ <script setup lang="ts">
77
+ interface User {
78
+ id: number
79
+ name: string
80
+ }
81
+
82
+ const emit = defineEmits<{
83
+ submit: [data: FormData]
84
+ cancel: []
85
+ 'update:modelValue': [value: string]
86
+ select: [user: User, index: number]
87
+ }>()
88
+
89
+ // Now TypeScript enforces correct payloads
90
+ emit('submit', formData) // OK
91
+ emit('submit') // Error: Expected 1 argument
92
+ emit('select', user) // Error: Expected 2 arguments
93
+ emit('unknown') // Error: Unknown event
94
+ </script>
95
+ ```
96
+
97
+ **Alternative syntax (Vue 3.3+):**
98
+ ```vue
99
+ <script setup lang="ts">
100
+ const emit = defineEmits<{
101
+ (e: 'submit', data: FormData): void
102
+ (e: 'cancel'): void
103
+ (e: 'update:modelValue', value: string): void
104
+ }>()
105
+ </script>
106
+ ```
107
+
108
+ ## Event Validation
109
+
110
+ You can validate event payloads at runtime:
111
+
112
+ **Correct - Validation functions:**
113
+ ```vue
114
+ <script setup>
115
+ const emit = defineEmits({
116
+ // No validation, just declaration
117
+ cancel: null,
118
+
119
+ // Validate payload
120
+ submit: (payload) => {
121
+ if (!payload.email) {
122
+ console.warn('Submit event requires email')
123
+ return false
124
+ }
125
+ return true
126
+ },
127
+
128
+ // Validate with type checking
129
+ click: (id) => typeof id === 'number'
130
+ })
131
+ </script>
132
+ ```
133
+
134
+ Returning `false` from a validator logs a console warning but doesn't prevent the event from being emitted.
135
+
136
+ ## Benefits of Declaring Emits
137
+
138
+ ### 1. Fallthrough Attribute Separation
139
+
140
+ Without declaration, native event listeners fall through to the root element:
141
+
142
+ ```vue
143
+ <!-- ParentComponent.vue -->
144
+ <ChildComponent @click="handleClick" />
145
+ ```
146
+
147
+ ```vue
148
+ <!-- ChildComponent.vue - WITHOUT emits declaration -->
149
+ <template>
150
+ <!-- Native click listener falls through to button -->
151
+ <button>Click me</button>
152
+ </template>
153
+ ```
154
+
155
+ With declaration, Vue knows it's a component event:
156
+
157
+ ```vue
158
+ <script setup>
159
+ // Now Vue knows 'click' is a component event, not native
160
+ const emit = defineEmits(['click'])
161
+ </script>
162
+ ```
163
+
164
+ ### 2. Self-Documentation
165
+
166
+ ```vue
167
+ <script setup>
168
+ // Clear contract: this component emits these events
169
+ const emit = defineEmits<{
170
+ 'row-click': [row: TableRow]
171
+ 'row-select': [row: TableRow, selected: boolean]
172
+ 'page-change': [page: number]
173
+ 'sort-change': [column: string, direction: 'asc' | 'desc']
174
+ }>()
175
+ </script>
176
+ ```
177
+
178
+ ### 3. IDE Support
179
+
180
+ With declarations, your IDE can:
181
+ - Autocomplete event names when using the component
182
+ - Show event payload types
183
+ - Warn about typos in event names
184
+ - Navigate to event definitions
185
+
186
+ ## $emit in Template vs emit in Script
187
+
188
+ ```vue
189
+ <script setup>
190
+ // $emit is available in template, but...
191
+ // emit() is needed in <script setup>
192
+ const emit = defineEmits(['submit'])
193
+
194
+ function handleSubmit() {
195
+ // $emit doesn't work here - use emit()
196
+ emit('submit', data)
197
+ }
198
+ </script>
199
+
200
+ <template>
201
+ <!-- $emit works in template -->
202
+ <button @click="$emit('submit', data)">Submit</button>
203
+
204
+ <!-- Or use the declared emit function -->
205
+ <button @click="emit('submit', data)">Submit</button>
206
+ </template>
207
+ ```
208
+
209
+ ## Reference
210
+ - [Vue.js Component Events - Declaring Emitted Events](https://vuejs.org/guide/components/events.html#declaring-emitted-events)
211
+ - [Vue.js Component Events - Events Validation](https://vuejs.org/guide/components/events.html#events-validation)
212
+ - [Vue 3 Migration - emits Option](https://v3-migration.vuejs.org/breaking-changes/emits-option)
@@ -0,0 +1,192 @@
1
+ ---
2
+ title: defineExpose Must Be Called Before Any Await
3
+ impact: HIGH
4
+ impactDescription: Properties exposed after await are inaccessible to parent component refs
5
+ type: gotcha
6
+ tags: [vue3, script-setup, defineExpose, async, component-refs]
7
+ ---
8
+
9
+ # defineExpose Must Be Called Before Any Await
10
+
11
+ **Impact: HIGH** - In `<script setup>`, if you call `defineExpose()` after an `await` statement, the exposed properties will NOT be accessible to parent components using template refs. This is a subtle async timing issue that causes silent failures.
12
+
13
+ The compiler transforms top-level await, and code after await runs in a different execution context where defineExpose cannot properly register with the component instance.
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] Always call defineExpose() at the top of script setup, before any await
18
+ - [ ] If async data is needed in exposed methods, fetch it separately
19
+ - [ ] Structure code so expose declarations come first
20
+ - [ ] Test parent ref access when using async setup
21
+
22
+ **Incorrect:**
23
+ ```vue
24
+ <!-- ChildComponent.vue -->
25
+ <script setup>
26
+ import { ref } from 'vue'
27
+
28
+ const data = ref(null)
29
+ const count = ref(0)
30
+
31
+ function increment() {
32
+ count.value++
33
+ }
34
+
35
+ // WRONG: await before defineExpose
36
+ const response = await fetch('/api/data')
37
+ data.value = await response.json()
38
+
39
+ // BROKEN: This won't work - called after await!
40
+ defineExpose({
41
+ count,
42
+ increment,
43
+ data
44
+ })
45
+ </script>
46
+
47
+ <template>
48
+ <div>{{ data }}</div>
49
+ </template>
50
+ ```
51
+
52
+ ```vue
53
+ <!-- ParentComponent.vue -->
54
+ <script setup>
55
+ import { ref, onMounted } from 'vue'
56
+ import ChildComponent from './ChildComponent.vue'
57
+
58
+ const childRef = ref(null)
59
+
60
+ onMounted(() => {
61
+ // FAILS: All exposed properties are undefined!
62
+ console.log(childRef.value.count) // undefined
63
+ childRef.value.increment() // TypeError
64
+ })
65
+ </script>
66
+
67
+ <template>
68
+ <Suspense>
69
+ <ChildComponent ref="childRef" />
70
+ </Suspense>
71
+ </template>
72
+ ```
73
+
74
+ **Correct:**
75
+ ```vue
76
+ <!-- ChildComponent.vue -->
77
+ <script setup>
78
+ import { ref } from 'vue'
79
+
80
+ const data = ref(null)
81
+ const count = ref(0)
82
+
83
+ function increment() {
84
+ count.value++
85
+ }
86
+
87
+ // CORRECT: defineExpose BEFORE any await
88
+ defineExpose({
89
+ count,
90
+ increment,
91
+ data
92
+ })
93
+
94
+ // Now safe to use await
95
+ const response = await fetch('/api/data')
96
+ data.value = await response.json()
97
+ </script>
98
+
99
+ <template>
100
+ <div>{{ data }}</div>
101
+ </template>
102
+ ```
103
+
104
+ ```vue
105
+ <!-- Alternative: Separate async logic from expose -->
106
+ <script setup>
107
+ import { ref, onMounted } from 'vue'
108
+
109
+ const data = ref(null)
110
+ const loading = ref(true)
111
+
112
+ function getData() {
113
+ return data.value
114
+ }
115
+
116
+ async function refreshData() {
117
+ loading.value = true
118
+ const response = await fetch('/api/data')
119
+ data.value = await response.json()
120
+ loading.value = false
121
+ }
122
+
123
+ // CORRECT: No await at top level - defineExpose always works
124
+ defineExpose({
125
+ data,
126
+ getData,
127
+ refreshData,
128
+ loading
129
+ })
130
+
131
+ // Trigger async load in lifecycle hook instead
132
+ onMounted(() => {
133
+ refreshData()
134
+ })
135
+ </script>
136
+
137
+ <template>
138
+ <div v-if="loading">Loading...</div>
139
+ <div v-else>{{ data }}</div>
140
+ </template>
141
+ ```
142
+
143
+ ```vue
144
+ <!-- If you must use top-level await, define expose first -->
145
+ <script setup>
146
+ import { ref } from 'vue'
147
+
148
+ const user = ref(null)
149
+ const posts = ref([])
150
+
151
+ // CORRECT: All expose calls come first
152
+ defineExpose({
153
+ user,
154
+ posts,
155
+ refresh: () => loadData()
156
+ })
157
+
158
+ // Now safe to await
159
+ async function loadData() {
160
+ const [userRes, postsRes] = await Promise.all([
161
+ fetch('/api/user'),
162
+ fetch('/api/posts')
163
+ ])
164
+ user.value = await userRes.json()
165
+ posts.value = await postsRes.json()
166
+ }
167
+
168
+ // Top-level await after defineExpose is safe
169
+ await loadData()
170
+ </script>
171
+ ```
172
+
173
+ ## Why This Happens
174
+
175
+ Vue's compiler transforms `<script setup>` with top-level await into an async setup function. The component instance context is only available synchronously before the first await. After await, the execution resumes outside that context, making defineExpose ineffective.
176
+
177
+ ```javascript
178
+ // What the compiler roughly generates:
179
+ async setup() {
180
+ const count = ref(0)
181
+
182
+ // Context available here
183
+ await fetch(...) // Suspends execution
184
+
185
+ // Context lost after resuming
186
+ defineExpose({ count }) // Too late!
187
+ }
188
+ ```
189
+
190
+ ## Reference
191
+ - [Vue.js Script Setup - defineExpose](https://vuejs.org/api/sfc-script-setup.html#defineexpose)
192
+ - [Vue.js Async Components](https://vuejs.org/guide/components/async.html)