@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,149 @@
1
+ ---
2
+ title: In-DOM Template Parsing Caveats
3
+ impact: HIGH
4
+ impactDescription: Browser HTML parsing before Vue compilation causes case sensitivity, self-closing tag, and element nesting issues
5
+ type: gotcha
6
+ tags: [vue3, templates, in-dom, html-parsing, kebab-case, self-closing-tags]
7
+ ---
8
+
9
+ # In-DOM Template Parsing Caveats
10
+
11
+ **Impact: HIGH** - When writing Vue templates directly in the DOM (not in `.vue` files), the browser's native HTML parser processes the template BEFORE Vue sees it. This causes three critical issues: case sensitivity problems, self-closing tag failures, and element placement restrictions.
12
+
13
+ These issues do NOT apply to Single-File Components (SFCs) or string templates where Vue's compiler handles parsing directly.
14
+
15
+ ## Task Checklist
16
+
17
+ - [ ] Use kebab-case for component names in in-DOM templates
18
+ - [ ] Use kebab-case for prop names in in-DOM templates
19
+ - [ ] Use explicit closing tags (not self-closing) in in-DOM templates
20
+ - [ ] Use `is="vue:component-name"` for components inside restricted elements
21
+ - [ ] Prefer SFCs to avoid all in-DOM parsing issues
22
+
23
+ ## Issue 1: Case Insensitivity
24
+
25
+ HTML is case-insensitive. The browser lowercases everything before Vue sees it.
26
+
27
+ **Incorrect (in-DOM template):**
28
+ ```html
29
+ <!-- Browser converts to: <blogpost posttitle="hello"> -->
30
+ <BlogPost postTitle="hello" @updatePost="onUpdate"></BlogPost>
31
+ ```
32
+
33
+ **Correct (in-DOM template):**
34
+ ```html
35
+ <!-- Use kebab-case for everything -->
36
+ <blog-post post-title="hello" @update-post="onUpdate"></blog-post>
37
+ ```
38
+
39
+ **In SFCs, PascalCase works fine:**
40
+ ```vue
41
+ <!-- BlogPost.vue - PascalCase recommended -->
42
+ <template>
43
+ <BlogPost postTitle="hello" @updatePost="onUpdate" />
44
+ </template>
45
+ ```
46
+
47
+ ## Issue 2: Self-Closing Tags Fail
48
+
49
+ HTML only allows self-closing syntax for void elements (`<input>`, `<img>`, etc.). For all others, the browser expects closing tags.
50
+
51
+ **Incorrect (in-DOM template):**
52
+ ```html
53
+ <!-- Browser thinks the tag never closed, breaks nesting -->
54
+ <my-component />
55
+ <another-component />
56
+ ```
57
+
58
+ **Correct (in-DOM template):**
59
+ ```html
60
+ <!-- Explicit closing tags required -->
61
+ <my-component></my-component>
62
+ <another-component></another-component>
63
+ ```
64
+
65
+ **In SFCs, self-closing works fine:**
66
+ ```vue
67
+ <template>
68
+ <MyComponent />
69
+ <AnotherComponent />
70
+ </template>
71
+ ```
72
+
73
+ ## Issue 3: Element Placement Restrictions
74
+
75
+ Some HTML elements have strict rules about valid children. Invalid elements are hoisted out by the browser before Vue sees the template.
76
+
77
+ **Restricted parent elements:**
78
+ - `<ul>`, `<ol>` - only allow `<li>`
79
+ - `<table>` - only allows `<thead>`, `<tbody>`, `<tfoot>`, `<tr>`, `<caption>`, `<colgroup>`
80
+ - `<tr>` - only allows `<td>`, `<th>`
81
+ - `<select>` - only allows `<option>`, `<optgroup>`
82
+
83
+ **Incorrect (in-DOM template):**
84
+ ```html
85
+ <!-- Browser hoists blog-post-row outside the table -->
86
+ <table>
87
+ <blog-post-row v-for="post in posts" :post="post"></blog-post-row>
88
+ </table>
89
+
90
+ <!-- Renders as: -->
91
+ <blog-post-row></blog-post-row>
92
+ <blog-post-row></blog-post-row>
93
+ <table></table>
94
+ ```
95
+
96
+ **Correct (in-DOM template):**
97
+ ```html
98
+ <!-- Use is="vue:component-name" on a valid native element -->
99
+ <table>
100
+ <tr is="vue:blog-post-row" v-for="post in posts" :key="post.id" :post="post"></tr>
101
+ </table>
102
+ ```
103
+
104
+ ```html
105
+ <ul>
106
+ <li is="vue:todo-item" v-for="todo in todos" :key="todo.id" :todo="todo"></li>
107
+ </ul>
108
+ ```
109
+
110
+ **Important:** The `vue:` prefix is required! Without it, `is` is treated as a native customized built-in element attribute.
111
+
112
+ ```html
113
+ <!-- WRONG: Missing vue: prefix -->
114
+ <tr is="blog-post-row"></tr>
115
+
116
+ <!-- CORRECT: With vue: prefix -->
117
+ <tr is="vue:blog-post-row"></tr>
118
+ ```
119
+
120
+ ## When Do These Apply?
121
+
122
+ | Template Type | Affected? | Example |
123
+ |---------------|-----------|---------|
124
+ | Single-File Component (`.vue`) | No | `<template>` section |
125
+ | String template | No | `template: '<div>...</div>'` |
126
+ | In-DOM template | **Yes** | `<div id="app">...</div>` |
127
+ | `<script type="text/x-template">` | **Yes** | Browser parses the script content |
128
+
129
+ ## Best Practice: Use SFCs
130
+
131
+ The simplest solution is to use Single-File Components (`.vue` files) which completely avoid in-DOM parsing issues:
132
+
133
+ ```vue
134
+ <!-- MyComponent.vue - All issues avoided -->
135
+ <script setup>
136
+ import BlogPost from './BlogPost.vue'
137
+ </script>
138
+
139
+ <template>
140
+ <BlogPost postTitle="hello" @updatePost="onUpdate" />
141
+
142
+ <table>
143
+ <BlogPostRow v-for="post in posts" :key="post.id" :post="post" />
144
+ </table>
145
+ </template>
146
+ ```
147
+
148
+ ## Reference
149
+ - [Vue.js - In-DOM Template Parsing Caveats](https://vuejs.org/guide/essentials/component-basics.html#in-dom-template-parsing-caveats)
@@ -0,0 +1,230 @@
1
+ # Use inheritAttrs: false for Wrapper Components
2
+
3
+ ## Rule
4
+
5
+ When building wrapper components where attributes should be applied to an inner element instead of the root element, always set `inheritAttrs: false` and explicitly bind `$attrs` to the target element.
6
+
7
+ ## Why This Matters
8
+
9
+ - By default, Vue applies all non-prop attributes to the root element
10
+ - Wrapper components often have a non-semantic root (div wrapper, label wrapper)
11
+ - Attributes like `id`, `aria-*`, `data-*`, and event listeners should target the functional element
12
+ - Without `inheritAttrs: false`, accessibility and functionality can break
13
+
14
+ ## Bad Code
15
+
16
+ ```vue
17
+ <!-- BaseInput.vue - WRONG: attrs go to wrapper div, not input -->
18
+ <template>
19
+ <div class="input-wrapper">
20
+ <label>{{ label }}</label>
21
+ <input type="text" />
22
+ </div>
23
+ </template>
24
+
25
+ <script setup>
26
+ defineProps(['label'])
27
+ </script>
28
+
29
+ <!-- Parent usage -->
30
+ <BaseInput
31
+ id="email"
32
+ placeholder="Enter email"
33
+ aria-describedby="email-help"
34
+ @focus="handleFocus"
35
+ />
36
+
37
+ <!--
38
+ RESULT: All attrs go to the wrapper div!
39
+ <div class="input-wrapper" id="email" placeholder="Enter email" ...>
40
+ <label>...</label>
41
+ <input type="text" /> <!-- No id, placeholder, or aria! -->
42
+ </div>
43
+ -->
44
+ ```
45
+
46
+ ## Good Code
47
+
48
+ ```vue
49
+ <!-- BaseInput.vue - CORRECT: attrs bound to input element -->
50
+ <script setup>
51
+ defineProps(['label'])
52
+
53
+ defineOptions({
54
+ inheritAttrs: false
55
+ })
56
+ </script>
57
+
58
+ <template>
59
+ <div class="input-wrapper">
60
+ <label>{{ label }}</label>
61
+ <input type="text" v-bind="$attrs" />
62
+ </div>
63
+ </template>
64
+
65
+ <!-- Parent usage -->
66
+ <BaseInput
67
+ id="email"
68
+ placeholder="Enter email"
69
+ aria-describedby="email-help"
70
+ @focus="handleFocus"
71
+ />
72
+
73
+ <!--
74
+ RESULT: Attrs correctly applied to input
75
+ <div class="input-wrapper">
76
+ <label>...</label>
77
+ <input type="text" id="email" placeholder="Enter email"
78
+ aria-describedby="email-help" />
79
+ </div>
80
+ -->
81
+ ```
82
+
83
+ ## Setting inheritAttrs in Different Syntaxes
84
+
85
+ ### Script Setup (Vue 3.3+)
86
+
87
+ ```vue
88
+ <script setup>
89
+ defineOptions({
90
+ inheritAttrs: false
91
+ })
92
+ </script>
93
+ ```
94
+
95
+ ### Script Setup (Before Vue 3.3)
96
+
97
+ ```vue
98
+ <script>
99
+ export default {
100
+ inheritAttrs: false
101
+ }
102
+ </script>
103
+
104
+ <script setup>
105
+ // Your setup code here
106
+ </script>
107
+ ```
108
+
109
+ ### Options API
110
+
111
+ ```vue
112
+ <script>
113
+ export default {
114
+ inheritAttrs: false,
115
+ // other options...
116
+ }
117
+ </script>
118
+ ```
119
+
120
+ ## Common Wrapper Component Patterns
121
+
122
+ ### Form Input Wrapper
123
+
124
+ ```vue
125
+ <script setup>
126
+ import { useAttrs, computed } from 'vue'
127
+
128
+ defineProps({
129
+ label: String,
130
+ error: String
131
+ })
132
+
133
+ defineOptions({
134
+ inheritAttrs: false
135
+ })
136
+
137
+ const attrs = useAttrs()
138
+
139
+ // Separate class/style for wrapper vs input
140
+ const inputAttrs = computed(() => {
141
+ const { class: _, style: __, ...rest } = attrs
142
+ return rest
143
+ })
144
+ </script>
145
+
146
+ <template>
147
+ <div class="form-field" :class="{ 'has-error': error }">
148
+ <label v-if="label">{{ label }}</label>
149
+ <input v-bind="inputAttrs" />
150
+ <span v-if="error" class="error">{{ error }}</span>
151
+ </div>
152
+ </template>
153
+ ```
154
+
155
+ ### Button with Icon Wrapper
156
+
157
+ ```vue
158
+ <script setup>
159
+ defineProps({
160
+ icon: String,
161
+ iconPosition: {
162
+ type: String,
163
+ default: 'left'
164
+ }
165
+ })
166
+
167
+ defineOptions({
168
+ inheritAttrs: false
169
+ })
170
+ </script>
171
+
172
+ <template>
173
+ <button class="icon-button" v-bind="$attrs">
174
+ <span v-if="icon && iconPosition === 'left'" class="icon">{{ icon }}</span>
175
+ <slot />
176
+ <span v-if="icon && iconPosition === 'right'" class="icon">{{ icon }}</span>
177
+ </button>
178
+ </template>
179
+ ```
180
+
181
+ ### Link Wrapper Component
182
+
183
+ ```vue
184
+ <script setup>
185
+ defineProps({
186
+ to: String,
187
+ external: Boolean
188
+ })
189
+
190
+ defineOptions({
191
+ inheritAttrs: false
192
+ })
193
+ </script>
194
+
195
+ <template>
196
+ <a
197
+ v-if="external"
198
+ :href="to"
199
+ target="_blank"
200
+ rel="noopener noreferrer"
201
+ v-bind="$attrs"
202
+ >
203
+ <slot />
204
+ </a>
205
+ <router-link v-else :to="to" v-bind="$attrs">
206
+ <slot />
207
+ </router-link>
208
+ </template>
209
+ ```
210
+
211
+ ## When NOT to Use inheritAttrs: false
212
+
213
+ - Simple components with a single semantic root element
214
+ - Components where the root element should receive all attributes
215
+ - Components that don't wrap other functional elements
216
+
217
+ ```vue
218
+ <!-- SimpleCard.vue - No need for inheritAttrs: false -->
219
+ <template>
220
+ <article class="card">
221
+ <slot />
222
+ </article>
223
+ </template>
224
+ <!-- Passing class, id, or data-* to the root article is fine -->
225
+ ```
226
+
227
+ ## References
228
+
229
+ - [Fallthrough Attributes - Disabling Attribute Inheritance](https://vuejs.org/guide/components/attrs.html#disabling-attribute-inheritance)
230
+ - [Build Advanced Components in Vue 3 using $attrs](https://www.thisdot.co/blog/build-advanced-components-in-vue-3-using-usdattrs)
@@ -0,0 +1,222 @@
1
+ ---
2
+ title: KeepAlive with Nested Routes Double Mount Issue
3
+ impact: HIGH
4
+ impactDescription: Using KeepAlive with nested Vue Router routes can cause child components to mount twice
5
+ type: gotcha
6
+ tags: [vue3, keepalive, vue-router, nested-routes, double-mount, bug]
7
+ ---
8
+
9
+ # KeepAlive with Nested Routes Double Mount Issue
10
+
11
+ **Impact: HIGH** - When using `<KeepAlive>` with nested Vue Router routes, child route components may mount twice. This is a known issue that can cause duplicate API calls, broken state, and confusing behavior.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Test nested routes thoroughly when using KeepAlive
16
+ - [ ] Avoid mixing KeepAlive with deeply nested route structures
17
+ - [ ] Use workarounds if double mount is observed
18
+ - [ ] Consider alternative caching strategies for nested routes
19
+
20
+ ## The Problem
21
+
22
+ ```vue
23
+ <!-- App.vue -->
24
+ <template>
25
+ <router-view v-slot="{ Component }">
26
+ <KeepAlive>
27
+ <component :is="Component" />
28
+ </KeepAlive>
29
+ </router-view>
30
+ </template>
31
+ ```
32
+
33
+ ```javascript
34
+ // router.js
35
+ const routes = [
36
+ {
37
+ path: '/parent',
38
+ component: Parent,
39
+ children: [
40
+ {
41
+ path: 'child',
42
+ component: Child // This may mount TWICE!
43
+ }
44
+ ]
45
+ }
46
+ ]
47
+ ```
48
+
49
+ **Symptoms:**
50
+ - `onMounted` called twice in child component
51
+ - Duplicate API requests
52
+ - State initialization runs twice
53
+ - Console logs appear doubled
54
+
55
+ ## Diagnosis
56
+
57
+ Add logging to confirm the issue:
58
+
59
+ ```vue
60
+ <!-- Child.vue -->
61
+ <script setup>
62
+ import { onMounted, onActivated } from 'vue'
63
+
64
+ let mountCount = 0
65
+
66
+ onMounted(() => {
67
+ mountCount++
68
+ console.log('Child mounted - count:', mountCount)
69
+ // If you see "count: 2", you have the double mount issue
70
+ })
71
+
72
+ onActivated(() => {
73
+ console.log('Child activated')
74
+ })
75
+ </script>
76
+ ```
77
+
78
+ ## Workarounds
79
+
80
+ ### Option 1: Use `useActivatedRoute` Pattern
81
+
82
+ Don't use `useRoute()` directly with KeepAlive:
83
+
84
+ ```vue
85
+ <script setup>
86
+ import { ref, onActivated } from 'vue'
87
+ import { useRoute } from 'vue-router'
88
+
89
+ // Problem: useRoute() can cause issues with KeepAlive
90
+ // const route = useRoute()
91
+
92
+ // Solution: Get route info in onActivated
93
+ const routeParams = ref({})
94
+
95
+ onActivated(() => {
96
+ const route = useRoute()
97
+ routeParams.value = { ...route.params }
98
+ })
99
+ </script>
100
+ ```
101
+
102
+ ### Option 2: Avoid KeepAlive for Nested Route Parents
103
+
104
+ Only cache leaf routes, not parent layouts:
105
+
106
+ ```vue
107
+ <script setup>
108
+ import { computed } from 'vue'
109
+ import { useRoute } from 'vue-router'
110
+
111
+ const route = useRoute()
112
+
113
+ // Only cache specific leaf routes
114
+ const cachedRoutes = computed(() => {
115
+ // Don't cache parent routes that have children
116
+ return ['UserProfile', 'UserSettings'] // Only leaf components
117
+ })
118
+ </script>
119
+
120
+ <template>
121
+ <router-view v-slot="{ Component, route: currentRoute }">
122
+ <KeepAlive :include="cachedRoutes">
123
+ <component :is="Component" :key="currentRoute.fullPath" />
124
+ </KeepAlive>
125
+ </router-view>
126
+ </template>
127
+ ```
128
+
129
+ ### Option 3: Guard Against Double Initialization
130
+
131
+ Protect your component from double mount effects:
132
+
133
+ ```vue
134
+ <script setup>
135
+ import { ref, onMounted } from 'vue'
136
+
137
+ const isInitialized = ref(false)
138
+
139
+ onMounted(() => {
140
+ if (isInitialized.value) {
141
+ console.warn('Double mount detected, skipping initialization')
142
+ return
143
+ }
144
+ isInitialized.value = true
145
+
146
+ // Safe to initialize
147
+ fetchData()
148
+ setupEventListeners()
149
+ })
150
+ </script>
151
+ ```
152
+
153
+ ### Option 4: Use Route-Level Cache Control
154
+
155
+ ```vue
156
+ <!-- App.vue -->
157
+ <script setup>
158
+ import { computed } from 'vue'
159
+ import { useRoute } from 'vue-router'
160
+
161
+ const route = useRoute()
162
+
163
+ // Define which routes should be cached in route meta
164
+ const shouldCache = computed(() => {
165
+ return route.meta.keepAlive !== false
166
+ })
167
+ </script>
168
+
169
+ <template>
170
+ <router-view v-slot="{ Component }">
171
+ <KeepAlive v-if="shouldCache">
172
+ <component :is="Component" />
173
+ </KeepAlive>
174
+ <component v-else :is="Component" />
175
+ </router-view>
176
+ </template>
177
+ ```
178
+
179
+ ```javascript
180
+ // router.js
181
+ const routes = [
182
+ {
183
+ path: '/parent',
184
+ component: Parent,
185
+ meta: { keepAlive: false }, // Don't cache parent routes
186
+ children: [
187
+ {
188
+ path: 'child',
189
+ component: Child,
190
+ meta: { keepAlive: true } // Cache leaf routes
191
+ }
192
+ ]
193
+ }
194
+ ]
195
+ ```
196
+
197
+ ### Option 5: Flatten Route Structure
198
+
199
+ Avoid nesting if possible:
200
+
201
+ ```javascript
202
+ // Instead of nested routes
203
+ const routes = [
204
+ // Flat structure avoids the issue
205
+ { path: '/users', component: UserList },
206
+ { path: '/users/:id', component: UserDetail },
207
+ { path: '/users/:id/settings', component: UserSettings }
208
+ ]
209
+ ```
210
+
211
+ ## Key Points
212
+
213
+ 1. **Known Vue Router issue** - Double mount with KeepAlive + nested routes
214
+ 2. **Watch for symptoms** - Duplicate API calls, doubled logs
215
+ 3. **Avoid caching parent routes** - Only cache leaf components
216
+ 4. **Add initialization guards** - Protect against double execution
217
+ 5. **Test thoroughly** - This issue may not appear immediately
218
+
219
+ ## Reference
220
+ - [Vue Router Issue #626: keep-alive in nested route mounted twice](https://github.com/vuejs/router/issues/626)
221
+ - [GitHub: vue3-keep-alive-component workaround](https://github.com/emiyalee1005/vue3-keep-alive-component)
222
+ - [Vue.js KeepAlive Documentation](https://vuejs.org/guide/built-ins/keep-alive.html)