@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,146 @@
1
+ ---
2
+ title: Dynamic Directive Arguments Have Syntax Constraints
3
+ impact: MEDIUM
4
+ impactDescription: Invalid dynamic arguments cause silent failures or browser compatibility issues
5
+ type: capability
6
+ tags: [vue3, template, directives, v-bind, v-on, dynamic-arguments]
7
+ ---
8
+
9
+ # Dynamic Directive Arguments Have Syntax Constraints
10
+
11
+ **Impact: MEDIUM** - Dynamic directive arguments (e.g., `:[attributeName]`, `@[eventName]`) have value and syntax constraints that can cause silent failures. In-DOM templates also have case sensitivity issues with browsers lowercasing attribute names.
12
+
13
+ Dynamic arguments allow runtime determination of which attribute or event to bind, but they have restrictions that differ from static arguments.
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] Ensure dynamic arguments evaluate to strings or `null`
18
+ - [ ] Avoid spaces and quotes inside dynamic argument brackets
19
+ - [ ] Use computed properties for complex dynamic argument expressions
20
+ - [ ] In in-DOM templates, use lowercase attribute names or switch to SFCs
21
+ - [ ] Use `null` to explicitly remove a binding
22
+
23
+ **Incorrect:**
24
+ ```vue
25
+ <template>
26
+ <!-- ERROR: Spaces and quotes not allowed in dynamic arguments -->
27
+ <a :[' foo' + bar]="value">Link</a>
28
+ <a :["data-" + name]="value">Link</a>
29
+
30
+ <!-- WARNING: Non-string values (except null) trigger warnings -->
31
+ <a :[123]="value">Link</a>
32
+ <a :[someObject]="value">Link</a>
33
+
34
+ <!-- BUG in in-DOM templates: Browsers lowercase attribute names -->
35
+ <!-- This becomes :[someattr] which won't match someAttr -->
36
+ <a :[someAttr]="url">Link</a>
37
+ </template>
38
+
39
+ <script setup>
40
+ // If component expects someAttr but browser lowercases to someattr
41
+ // the binding silently fails
42
+ const someAttr = 'href'
43
+ </script>
44
+ ```
45
+
46
+ **Correct:**
47
+ ```vue
48
+ <template>
49
+ <!-- OK: Simple variable reference -->
50
+ <a :[attributeName]="url">Link</a>
51
+
52
+ <!-- OK: Use computed property for complex expressions -->
53
+ <a :[dynamicAttr]="value">Link</a>
54
+
55
+ <!-- OK: null removes the binding -->
56
+ <button :[disabledAttr]="isDisabled">Submit</button>
57
+
58
+ <!-- OK: Dynamic event names -->
59
+ <button @[eventName]="handler">Click</button>
60
+
61
+ <!-- OK: In SFCs, case is preserved -->
62
+ <a :[someAttr]="url">Link</a>
63
+ </template>
64
+
65
+ <script setup>
66
+ import { ref, computed } from 'vue'
67
+
68
+ // Simple string variable
69
+ const attributeName = ref('href')
70
+ const url = ref('https://vuejs.org')
71
+
72
+ // Complex expression via computed property
73
+ const prefix = ref('data')
74
+ const name = ref('id')
75
+ const dynamicAttr = computed(() => `${prefix.value}-${name.value}`)
76
+
77
+ // Conditional binding with null
78
+ const isDisabled = ref(false)
79
+ const disabledAttr = computed(() => isDisabled.value ? 'disabled' : null)
80
+
81
+ // Dynamic events
82
+ const useTouch = ref(false)
83
+ const eventName = computed(() => useTouch.value ? 'touchstart' : 'click')
84
+
85
+ function handler() {
86
+ console.log('Event triggered')
87
+ }
88
+ </script>
89
+ ```
90
+
91
+ ## In-DOM Template Workaround
92
+
93
+ When writing templates directly in HTML (not SFCs), use lowercase:
94
+
95
+ ```html
96
+ <!-- In-DOM template (index.html) -->
97
+ <div id="app">
98
+ <!-- Use lowercase to avoid browser issues -->
99
+ <a :[attrname]="url">Link</a>
100
+ </div>
101
+
102
+ <script type="module">
103
+ import { createApp, ref } from 'vue'
104
+
105
+ createApp({
106
+ setup() {
107
+ // Match the lowercase used in template
108
+ const attrname = ref('href')
109
+ const url = ref('https://vuejs.org')
110
+ return { attrname, url }
111
+ }
112
+ }).mount('#app')
113
+ </script>
114
+ ```
115
+
116
+ ## SFC vs In-DOM Templates
117
+
118
+ | Feature | SFC (.vue files) | In-DOM (HTML) |
119
+ |---------|------------------|---------------|
120
+ | Case sensitivity | Preserved | Lowercased by browser |
121
+ | Dynamic arguments | Full support | Lowercase only |
122
+ | Recommendation | Preferred | Use for progressive enhancement |
123
+
124
+ ## Valid Dynamic Argument Values
125
+
126
+ ```vue
127
+ <script setup>
128
+ // String values - OK
129
+ const attr1 = 'href'
130
+ const attr2 = 'data-custom'
131
+
132
+ // null - OK (removes binding)
133
+ const attr3 = null
134
+
135
+ // undefined - OK (removes binding)
136
+ const attr4 = undefined
137
+
138
+ // Numbers, objects, arrays - WARNING
139
+ const attr5 = 123 // Warning: should be string
140
+ const attr6 = { foo: 1 } // Warning: should be string
141
+ </script>
142
+ ```
143
+
144
+ ## Reference
145
+ - [Vue.js Template Syntax - Dynamic Arguments](https://vuejs.org/guide/essentials/template-syntax.html#dynamic-arguments)
146
+ - [Vue.js Template Syntax - Dynamic Argument Value Constraints](https://vuejs.org/guide/essentials/template-syntax.html#dynamic-argument-value-constraints)
@@ -0,0 +1,147 @@
1
+ ---
2
+ title: Use import.meta.glob for Dynamic Component Registration in Vite
3
+ impact: MEDIUM
4
+ impactDescription: require.context from Webpack doesn't work in Vite projects
5
+ type: gotcha
6
+ tags: [vue3, component-registration, vite, dynamic-import, migration, webpack]
7
+ ---
8
+
9
+ # Use import.meta.glob for Dynamic Component Registration in Vite
10
+
11
+ **Impact: MEDIUM** - When migrating from Webpack to Vite or starting a new Vite project, the `require.context` pattern for dynamically registering components won't work. Vite uses `import.meta.glob` instead. Using the wrong approach will cause build errors or runtime failures.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Replace `require.context` with `import.meta.glob` in Vite projects
16
+ - [ ] Update component registration patterns when migrating from Vue CLI to Vite
17
+ - [ ] Use `{ eager: true }` for synchronous loading when needed
18
+ - [ ] Handle async components appropriately with `defineAsyncComponent`
19
+
20
+ **Incorrect (Webpack pattern - doesn't work in Vite):**
21
+ ```javascript
22
+ // main.js - WRONG for Vite
23
+ import { createApp } from 'vue'
24
+ import App from './App.vue'
25
+
26
+ const app = createApp(App)
27
+
28
+ // This Webpack-specific API doesn't exist in Vite
29
+ const requireComponent = require.context(
30
+ './components/base',
31
+ false,
32
+ /Base[A-Z]\w+\.vue$/
33
+ )
34
+
35
+ requireComponent.keys().forEach(fileName => {
36
+ const componentConfig = requireComponent(fileName)
37
+ const componentName = fileName
38
+ .split('/')
39
+ .pop()
40
+ .replace(/\.\w+$/, '')
41
+
42
+ app.component(componentName, componentConfig.default || componentConfig)
43
+ })
44
+
45
+ app.mount('#app')
46
+ ```
47
+
48
+ **Correct (Vite pattern):**
49
+ ```javascript
50
+ // main.js - Correct for Vite
51
+ import { createApp } from 'vue'
52
+ import App from './App.vue'
53
+
54
+ const app = createApp(App)
55
+
56
+ // Vite's glob import - eager loading for synchronous registration
57
+ const modules = import.meta.glob('./components/base/Base*.vue', { eager: true })
58
+
59
+ for (const path in modules) {
60
+ // Extract component name from path: './components/base/BaseButton.vue' -> 'BaseButton'
61
+ const componentName = path.split('/').pop().replace('.vue', '')
62
+ app.component(componentName, modules[path].default)
63
+ }
64
+
65
+ app.mount('#app')
66
+ ```
67
+
68
+ ## Lazy Loading with Async Components
69
+
70
+ ```javascript
71
+ // main.js - Lazy loading variant
72
+ import { createApp, defineAsyncComponent } from 'vue'
73
+ import App from './App.vue'
74
+
75
+ const app = createApp(App)
76
+
77
+ // Without { eager: true }, returns functions that return Promises
78
+ const modules = import.meta.glob('./components/base/Base*.vue')
79
+
80
+ for (const path in modules) {
81
+ const componentName = path.split('/').pop().replace('.vue', '')
82
+ // Wrap in defineAsyncComponent for lazy loading
83
+ app.component(componentName, defineAsyncComponent(modules[path]))
84
+ }
85
+
86
+ app.mount('#app')
87
+ ```
88
+
89
+ ## Glob Pattern Examples
90
+
91
+ ```javascript
92
+ // All .vue files in a directory (not recursive)
93
+ import.meta.glob('./components/*.vue', { eager: true })
94
+
95
+ // All .vue files recursively
96
+ import.meta.glob('./components/**/*.vue', { eager: true })
97
+
98
+ // Specific naming pattern
99
+ import.meta.glob('./components/Base*.vue', { eager: true })
100
+
101
+ // Multiple patterns
102
+ import.meta.glob([
103
+ './components/Base*.vue',
104
+ './components/App*.vue'
105
+ ], { eager: true })
106
+
107
+ // Exclude patterns
108
+ import.meta.glob('./components/**/*.vue', {
109
+ eager: true,
110
+ ignore: ['**/*.test.vue', '**/*.spec.vue']
111
+ })
112
+ ```
113
+
114
+ ## TypeScript Support
115
+
116
+ ```typescript
117
+ // main.ts - with proper typing
118
+ import { createApp, Component } from 'vue'
119
+ import App from './App.vue'
120
+
121
+ const app = createApp(App)
122
+
123
+ const modules = import.meta.glob<{ default: Component }>(
124
+ './components/base/Base*.vue',
125
+ { eager: true }
126
+ )
127
+
128
+ for (const path in modules) {
129
+ const componentName = path.split('/').pop()!.replace('.vue', '')
130
+ app.component(componentName, modules[path].default)
131
+ }
132
+
133
+ app.mount('#app')
134
+ ```
135
+
136
+ ## Migration Checklist (Webpack to Vite)
137
+
138
+ | Webpack | Vite |
139
+ |---------|------|
140
+ | `require.context(dir, recursive, regex)` | `import.meta.glob(pattern, options)` |
141
+ | Synchronous by default | Use `{ eager: true }` for sync |
142
+ | `.keys()` returns array | Returns object with paths as keys |
143
+ | Returns module directly | Access via `.default` for ES modules |
144
+
145
+ ## Reference
146
+ - [Vite - Glob Import](https://vitejs.dev/guide/features.html#glob-import)
147
+ - [Vue.js Component Registration](https://vuejs.org/guide/components/registration.html)
@@ -0,0 +1,101 @@
1
+ ---
2
+ title: Event Modifier Order Matters
3
+ impact: MEDIUM
4
+ impactDescription: Modifier order affects event handling behavior - wrong order causes unexpected propagation or prevention
5
+ type: gotcha
6
+ tags: [vue3, events, modifiers, v-on, click, form]
7
+ ---
8
+
9
+ # Event Modifier Order Matters
10
+
11
+ **Impact: MEDIUM** - When chaining event modifiers, the order determines behavior because Vue generates code in the same sequence. Using `.prevent.self` vs `.self.prevent` produces different results that can cause subtle bugs in event handling.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Always consider modifier order when chaining multiple modifiers
16
+ - [ ] Use `.prevent.self` to prevent default on element AND children
17
+ - [ ] Use `.self.prevent` to prevent default ONLY on the element itself
18
+ - [ ] Test event behavior on both the element and its children
19
+
20
+ **Incorrect:**
21
+ ```html
22
+ <!-- WRONG: Unintended behavior - prevents clicks on children too -->
23
+ <template>
24
+ <div @click.prevent.self="handleClick">
25
+ <button>Child Button</button> <!-- Default also prevented here! -->
26
+ </div>
27
+ </template>
28
+ ```
29
+
30
+ ```html
31
+ <!-- WRONG: Assuming order doesn't matter -->
32
+ <template>
33
+ <!-- Developer expects only self clicks to be handled -->
34
+ <!-- But .prevent runs first, affecting all clicks -->
35
+ <a href="/page" @click.prevent.self="navigate">
36
+ <span>Click me</span>
37
+ </a>
38
+ </template>
39
+ ```
40
+
41
+ **Correct:**
42
+ ```html
43
+ <!-- CORRECT: Only prevent default on the element itself -->
44
+ <template>
45
+ <div @click.self.prevent="handleClick">
46
+ <button>Child Button</button> <!-- Default NOT prevented here -->
47
+ </div>
48
+ </template>
49
+ ```
50
+
51
+ ```html
52
+ <!-- CORRECT: Prevent default on element and children -->
53
+ <template>
54
+ <form @submit.prevent.self="onSubmit">
55
+ <button type="submit">Submit</button>
56
+ </form>
57
+ </template>
58
+ ```
59
+
60
+ ```html
61
+ <!-- CORRECT: Explicit intent with separate handlers when needed -->
62
+ <template>
63
+ <div @click.self="handleSelfClick">
64
+ <button @click.prevent="handleChildClick">
65
+ Child with prevented default
66
+ </button>
67
+ </div>
68
+ </template>
69
+ ```
70
+
71
+ ## How Modifier Order Works
72
+
73
+ ```javascript
74
+ // Vue compiles modifiers in order, so:
75
+
76
+ // @click.prevent.self compiles to:
77
+ // event.preventDefault()
78
+ // if (event.target !== event.currentTarget) return
79
+ // handler()
80
+
81
+ // @click.self.prevent compiles to:
82
+ // if (event.target !== event.currentTarget) return
83
+ // event.preventDefault()
84
+ // handler()
85
+ ```
86
+
87
+ ## Common Modifier Combinations
88
+
89
+ ```html
90
+ <!-- Stop propagation AND prevent default -->
91
+ <a @click.stop.prevent="handleClick">Link</a>
92
+
93
+ <!-- Capture mode with once -->
94
+ <div @click.capture.once="handleOnce">...</div>
95
+
96
+ <!-- Only exact modifier key combination -->
97
+ <button @click.ctrl.exact="onCtrlClick">Ctrl+Click Only</button>
98
+ ```
99
+
100
+ ## Reference
101
+ - [Vue.js Event Handling - Event Modifiers](https://vuejs.org/guide/essentials/event-handling.html#event-modifiers)
@@ -0,0 +1,155 @@
1
+ ---
2
+ title: Use .exact Modifier for Precise Keyboard/Mouse Shortcuts
3
+ impact: MEDIUM
4
+ impactDescription: Without .exact, shortcuts fire even when additional modifier keys are pressed, causing unintended behavior
5
+ type: best-practice
6
+ tags: [vue3, events, keyboard, modifiers, shortcuts, accessibility]
7
+ ---
8
+
9
+ # Use .exact Modifier for Precise Keyboard/Mouse Shortcuts
10
+
11
+ **Impact: MEDIUM** - By default, Vue's modifier key handlers (`.ctrl`, `.alt`, `.shift`, `.meta`) fire even when other modifier keys are also pressed. Use `.exact` to require that ONLY the specified modifiers are pressed, preventing accidental triggering of shortcuts.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Use `.exact` when you need precise modifier combinations
16
+ - [ ] Without `.exact`: `@click.ctrl` fires for Ctrl+Click AND Ctrl+Shift+Click
17
+ - [ ] With `.exact`: `@click.ctrl.exact` fires ONLY for Ctrl+Click
18
+ - [ ] Use `@click.exact` for plain clicks with no modifiers
19
+
20
+ **Incorrect:**
21
+ ```html
22
+ <!-- WRONG: Fires even with additional modifiers -->
23
+ <template>
24
+ <button @click.ctrl="copyItem">Copy</button>
25
+ <!-- Also fires on Ctrl+Shift+Click, Ctrl+Alt+Click, etc. -->
26
+
27
+ <button @click.ctrl.shift="copyAll">Copy All</button>
28
+ <!-- User expects Ctrl+Shift, but also fires on Ctrl+Shift+Alt -->
29
+ </template>
30
+ ```
31
+
32
+ ```html
33
+ <!-- WRONG: Conflicting shortcuts without .exact -->
34
+ <template>
35
+ <div>
36
+ <button @click.ctrl="copy">Copy (Ctrl+Click)</button>
37
+ <button @click.ctrl.shift="copyAll">Copy All (Ctrl+Shift+Click)</button>
38
+ <!-- Both fire when user does Ctrl+Shift+Click! -->
39
+ </div>
40
+ </template>
41
+ ```
42
+
43
+ **Correct:**
44
+ ```html
45
+ <!-- CORRECT: Precise modifier matching with .exact -->
46
+ <template>
47
+ <button @click.ctrl.exact="copyItem">Copy (Ctrl only)</button>
48
+ <!-- Only fires on Ctrl+Click, not Ctrl+Shift+Click -->
49
+
50
+ <button @click.ctrl.shift.exact="copyAll">Copy All (Ctrl+Shift only)</button>
51
+ <!-- Only fires on Ctrl+Shift+Click, not Ctrl+Shift+Alt+Click -->
52
+ </template>
53
+ ```
54
+
55
+ ```html
56
+ <!-- CORRECT: Plain click without any modifiers -->
57
+ <template>
58
+ <button @click.exact="selectItem">Select</button>
59
+ <!-- Only fires when NO modifier keys are pressed -->
60
+ <!-- Ctrl+Click, Shift+Click, etc. will NOT trigger this -->
61
+ </template>
62
+ ```
63
+
64
+ ```html
65
+ <!-- CORRECT: Non-conflicting shortcuts -->
66
+ <template>
67
+ <div class="editor">
68
+ <div
69
+ @click.exact="selectItem"
70
+ @click.ctrl.exact="addToSelection"
71
+ @click.shift.exact="extendSelection"
72
+ @click.ctrl.shift.exact="selectRange"
73
+ >
74
+ Click, Ctrl+Click, Shift+Click, or Ctrl+Shift+Click
75
+ </div>
76
+ </div>
77
+ </template>
78
+ ```
79
+
80
+ ## Behavior Comparison
81
+
82
+ ```javascript
83
+ // WITHOUT .exact
84
+ @click.ctrl="handler"
85
+ // Fires when: Ctrl+Click, Ctrl+Shift+Click, Ctrl+Alt+Click, Ctrl+Shift+Alt+Click
86
+ // Does NOT fire: Click (without Ctrl)
87
+
88
+ // WITH .exact
89
+ @click.ctrl.exact="handler"
90
+ // Fires when: ONLY Ctrl+Click
91
+ // Does NOT fire: Ctrl+Shift+Click, Ctrl+Alt+Click, Click
92
+
93
+ // ONLY .exact (no other modifiers)
94
+ @click.exact="handler"
95
+ // Fires when: Plain click with NO modifiers
96
+ // Does NOT fire: Ctrl+Click, Shift+Click, Alt+Click
97
+ ```
98
+
99
+ ## Practical Example: File Browser Selection
100
+
101
+ ```vue
102
+ <template>
103
+ <ul class="file-list">
104
+ <li
105
+ v-for="file in files"
106
+ :key="file.id"
107
+ @click.exact="selectSingle(file)"
108
+ @click.ctrl.exact="toggleSelection(file)"
109
+ @click.shift.exact="selectRange(file)"
110
+ @click.ctrl.shift.exact="addRangeToSelection(file)"
111
+ :class="{ selected: isSelected(file) }"
112
+ >
113
+ {{ file.name }}
114
+ </li>
115
+ </ul>
116
+ </template>
117
+
118
+ <script setup>
119
+ // Each click type has distinct, non-overlapping behavior
120
+ function selectSingle(file) {
121
+ // Clear selection and select only this file
122
+ }
123
+
124
+ function toggleSelection(file) {
125
+ // Add or remove this file from current selection
126
+ }
127
+
128
+ function selectRange(file) {
129
+ // Select all files from last selected to this one
130
+ }
131
+
132
+ function addRangeToSelection(file) {
133
+ // Add range to existing selection
134
+ }
135
+ </script>
136
+ ```
137
+
138
+ ## Keyboard Shortcuts with .exact
139
+
140
+ ```html
141
+ <template>
142
+ <div
143
+ tabindex="0"
144
+ @keydown.ctrl.s.exact.prevent="save"
145
+ @keydown.ctrl.shift.s.exact.prevent="saveAs"
146
+ @keydown.ctrl.z.exact.prevent="undo"
147
+ @keydown.ctrl.shift.z.exact.prevent="redo"
148
+ >
149
+ <!-- Each shortcut is precisely defined -->
150
+ </div>
151
+ </template>
152
+ ```
153
+
154
+ ## Reference
155
+ - [Vue.js Event Handling - .exact Modifier](https://vuejs.org/guide/essentials/event-handling.html#exact-modifier)
@@ -0,0 +1,159 @@
1
+ # Fallthrough Attributes Overwrite Explicit Attributes in Vue 3
2
+
3
+ ## Rule
4
+
5
+ In Vue 3, fallthrough attributes overwrite explicitly set attributes on the root element (except `class` and `style` which are merged). This is a breaking change from Vue 2. To preserve explicit attribute values, use `inheritAttrs: false` and manually bind `$attrs` before the explicit attribute.
6
+
7
+ ## Why This Matters
8
+
9
+ - Silent behavior change from Vue 2 to Vue 3
10
+ - Can cause unexpected attribute values in migrated codebases
11
+ - Only `class` and `style` merge intelligently; other attributes are overwritten
12
+ - Affects component composition patterns and wrapper components
13
+
14
+ ## Bad Code
15
+
16
+ ```vue
17
+ <!-- Parent.vue -->
18
+ <template>
19
+ <Child msg="Passed from Parent" />
20
+ </template>
21
+
22
+ <!-- Child.vue - UNEXPECTED BEHAVIOR -->
23
+ <template>
24
+ <GrandChild msg="Set in Child" />
25
+ </template>
26
+
27
+ <!--
28
+ Vue 3 Result: GrandChild receives msg="Passed from Parent"
29
+ The fallthrough attribute OVERWRITES the explicit one!
30
+
31
+ Vue 2 Result: GrandChild receives msg="Set in Child"
32
+ The explicit attribute took precedence
33
+ -->
34
+ ```
35
+
36
+ ### Another common case with data attributes
37
+
38
+ ```vue
39
+ <!-- Parent.vue -->
40
+ <template>
41
+ <Button data-testid="parent-button" />
42
+ </template>
43
+
44
+ <!-- Button.vue - WRONG: explicit data-testid is overwritten -->
45
+ <template>
46
+ <button data-testid="submit-btn">Submit</button>
47
+ </template>
48
+
49
+ <!-- Result: <button data-testid="parent-button">Submit</button> -->
50
+ <!-- The component's intended test ID is lost! -->
51
+ ```
52
+
53
+ ## Good Code
54
+
55
+ ### Option 1: Control attribute order with inheritAttrs: false
56
+
57
+ ```vue
58
+ <!-- Child.vue - CORRECT: Control attribute precedence -->
59
+ <script setup>
60
+ defineOptions({
61
+ inheritAttrs: false
62
+ })
63
+ </script>
64
+
65
+ <template>
66
+ <!-- v-bind="$attrs" FIRST, then explicit attribute -->
67
+ <GrandChild v-bind="$attrs" msg="Set in Child" />
68
+ </template>
69
+
70
+ <!--
71
+ Result: GrandChild receives msg="Set in Child"
72
+ Explicit attribute overrides fallthrough because it comes last
73
+ -->
74
+ ```
75
+
76
+ ### Option 2: Exclude specific attrs from fallthrough
77
+
78
+ ```vue
79
+ <script setup>
80
+ import { computed, useAttrs } from 'vue'
81
+
82
+ defineOptions({
83
+ inheritAttrs: false
84
+ })
85
+
86
+ const attrs = useAttrs()
87
+
88
+ // Filter out attributes you want to control explicitly
89
+ const filteredAttrs = computed(() => {
90
+ const { msg, ...rest } = attrs
91
+ return rest
92
+ })
93
+ </script>
94
+
95
+ <template>
96
+ <GrandChild v-bind="filteredAttrs" msg="Set in Child" />
97
+ </template>
98
+ ```
99
+
100
+ ### Option 3: For wrapper components, declare as prop
101
+
102
+ ```vue
103
+ <!-- Button.vue - BEST: Declare attributes you need to control -->
104
+ <script setup>
105
+ const props = defineProps({
106
+ dataTestid: {
107
+ type: String,
108
+ default: 'submit-btn'
109
+ }
110
+ })
111
+
112
+ defineOptions({
113
+ inheritAttrs: false
114
+ })
115
+ </script>
116
+
117
+ <template>
118
+ <button :data-testid="dataTestid" v-bind="$attrs">
119
+ <slot />
120
+ </button>
121
+ </template>
122
+ ```
123
+
124
+ ## Class and Style Are Special
125
+
126
+ Unlike other attributes, `class` and `style` merge rather than overwrite:
127
+
128
+ ```vue
129
+ <!-- Parent.vue -->
130
+ <template>
131
+ <Button class="large" style="color: red" />
132
+ </template>
133
+
134
+ <!-- Button.vue -->
135
+ <template>
136
+ <button class="btn" style="padding: 10px">Submit</button>
137
+ </template>
138
+
139
+ <!--
140
+ Result: <button class="btn large" style="padding: 10px; color: red">
141
+ Both classes and styles are MERGED, not overwritten
142
+ -->
143
+ ```
144
+
145
+ ## Vue 2 to Vue 3 Migration Checklist
146
+
147
+ When migrating components that rely on attribute precedence:
148
+
149
+ 1. Identify components that set explicit attributes on root elements
150
+ 2. Check if parent components pass the same attributes
151
+ 3. If explicit values should take precedence:
152
+ - Add `inheritAttrs: false`
153
+ - Use `v-bind="$attrs"` before explicit attributes
154
+
155
+ ## References
156
+
157
+ - [Fallthrough Attributes](https://vuejs.org/guide/components/attrs.html)
158
+ - [Vue 3 Migration Guide - Attribute Coercion Behavior](https://v3-migration.vuejs.org/breaking-changes/)
159
+ - [Vue Fallthrough Attributes behaviour changes from Vue 2 to Vue 3](https://lukes.tips/posts/vue-3-fallthough-attributes-changes/)