@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,148 @@
1
+ ---
2
+ title: Import h Globally in Vue 3 Render Functions
3
+ impact: HIGH
4
+ impactDescription: Vue 3 requires explicit h import; using Vue 2 patterns causes runtime errors
5
+ type: gotcha
6
+ tags: [vue3, render-function, migration, h, vnode, breaking-change]
7
+ ---
8
+
9
+ # Import h Globally in Vue 3 Render Functions
10
+
11
+ **Impact: HIGH** - In Vue 2, the `h` function (createElement) was passed as an argument to render functions. In Vue 3, `h` must be explicitly imported from 'vue'. Using Vue 2 patterns causes runtime errors.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Import `h` from 'vue' at the top of files using render functions
16
+ - [ ] Remove the `h` parameter from render function signatures
17
+ - [ ] Update all render functions when migrating from Vue 2
18
+
19
+ **Incorrect (Vue 2 pattern - broken in Vue 3):**
20
+ ```js
21
+ // WRONG: Vue 2 pattern - h is not passed as argument in Vue 3
22
+ export default {
23
+ render(h) { // h is undefined in Vue 3!
24
+ return h('div', [
25
+ h('span', 'Hello')
26
+ ])
27
+ }
28
+ }
29
+
30
+ // WRONG: Using createElement alias from Vue 2
31
+ export default {
32
+ render(createElement) { // Also undefined
33
+ return createElement('div', 'Hello')
34
+ }
35
+ }
36
+ ```
37
+
38
+ **Correct (Vue 3 pattern):**
39
+ ```js
40
+ // CORRECT: Import h from vue
41
+ import { h } from 'vue'
42
+
43
+ export default {
44
+ render() {
45
+ return h('div', [
46
+ h('span', 'Hello')
47
+ ])
48
+ }
49
+ }
50
+ ```
51
+
52
+ ## With Composition API
53
+
54
+ ```js
55
+ import { h, ref } from 'vue'
56
+
57
+ export default {
58
+ setup() {
59
+ const count = ref(0)
60
+
61
+ // Return a render function from setup
62
+ return () => h('div', [
63
+ h('button', { onClick: () => count.value++ }, `Count: ${count.value}`)
64
+ ])
65
+ }
66
+ }
67
+ ```
68
+
69
+ ## With script setup (Not Recommended)
70
+
71
+ ```vue
72
+ <script setup>
73
+ import { h, ref } from 'vue'
74
+
75
+ const count = ref(0)
76
+
77
+ // Cannot return render function from script setup
78
+ // Must use a separate render option or template
79
+ </script>
80
+
81
+ <!-- script setup typically uses templates, not render functions -->
82
+ <template>
83
+ <div>
84
+ <button @click="count++">Count: {{ count }}</button>
85
+ </div>
86
+ </template>
87
+ ```
88
+
89
+ If you need render functions with `<script setup>`, use the `render` option:
90
+
91
+ ```vue
92
+ <script>
93
+ import { h, ref } from 'vue'
94
+
95
+ export default {
96
+ setup() {
97
+ const count = ref(0)
98
+ return () => h('button', { onClick: () => count.value++ }, count.value)
99
+ }
100
+ }
101
+ </script>
102
+ ```
103
+
104
+ ## Component Resolution Change
105
+
106
+ In Vue 3, you must also explicitly resolve components:
107
+
108
+ **Incorrect:**
109
+ ```js
110
+ // Vue 2: Could use string names for registered components
111
+ render(h) {
112
+ return h('my-component', { props: { value: 1 } })
113
+ }
114
+ ```
115
+
116
+ **Correct:**
117
+ ```js
118
+ import { h, resolveComponent } from 'vue'
119
+
120
+ export default {
121
+ render() {
122
+ // Must resolve component by name
123
+ const MyComponent = resolveComponent('my-component')
124
+ return h(MyComponent, { value: 1 })
125
+ }
126
+ }
127
+
128
+ // Or import the component directly (preferred)
129
+ import { h } from 'vue'
130
+ import MyComponent from './MyComponent.vue'
131
+
132
+ export default {
133
+ render() {
134
+ return h(MyComponent, { value: 1 })
135
+ }
136
+ }
137
+ ```
138
+
139
+ ## Why This Changed
140
+
141
+ Vue 3's `h` is globally importable to:
142
+ 1. Enable tree-shaking (unused features can be removed)
143
+ 2. Support better TypeScript inference
144
+ 3. Allow use outside of component context
145
+
146
+ ## Reference
147
+ - [Vue 3 Migration Guide - Render Function API](https://v3-migration.vuejs.org/breaking-changes/render-function-api.html)
148
+ - [Vue.js Render Functions & JSX](https://vuejs.org/guide/extras/render-function.html)
@@ -0,0 +1,148 @@
1
+ ---
2
+ title: Return Render Function from setup(), Not Direct VNodes
3
+ impact: HIGH
4
+ impactDescription: Returning a vnode directly from setup makes it static; returning a function enables reactive updates
5
+ type: gotcha
6
+ tags: [vue3, render-function, composition-api, setup, reactivity]
7
+ ---
8
+
9
+ # Return Render Function from setup(), Not Direct VNodes
10
+
11
+ **Impact: HIGH** - When using render functions with the Composition API, you must return a function that returns vnodes, not the vnodes directly. Returning vnodes directly creates a static render that never updates when reactive state changes.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Always return an arrow function from setup() when using render functions
16
+ - [ ] Never return h() calls directly from setup()
17
+ - [ ] Ensure reactive values are accessed inside the returned function
18
+
19
+ **Incorrect:**
20
+ ```js
21
+ import { h, ref } from 'vue'
22
+
23
+ export default {
24
+ setup() {
25
+ const count = ref(0)
26
+ const increment = () => count.value++
27
+
28
+ // WRONG: Returns a static vnode, created once
29
+ // Clicking the button updates count.value, but the DOM never changes!
30
+ return h('div', [
31
+ h('p', `Count: ${count.value}`), // Captures count.value at setup time (0)
32
+ h('button', { onClick: increment }, 'Increment')
33
+ ])
34
+ }
35
+ }
36
+ ```
37
+
38
+ **Correct:**
39
+ ```js
40
+ import { h, ref } from 'vue'
41
+
42
+ export default {
43
+ setup() {
44
+ const count = ref(0)
45
+ const increment = () => count.value++
46
+
47
+ // CORRECT: Returns a render function
48
+ // Vue calls this function on every reactive update
49
+ return () => h('div', [
50
+ h('p', `Count: ${count.value}`), // Re-evaluated each render
51
+ h('button', { onClick: increment }, 'Increment')
52
+ ])
53
+ }
54
+ }
55
+ ```
56
+
57
+ ## Why This Happens
58
+
59
+ ```js
60
+ // What Vue does internally:
61
+
62
+ // WRONG approach - setup runs once:
63
+ const result = setup()
64
+ // result is a vnode { type: 'div', children: [...] }
65
+ // Vue renders this once, then has no way to re-render
66
+
67
+ // CORRECT approach - setup returns a function:
68
+ const renderFn = setup()
69
+ // renderFn is () => h('div', ...)
70
+ // Vue calls renderFn() on mount
71
+ // Vue calls renderFn() again whenever dependencies change
72
+ ```
73
+
74
+ ## Common Mistake: Mixing Template and Render Function
75
+
76
+ ```vue
77
+ <script setup>
78
+ import { h, ref } from 'vue'
79
+
80
+ const count = ref(0)
81
+
82
+ // WRONG: Can't use render functions in script setup with templates
83
+ // This h() call does nothing
84
+ const node = h('div', count.value)
85
+ </script>
86
+
87
+ <template>
88
+ <!-- Template is used, render function is ignored -->
89
+ <div>{{ count }}</div>
90
+ </template>
91
+ ```
92
+
93
+ If you need a render function with Composition API, don't use `<script setup>`:
94
+
95
+ ```vue
96
+ <script>
97
+ import { h, ref } from 'vue'
98
+
99
+ export default {
100
+ setup() {
101
+ const count = ref(0)
102
+ return () => h('div', count.value)
103
+ }
104
+ }
105
+ </script>
106
+ <!-- No template - render function is used -->
107
+ ```
108
+
109
+ ## Exposing Values While Using Render Functions
110
+
111
+ ```js
112
+ import { h, ref } from 'vue'
113
+
114
+ export default {
115
+ setup(props, { expose }) {
116
+ const count = ref(0)
117
+ const reset = () => { count.value = 0 }
118
+
119
+ // Expose methods for parent refs
120
+ expose({ reset })
121
+
122
+ // Still return the render function
123
+ return () => h('div', count.value)
124
+ }
125
+ }
126
+ ```
127
+
128
+ ## With Slots
129
+
130
+ ```js
131
+ import { h, ref } from 'vue'
132
+
133
+ export default {
134
+ setup(props, { slots }) {
135
+ const count = ref(0)
136
+
137
+ return () => h('div', [
138
+ h('p', `Count: ${count.value}`),
139
+ // Slots must also be called inside the render function
140
+ slots.default?.()
141
+ ])
142
+ }
143
+ }
144
+ ```
145
+
146
+ ## Reference
147
+ - [Vue.js Render Functions with Composition API](https://vuejs.org/guide/extras/render-function.html#render-functions-jsx)
148
+ - [Vue.js Composition API setup()](https://vuejs.org/api/composition-api-setup.html)
@@ -0,0 +1,168 @@
1
+ ---
2
+ title: Pass Slots as Functions in Render Functions, Not Direct Children
3
+ impact: HIGH
4
+ impactDescription: Passing slot content incorrectly causes slots to not render or be treated as props
5
+ type: gotcha
6
+ tags: [vue3, render-function, slots, children, vnode]
7
+ ---
8
+
9
+ # Pass Slots as Functions in Render Functions, Not Direct Children
10
+
11
+ **Impact: HIGH** - When creating component vnodes with `h()`, children must be passed as slot functions, not as direct children. Passing children directly may cause them to be interpreted as props or fail to render.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Pass slot content as functions: `{ default: () => [...] }`
16
+ - [ ] Use `null` for props when only passing slots to avoid misinterpretation
17
+ - [ ] For default slot only, a single function can be passed directly
18
+ - [ ] For named slots, use an object with slot function properties
19
+
20
+ **Incorrect:**
21
+ ```js
22
+ import { h } from 'vue'
23
+ import MyComponent from './MyComponent.vue'
24
+
25
+ // WRONG: Children array may be misinterpreted
26
+ h(MyComponent, [
27
+ h('span', 'Slot content') // May not render as expected
28
+ ])
29
+
30
+ // WRONG: Named slots as direct properties
31
+ h(MyComponent, {
32
+ header: h('h1', 'Title'), // This is a prop, not a slot!
33
+ default: h('p', 'Content') // This is also a prop
34
+ })
35
+ ```
36
+
37
+ **Correct:**
38
+ ```js
39
+ import { h } from 'vue'
40
+ import MyComponent from './MyComponent.vue'
41
+
42
+ // CORRECT: Default slot as function
43
+ h(MyComponent, null, {
44
+ default: () => h('span', 'Slot content')
45
+ })
46
+
47
+ // CORRECT: Single default slot shorthand
48
+ h(MyComponent, null, () => h('span', 'Slot content'))
49
+
50
+ // CORRECT: Named slots as functions
51
+ h(MyComponent, null, {
52
+ header: () => h('h1', 'Title'),
53
+ default: () => h('p', 'Content'),
54
+ footer: () => [
55
+ h('span', 'Footer item 1'),
56
+ h('span', 'Footer item 2')
57
+ ]
58
+ })
59
+
60
+ // CORRECT: With props AND slots
61
+ h(MyComponent, { size: 'large' }, {
62
+ default: () => 'Button Text'
63
+ })
64
+ ```
65
+
66
+ ## Why Functions?
67
+
68
+ Slots in Vue 3 are functions for lazy evaluation:
69
+
70
+ ```js
71
+ // Slots are called by the child component when needed
72
+ // This enables:
73
+ // 1. Scoped slots (passing data back)
74
+ // 2. Conditional rendering (slot not called if not used)
75
+ // 3. Proper reactivity tracking
76
+
77
+ h(MyList, { items }, {
78
+ // Scoped slot - receives data from child
79
+ item: ({ item, index }) => h('li', `${index}: ${item.name}`)
80
+ })
81
+ ```
82
+
83
+ ## The null Props Gotcha
84
+
85
+ When passing only slots, always use `null` for props:
86
+
87
+ ```js
88
+ // WRONG: Slots object interpreted as props!
89
+ h(MyComponent, {
90
+ default: () => 'Hello'
91
+ })
92
+ // MyComponent receives: props.default = () => 'Hello'
93
+
94
+ // CORRECT: null signals "no props, next arg is slots"
95
+ h(MyComponent, null, {
96
+ default: () => 'Hello'
97
+ })
98
+ // MyComponent receives slot correctly
99
+ ```
100
+
101
+ ## Forwarding Slots from Parent
102
+
103
+ ```js
104
+ export default {
105
+ setup(props, { slots }) {
106
+ return () => h(ChildComponent, null, {
107
+ // Forward all slots from parent
108
+ ...slots,
109
+
110
+ // Or forward specific slots
111
+ default: slots.default,
112
+ header: slots.header
113
+ })
114
+ }
115
+ }
116
+ ```
117
+
118
+ ## Scoped Slots in Render Functions
119
+
120
+ ```js
121
+ // Parent: Receives data from child via slot props
122
+ h(DataTable, { data: items }, {
123
+ row: (slotProps) => h('tr', [
124
+ h('td', slotProps.item.name),
125
+ h('td', slotProps.item.value)
126
+ ])
127
+ })
128
+
129
+ // Child (DataTable): Calls slot with data
130
+ export default {
131
+ props: ['data'],
132
+ setup(props, { slots }) {
133
+ return () => h('table', [
134
+ h('tbody',
135
+ props.data.map(item =>
136
+ // Pass data to slot function
137
+ slots.row?.({ item })
138
+ )
139
+ )
140
+ ])
141
+ }
142
+ }
143
+ ```
144
+
145
+ ## Common Patterns
146
+
147
+ ```js
148
+ // Wrapper component forwarding slots
149
+ h('div', { class: 'wrapper' }, [
150
+ h(InnerComponent, null, slots)
151
+ ])
152
+
153
+ // Conditional slot rendering
154
+ h('div', [
155
+ slots.header?.(), // Optional chaining - only render if slot provided
156
+ h('main', slots.default?.()),
157
+ slots.footer?.()
158
+ ])
159
+
160
+ // Slot with fallback content
161
+ h('div', [
162
+ slots.default?.() ?? h('p', 'Default content when slot not provided')
163
+ ])
164
+ ```
165
+
166
+ ## Reference
167
+ - [Vue.js Render Functions - Passing Slots](https://vuejs.org/guide/extras/render-function.html#passing-slots)
168
+ - [Vue.js Render Functions - Children](https://vuejs.org/guide/extras/render-function.html#children)
@@ -0,0 +1,231 @@
1
+ ---
2
+ title: Use resolveComponent for String Component Names in Render Functions
3
+ impact: HIGH
4
+ impactDescription: String component names don't work in Vue 3 render functions; causes silent failures or runtime errors
5
+ type: gotcha
6
+ tags: [vue3, render-function, components, resolveComponent, migration]
7
+ ---
8
+
9
+ # Use resolveComponent for String Component Names in Render Functions
10
+
11
+ **Impact: HIGH** - In Vue 2, render functions could use string names for globally or locally registered components. In Vue 3, you must either import components directly or use `resolveComponent()`. Using string names causes components to render as HTML elements or fail silently.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Import components directly when possible (preferred)
16
+ - [ ] Use `resolveComponent()` for dynamically registered components
17
+ - [ ] Use `resolveDynamicComponent()` for `<component :is="">` equivalent
18
+ - [ ] Call `resolveComponent()` inside `setup()` or the render function
19
+ - [ ] Handle the case when component is not found
20
+
21
+ **Incorrect:**
22
+ ```js
23
+ import { h } from 'vue'
24
+
25
+ export default {
26
+ render() {
27
+ // WRONG: String names don't resolve to components
28
+ return h('div', [
29
+ h('my-component', { value: 1 }), // Renders <my-component> HTML element!
30
+ h('router-link', { to: '/' }, 'Home') // Also fails
31
+ ])
32
+ }
33
+ }
34
+ ```
35
+
36
+ **Correct (Direct Import - Preferred):**
37
+ ```js
38
+ import { h } from 'vue'
39
+ import MyComponent from './MyComponent.vue'
40
+ import { RouterLink } from 'vue-router'
41
+
42
+ export default {
43
+ render() {
44
+ return h('div', [
45
+ h(MyComponent, { value: 1 }),
46
+ h(RouterLink, { to: '/' }, () => 'Home')
47
+ ])
48
+ }
49
+ }
50
+ ```
51
+
52
+ **Correct (resolveComponent for Registered Components):**
53
+ ```js
54
+ import { h, resolveComponent } from 'vue'
55
+
56
+ export default {
57
+ components: {
58
+ MyComponent: () => import('./MyComponent.vue')
59
+ },
60
+
61
+ setup() {
62
+ // Resolve inside setup - component context is available
63
+ const MyComponent = resolveComponent('MyComponent')
64
+
65
+ return () => h('div', [
66
+ h(MyComponent, { value: 1 })
67
+ ])
68
+ }
69
+ }
70
+
71
+ // Or resolve inside render function
72
+ export default {
73
+ render() {
74
+ const MyComponent = resolveComponent('MyComponent')
75
+ const RouterLink = resolveComponent('RouterLink')
76
+
77
+ return h('div', [
78
+ h(MyComponent, { value: 1 }),
79
+ h(RouterLink, { to: '/' }, () => 'Home')
80
+ ])
81
+ }
82
+ }
83
+ ```
84
+
85
+ ## When to Use Each Approach
86
+
87
+ | Approach | Use When |
88
+ |----------|----------|
89
+ | Direct Import | Component is known at build time (most common) |
90
+ | `resolveComponent()` | Component is registered globally or locally by name |
91
+ | `resolveComponent()` | Dynamic component selection from registered set |
92
+
93
+ ## Handling Missing Components
94
+
95
+ ```js
96
+ import { h, resolveComponent } from 'vue'
97
+
98
+ export default {
99
+ setup() {
100
+ // resolveComponent returns the component or the string name if not found
101
+ const DynamicComponent = resolveComponent('MaybeRegistered')
102
+
103
+ // Check if resolution succeeded
104
+ if (typeof DynamicComponent === 'string') {
105
+ console.warn(`Component "${DynamicComponent}" not found`)
106
+ }
107
+
108
+ return () => h(DynamicComponent, { value: 1 })
109
+ }
110
+ }
111
+ ```
112
+
113
+ ## Dynamic Component Selection
114
+
115
+ ```js
116
+ import { h, resolveComponent, computed } from 'vue'
117
+
118
+ export default {
119
+ props: ['componentName'],
120
+
121
+ setup(props) {
122
+ // For truly dynamic components, resolve in render function
123
+ return () => {
124
+ const Component = resolveComponent(props.componentName)
125
+ return h(Component, { /* props */ })
126
+ }
127
+ }
128
+ }
129
+ ```
130
+
131
+ For the equivalent of `<component :is="componentName">`, use `resolveDynamicComponent`:
132
+
133
+ ```js
134
+ import { h, resolveDynamicComponent } from 'vue'
135
+
136
+ export default {
137
+ props: ['componentType'],
138
+ setup(props) {
139
+ return () => {
140
+ // Resolves string names, component objects, or built-in elements
141
+ const component = resolveDynamicComponent(props.componentType)
142
+ return h(component, { /* props */ })
143
+ }
144
+ }
145
+ }
146
+ ```
147
+
148
+ ## Practical Example: Tab Component
149
+
150
+ ```js
151
+ import { h, resolveComponent, ref } from 'vue'
152
+
153
+ export default {
154
+ setup() {
155
+ const currentTab = ref('TabA')
156
+ const tabs = ['TabA', 'TabB', 'TabC']
157
+
158
+ return () => h('div', [
159
+ // Tab buttons
160
+ h('div', { class: 'tabs' },
161
+ tabs.map(tab =>
162
+ h('button', {
163
+ key: tab,
164
+ class: { active: currentTab.value === tab },
165
+ onClick: () => currentTab.value = tab
166
+ }, tab)
167
+ )
168
+ ),
169
+
170
+ // Dynamic component based on current tab
171
+ h(resolveComponent(currentTab.value))
172
+ ])
173
+ }
174
+ }
175
+ ```
176
+
177
+ ## Resolving Built-in Components
178
+
179
+ For built-in components like `<Transition>` or `<KeepAlive>`, import them directly from Vue:
180
+
181
+ ```js
182
+ import { h, Transition, KeepAlive, Teleport, Suspense } from 'vue'
183
+
184
+ export default {
185
+ setup() {
186
+ return () => h(Transition, { name: 'fade' }, () =>
187
+ h('div', 'Content')
188
+ )
189
+ }
190
+ }
191
+ ```
192
+
193
+ ## Resolving Directives
194
+
195
+ Similar pattern for custom directives:
196
+
197
+ ```js
198
+ import { h, resolveDirective, withDirectives } from 'vue'
199
+
200
+ export default {
201
+ render() {
202
+ const vFocus = resolveDirective('focus')
203
+
204
+ return withDirectives(
205
+ h('input', { type: 'text' }),
206
+ [[vFocus]]
207
+ )
208
+ }
209
+ }
210
+ ```
211
+
212
+ ## Migration from Vue 2
213
+
214
+ ```js
215
+ // Vue 2 (worked with registered components)
216
+ render(h) {
217
+ return h('my-component', { props: { value: 1 } })
218
+ }
219
+
220
+ // Vue 3 (must resolve or import)
221
+ import { h, resolveComponent } from 'vue'
222
+
223
+ render() {
224
+ const MyComponent = resolveComponent('my-component')
225
+ return h(MyComponent, { value: 1 }) // Note: props go directly, not in 'props' key
226
+ }
227
+ ```
228
+
229
+ ## Reference
230
+ - [Vue 3 Migration - Render Function API](https://v3-migration.vuejs.org/breaking-changes/render-function-api.html)
231
+ - [Vue.js Render Function API - resolveComponent](https://vuejs.org/api/render-function.html#resolvecomponent)