@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,166 @@
1
+ ---
2
+ title: Understand Reactive Updates are Batched Per Event Loop Tick
3
+ impact: MEDIUM
4
+ impactDescription: Multiple synchronous reactive changes are batched - watchers only see the final value, not intermediate states
5
+ type: gotcha
6
+ tags: [vue3, reactivity, batching, event-loop, watchers, nextTick]
7
+ ---
8
+
9
+ # Understand Reactive Updates are Batched Per Event Loop Tick
10
+
11
+ **Impact: MEDIUM** - Vue batches multiple reactive state changes that happen synchronously within the same event loop tick. Watchers and computed properties only see the final state, not intermediate values. This is an optimization, but it can be surprising if you expect watchers to fire for each individual change.
12
+
13
+ Understanding this behavior is essential for debugging scenarios where you expect to observe every state transition.
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] Understand watchers fire once per tick with final value, not for each mutation
18
+ - [ ] Use `nextTick()` if you need to ensure DOM updates between state changes
19
+ - [ ] Use `flush: 'sync'` on watchers only if you absolutely need immediate execution
20
+ - [ ] For intermediate value tracking, consider logging or explicit state snapshots
21
+
22
+ **Example of batching behavior:**
23
+ ```javascript
24
+ import { ref, watch } from 'vue'
25
+
26
+ const count = ref(0)
27
+
28
+ watch(count, (newValue) => {
29
+ console.log('Count changed to:', newValue)
30
+ })
31
+
32
+ // Multiple synchronous changes in the same tick
33
+ function multipleUpdates() {
34
+ count.value = 1
35
+ count.value = 2
36
+ count.value = 3
37
+ count.value = 4
38
+ }
39
+
40
+ multipleUpdates()
41
+ // Console output: "Count changed to: 4"
42
+ // NOT: 1, 2, 3, 4 - only the final value is observed!
43
+ ```
44
+
45
+ **The console logs you WON'T see:**
46
+ ```javascript
47
+ const items = reactive([])
48
+
49
+ watch(items, (newItems) => {
50
+ console.log('Items count:', newItems.length)
51
+ })
52
+
53
+ // Batch of changes
54
+ items.push('a') // length: 1
55
+ items.push('b') // length: 2
56
+ items.push('c') // length: 3
57
+
58
+ // Output: "Items count: 3"
59
+ // You won't see 1, 2, 3 logged separately
60
+ ```
61
+
62
+ **Using flush: 'sync' for immediate watching (use with caution):**
63
+ ```javascript
64
+ import { ref, watch } from 'vue'
65
+
66
+ const count = ref(0)
67
+
68
+ // Sync watcher fires immediately on each change
69
+ watch(count, (newValue) => {
70
+ console.log('Immediate:', newValue)
71
+ }, { flush: 'sync' })
72
+
73
+ count.value = 1 // Logs: "Immediate: 1"
74
+ count.value = 2 // Logs: "Immediate: 2"
75
+ count.value = 3 // Logs: "Immediate: 3"
76
+
77
+ // WARNING: flush: 'sync' can cause performance issues
78
+ // and creates less predictable behavior. Avoid if possible.
79
+ ```
80
+
81
+ **Using nextTick to separate batches:**
82
+ ```javascript
83
+ import { ref, watch, nextTick } from 'vue'
84
+
85
+ const count = ref(0)
86
+
87
+ watch(count, (newValue) => {
88
+ console.log('Count:', newValue)
89
+ })
90
+
91
+ async function separatedUpdates() {
92
+ count.value = 1
93
+ await nextTick() // Force flush
94
+ // Output: "Count: 1"
95
+
96
+ count.value = 2
97
+ await nextTick()
98
+ // Output: "Count: 2"
99
+
100
+ count.value = 3
101
+ // Output: "Count: 3"
102
+ }
103
+ ```
104
+
105
+ **Practical example - form validation:**
106
+ ```javascript
107
+ const formData = reactive({
108
+ email: '',
109
+ password: ''
110
+ })
111
+
112
+ const validationErrors = ref([])
113
+
114
+ // This watcher only fires once, with final form state
115
+ watch(formData, (data) => {
116
+ // Runs once after all fields are updated
117
+ validateForm(data)
118
+ }, { deep: true })
119
+
120
+ // When user submits, you might update multiple fields
121
+ function populateFromSavedData(saved) {
122
+ formData.email = saved.email
123
+ formData.password = saved.password
124
+ // Validation runs once with both fields set
125
+ }
126
+ ```
127
+
128
+ **When batching helps performance:**
129
+ ```javascript
130
+ // Without batching, this would trigger 1000 watcher/render cycles
131
+ const list = reactive([])
132
+
133
+ function addManyItems() {
134
+ for (let i = 0; i < 1000; i++) {
135
+ list.push(i)
136
+ }
137
+ }
138
+ // With batching: renders once with all 1000 items
139
+ // Without batching: would render 1000 times!
140
+ ```
141
+
142
+ **Debugging intermediate states:**
143
+ ```javascript
144
+ // If you need to observe every change for debugging:
145
+ import { ref, watch } from 'vue'
146
+
147
+ const count = ref(0)
148
+
149
+ // Method 1: Sync watcher (not recommended for production)
150
+ watch(count, (val) => console.log('DEBUG:', val), { flush: 'sync' })
151
+
152
+ // Method 2: Track history manually
153
+ const history = []
154
+ const originalSet = count.value
155
+ Object.defineProperty(count, 'value', {
156
+ set(val) {
157
+ history.push(val)
158
+ originalSet.call(this, val)
159
+ }
160
+ })
161
+ ```
162
+
163
+ ## Reference
164
+ - [Vue.js Reactivity in Depth](https://vuejs.org/guide/extras/reactivity-in-depth.html)
165
+ - [Vue.js Watchers - Callback Flush Timing](https://vuejs.org/guide/essentials/watchers.html#callback-flush-timing)
166
+ - [Vue.js nextTick()](https://vuejs.org/api/general.html#nexttick)
@@ -0,0 +1,61 @@
1
+ ---
2
+ title: Always Use .value When Accessing ref() in JavaScript
3
+ impact: HIGH
4
+ impactDescription: Forgetting .value causes silent failures and bugs in reactive state updates
5
+ type: capability
6
+ tags: [vue3, reactivity, ref, composition-api]
7
+ ---
8
+
9
+ # Always Use .value When Accessing ref() in JavaScript
10
+
11
+ **Impact: HIGH** - Forgetting `.value` causes silent failures where state updates don't trigger reactivity, leading to hard-to-debug issues.
12
+
13
+ When using `ref()` in Vue 3's Composition API, the reactive value is wrapped in an object and must be accessed via `.value` in JavaScript code. However, in templates, Vue automatically unwraps refs so `.value` is not needed there. This inconsistency is a common source of bugs.
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] Always use `.value` when reading or writing ref values in `<script>` or `.js`/`.ts` files
18
+ - [ ] Never use `.value` in `<template>` - Vue unwraps refs automatically there
19
+ - [ ] When passing refs to functions, decide whether to pass the ref object or `.value`
20
+ - [ ] Use IDE/TypeScript to catch missing `.value` errors early
21
+
22
+ **Incorrect:**
23
+ ```javascript
24
+ import { ref } from 'vue'
25
+
26
+ const count = ref(0)
27
+
28
+ // These do NOT work as expected
29
+ count++ // Tries to increment the ref object, not the value
30
+ count = 5 // Reassigns the variable, loses reactivity
31
+ console.log(count) // Logs "[object Object]", not the number
32
+
33
+ const items = ref([1, 2, 3])
34
+ items.push(4) // Error: push is not a function
35
+ ```
36
+
37
+ **Correct:**
38
+ ```javascript
39
+ import { ref } from 'vue'
40
+
41
+ const count = ref(0)
42
+
43
+ // Always use .value in JavaScript
44
+ count.value++ // Correctly increments to 1
45
+ count.value = 5 // Correctly sets value to 5
46
+ console.log(count.value) // Logs "5"
47
+
48
+ const items = ref([1, 2, 3])
49
+ items.value.push(4) // Correctly adds 4 to the array
50
+ ```
51
+
52
+ ```vue
53
+ <template>
54
+ <!-- In templates, NO .value needed - Vue unwraps automatically -->
55
+ <p>{{ count }}</p>
56
+ <button @click="count++">Increment</button>
57
+ </template>
58
+ ```
59
+
60
+ ## Reference
61
+ - [Vue.js Reactivity Fundamentals - ref()](https://vuejs.org/guide/essentials/reactivity-fundamentals.html#ref)
@@ -0,0 +1,81 @@
1
+ ---
2
+ title: Refs in Arrays and Collections Require .value
3
+ impact: MEDIUM
4
+ impactDescription: Refs inside reactive arrays, Maps, or Sets are NOT auto-unwrapped like in reactive objects
5
+ type: capability
6
+ tags: [vue3, reactivity, ref, arrays, collections, unwrapping]
7
+ ---
8
+
9
+ # Refs in Arrays and Collections Require .value
10
+
11
+ **Impact: MEDIUM** - Unlike when a ref is a property of a reactive object, refs inside reactive arrays, Maps, and Sets are NOT automatically unwrapped. You must access them with `.value`, and forgetting this leads to silent bugs.
12
+
13
+ Vue only auto-unwraps refs when they are properties of reactive objects. When refs are elements in arrays or values in Maps/Sets, they remain as ref objects and require explicit `.value` access.
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] Always use `.value` when accessing refs stored in reactive arrays
18
+ - [ ] Always use `.value` when accessing refs stored in reactive Maps or Sets
19
+ - [ ] Consider storing plain values instead of refs in collections to avoid confusion
20
+ - [ ] Be aware of this when iterating over arrays containing refs
21
+
22
+ **Incorrect:**
23
+ ```javascript
24
+ import { ref, reactive } from 'vue'
25
+
26
+ const books = reactive([ref('Vue 3 Guide')])
27
+ const counts = reactive(new Map([['clicks', ref(0)]]))
28
+
29
+ // WRONG: Refs in arrays are NOT unwrapped
30
+ console.log(books[0]) // Ref object, not 'Vue 3 Guide'
31
+ books[0] = 'New Title' // Replaces the ref, doesn't update it!
32
+
33
+ // WRONG: Refs in Maps are NOT unwrapped
34
+ console.log(counts.get('clicks')) // Ref object, not 0
35
+ counts.get('clicks')++ // Does nothing useful
36
+ ```
37
+
38
+ **Correct:**
39
+ ```javascript
40
+ import { ref, reactive } from 'vue'
41
+
42
+ const books = reactive([ref('Vue 3 Guide')])
43
+ const counts = reactive(new Map([['clicks', ref(0)]]))
44
+
45
+ // CORRECT: Use .value for refs in arrays
46
+ console.log(books[0].value) // 'Vue 3 Guide'
47
+ books[0].value = 'New Title' // Updates the ref's value
48
+
49
+ // CORRECT: Use .value for refs in Maps
50
+ console.log(counts.get('clicks').value) // 0
51
+ counts.get('clicks').value++ // Increments to 1
52
+ ```
53
+
54
+ ```javascript
55
+ // ALTERNATIVE: Just store plain values in collections (simpler)
56
+ const books = reactive(['Vue 3 Guide', 'Vuex Handbook'])
57
+ const counts = reactive(new Map([['clicks', 0]]))
58
+
59
+ // No .value needed - but changes to individual items aren't independently reactive
60
+ console.log(books[0]) // 'Vue 3 Guide'
61
+ console.log(counts.get('clicks')) // 0
62
+
63
+ // Mutations still trigger reactivity through the reactive wrapper
64
+ books[0] = 'New Title' // Works
65
+ counts.set('clicks', counts.get('clicks') + 1) // Works
66
+ ```
67
+
68
+ ```vue
69
+ <template>
70
+ <!-- In templates, refs in arrays also need special handling -->
71
+ <div v-for="(book, index) in books" :key="index">
72
+ <!-- If book is a ref, you'd need: -->
73
+ {{ book.value }}
74
+
75
+ <!-- Or use computed to unwrap them first -->
76
+ </div>
77
+ </template>
78
+ ```
79
+
80
+ ## Reference
81
+ - [Vue.js Reactivity Fundamentals - Caveat in Arrays and Collections](https://vuejs.org/guide/essentials/reactivity-fundamentals.html#caveat-in-arrays-and-collections)
@@ -0,0 +1,151 @@
1
+ ---
2
+ title: Do Not Rely on Internal VNode Properties
3
+ impact: MEDIUM
4
+ impactDescription: Using undocumented vnode properties causes code to break on Vue updates
5
+ type: gotcha
6
+ tags: [vue3, render-function, vnode, internal-api]
7
+ ---
8
+
9
+ # Do Not Rely on Internal VNode Properties
10
+
11
+ **Impact: MEDIUM** - The `VNode` interface contains many internal properties used by Vue's rendering system. Relying on any properties other than the documented public ones will cause your code to break when Vue's internal implementation changes.
12
+
13
+ Only use the documented vnode properties: `type`, `props`, `children`, and `key`. All other properties are internal implementation details that may change without notice between Vue versions.
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] Only access documented vnode properties: `type`, `props`, `children`, `key`
18
+ - [ ] Never access properties like `el`, `component`, `shapeFlag`, `patchFlag`, etc.
19
+ - [ ] If you need DOM element access, use template refs instead
20
+ - [ ] Treat vnodes as opaque data structures for rendering, not inspection
21
+
22
+ **Incorrect:**
23
+ ```javascript
24
+ import { h } from 'vue'
25
+
26
+ export default {
27
+ setup(props, { slots }) {
28
+ return () => {
29
+ const slotContent = slots.default?.()
30
+
31
+ // WRONG: Accessing internal properties
32
+ if (slotContent?.[0]?.el) {
33
+ // el is an internal property
34
+ console.log(slotContent[0].el.tagName)
35
+ }
36
+
37
+ // WRONG: Using shapeFlag internal property
38
+ if (slotContent?.[0]?.shapeFlag & 1) {
39
+ // This is internal implementation
40
+ }
41
+
42
+ return h('div', slotContent)
43
+ }
44
+ }
45
+ }
46
+ ```
47
+
48
+ ```javascript
49
+ // WRONG: Inspecting component instance via vnode
50
+ const vnode = h(MyComponent)
51
+ console.log(vnode.component) // Internal property
52
+ console.log(vnode.appContext) // Internal property
53
+ ```
54
+
55
+ **Correct:**
56
+ ```javascript
57
+ import { h } from 'vue'
58
+
59
+ export default {
60
+ setup(props, { slots }) {
61
+ return () => {
62
+ const slotContent = slots.default?.()
63
+
64
+ // CORRECT: Only use documented properties
65
+ if (slotContent?.[0]) {
66
+ const vnode = slotContent[0]
67
+ console.log(vnode.type) // Safe: element type or component
68
+ console.log(vnode.props) // Safe: props object
69
+ console.log(vnode.children) // Safe: children
70
+ console.log(vnode.key) // Safe: key prop
71
+ }
72
+
73
+ return h('div', slotContent)
74
+ }
75
+ }
76
+ }
77
+ ```
78
+
79
+ ```javascript
80
+ import { h, ref, onMounted } from 'vue'
81
+
82
+ export default {
83
+ setup() {
84
+ // CORRECT: Use template refs for DOM access
85
+ const divRef = ref(null)
86
+
87
+ onMounted(() => {
88
+ // Safe way to access DOM element
89
+ console.log(divRef.value.tagName)
90
+ })
91
+
92
+ return () => h('div', { ref: divRef }, 'Content')
93
+ }
94
+ }
95
+ ```
96
+
97
+ ## Documented VNode Properties
98
+
99
+ | Property | Type | Description |
100
+ |----------|------|-------------|
101
+ | `type` | `string \| Component` | Element tag name or component definition |
102
+ | `props` | `object \| null` | Props passed to the vnode |
103
+ | `children` | `any` | Child vnodes, text, or slots |
104
+ | `key` | `string \| number \| null` | Key for list rendering |
105
+
106
+ ## Safe VNode Inspection Patterns
107
+
108
+ ```javascript
109
+ import { h, isVNode } from 'vue'
110
+
111
+ export default {
112
+ setup(props, { slots }) {
113
+ return () => {
114
+ const children = slots.default?.() || []
115
+
116
+ // Safe: Check if something is a vnode
117
+ children.forEach(child => {
118
+ if (isVNode(child)) {
119
+ // Safe: Check vnode type
120
+ if (typeof child.type === 'string') {
121
+ console.log('Element:', child.type)
122
+ } else if (typeof child.type === 'object') {
123
+ console.log('Component:', child.type.name)
124
+ }
125
+
126
+ // Safe: Read props
127
+ if (child.props?.class) {
128
+ console.log('Has class:', child.props.class)
129
+ }
130
+ }
131
+ })
132
+
133
+ return h('div', children)
134
+ }
135
+ }
136
+ }
137
+ ```
138
+
139
+ ## Why This Matters
140
+
141
+ Vue's internal vnode structure may change for:
142
+ - Performance optimizations
143
+ - New feature implementations
144
+ - Bug fixes
145
+ - Tree-shaking improvements
146
+
147
+ Code relying on internal properties will break silently or throw errors when upgrading Vue versions. The documented properties are part of Vue's public API and are guaranteed to remain stable.
148
+
149
+ ## Reference
150
+ - [Vue.js Render Function APIs](https://vuejs.org/api/render-function.html)
151
+ - [Vue.js Render Functions - The Virtual DOM](https://vuejs.org/guide/extras/render-function.html#the-virtual-dom)
@@ -0,0 +1,133 @@
1
+ ---
2
+ title: VNodes Must Be Unique in Render Functions
3
+ impact: HIGH
4
+ impactDescription: Reusing vnode references causes rendering bugs and unexpected behavior
5
+ type: gotcha
6
+ tags: [vue3, render-function, vnode, composition-api]
7
+ ---
8
+
9
+ # VNodes Must Be Unique in Render Functions
10
+
11
+ **Impact: HIGH** - Reusing the same vnode reference multiple times in a render function tree causes rendering bugs, where only one instance appears or updates behave unexpectedly.
12
+
13
+ Every vnode in a component's render tree must be unique. You cannot use the same vnode object multiple times. If you need to render the same element multiple times, create each vnode separately using a factory function or by calling `h()` in a loop.
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] Never store a vnode in a variable and use it multiple times in the same tree
18
+ - [ ] Use a factory function or `.map()` to create multiple similar vnodes
19
+ - [ ] Each `h()` call creates a new vnode, so call it for each instance needed
20
+ - [ ] Be especially careful when extracting vnode creation into helper functions
21
+
22
+ **Incorrect:**
23
+ ```javascript
24
+ import { h } from 'vue'
25
+
26
+ export default {
27
+ setup() {
28
+ return () => {
29
+ // WRONG: Same vnode reference used twice
30
+ const p = h('p', 'Hello')
31
+ return h('div', [p, p]) // Bug! Duplicate vnode reference
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ ```javascript
38
+ import { h } from 'vue'
39
+
40
+ export default {
41
+ setup() {
42
+ return () => {
43
+ // WRONG: Reusing vnode in different parts of tree
44
+ const icon = h('span', { class: 'icon' }, '★')
45
+ return h('div', [
46
+ h('button', [icon, ' Save']), // Uses icon
47
+ h('button', [icon, ' Delete']) // Reuses same icon - Bug!
48
+ ])
49
+ }
50
+ }
51
+ }
52
+ ```
53
+
54
+ **Correct:**
55
+ ```javascript
56
+ import { h } from 'vue'
57
+
58
+ export default {
59
+ setup() {
60
+ return () => {
61
+ // CORRECT: Create new vnode for each use
62
+ return h('div', [
63
+ h('p', 'Hello'),
64
+ h('p', 'Hello')
65
+ ])
66
+ }
67
+ }
68
+ }
69
+ ```
70
+
71
+ ```javascript
72
+ import { h } from 'vue'
73
+
74
+ export default {
75
+ setup() {
76
+ return () => {
77
+ // CORRECT: Factory function creates new vnode each time
78
+ const createIcon = () => h('span', { class: 'icon' }, '★')
79
+ return h('div', [
80
+ h('button', [createIcon(), ' Save']),
81
+ h('button', [createIcon(), ' Delete'])
82
+ ])
83
+ }
84
+ }
85
+ }
86
+ ```
87
+
88
+ ```javascript
89
+ import { h } from 'vue'
90
+
91
+ export default {
92
+ setup() {
93
+ return () => {
94
+ // CORRECT: Using map to create multiple vnodes
95
+ return h('div',
96
+ Array.from({ length: 20 }).map(() => h('p', 'Hello'))
97
+ )
98
+ }
99
+ }
100
+ }
101
+ ```
102
+
103
+ ```javascript
104
+ import { h } from 'vue'
105
+
106
+ export default {
107
+ setup() {
108
+ const items = ['Apple', 'Banana', 'Cherry']
109
+
110
+ return () => h('ul',
111
+ // CORRECT: Each iteration creates a new vnode
112
+ items.map((item, index) =>
113
+ h('li', { key: index }, item)
114
+ )
115
+ )
116
+ }
117
+ }
118
+ ```
119
+
120
+ ## Why VNodes Must Be Unique
121
+
122
+ VNodes are lightweight JavaScript objects that Vue's virtual DOM algorithm uses for diffing and patching. When the same vnode reference appears multiple times:
123
+ - Vue cannot differentiate between the instances
124
+ - The diffing algorithm produces incorrect results
125
+ - Only one instance may render, or updates may corrupt the DOM
126
+
127
+ Each vnode maintains its own identity and position in the tree, which is essential for:
128
+ - Correct DOM patching during updates
129
+ - Proper lifecycle hook execution
130
+ - Accurate key-based reconciliation in lists
131
+
132
+ ## Reference
133
+ - [Vue.js Render Functions - Vnodes Must Be Unique](https://vuejs.org/guide/extras/render-function.html#vnodes-must-be-unique)