@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,203 @@
1
+ ---
2
+ title: Provide/Inject Has Limited DevTools Support - Plan for Debugging
3
+ impact: LOW
4
+ impactDescription: Unlike props and state, provided values are harder to trace in Vue DevTools, making debugging more challenging
5
+ type: gotcha
6
+ tags: [vue3, provide-inject, debugging, devtools, architecture]
7
+ ---
8
+
9
+ # Provide/Inject Has Limited DevTools Support - Plan for Debugging
10
+
11
+ **Impact: LOW** - While provide/inject is powerful for avoiding prop drilling, it creates less visible data flow than props. Provided values are not as easily inspectable in Vue DevTools, and tracing where a value comes from requires navigating the component tree manually.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Document provided values at the provider component level
16
+ - [ ] Use descriptive Symbol descriptions for easier identification
17
+ - [ ] Consider adding development-only logging for provided state changes
18
+ - [ ] Keep provide/inject chains shallow when possible
19
+ - [ ] Prefer Pinia for complex state that needs DevTools integration
20
+
21
+ ## The Challenge
22
+
23
+ Unlike props which are clearly visible in Vue DevTools for each component, provided values:
24
+
25
+ 1. Don't show which ancestor provided them
26
+ 2. Require manual navigation to find the provider
27
+ 3. Don't show in the standard props/data panels
28
+ 4. Can be shadowed by closer ancestors using the same key
29
+
30
+ ## Strategies for Better Debugging
31
+
32
+ ### 1. Use Descriptive Symbol Names
33
+
34
+ ```js
35
+ // injection-keys.js
36
+
37
+ // BETTER: Descriptive names appear in errors and debugging
38
+ export const UserAuthKey = Symbol('UserAuthenticationState')
39
+ export const ThemeConfigKey = Symbol('ThemeConfiguration')
40
+ export const FormContextKey = Symbol('FormValidationContext')
41
+
42
+ // WORSE: Generic names are harder to trace
43
+ export const UserKey = Symbol()
44
+ export const ThemeKey = Symbol('theme')
45
+ ```
46
+
47
+ ### 2. Document Providers Clearly
48
+
49
+ ```vue
50
+ <!-- AuthProvider.vue -->
51
+ <script setup>
52
+ /**
53
+ * Authentication Provider
54
+ *
55
+ * Provides:
56
+ * - UserAuthKey: Current user state (Ref<User | null>)
57
+ * - AuthActionsKey: { login, logout, refresh }
58
+ *
59
+ * Must wrap any component that needs authentication state.
60
+ */
61
+ import { provide, ref, readonly } from 'vue'
62
+ import { UserAuthKey, AuthActionsKey } from '@/injection-keys'
63
+
64
+ const user = ref(null)
65
+
66
+ // ... implementation
67
+
68
+ provide(UserAuthKey, readonly(user))
69
+ provide(AuthActionsKey, { login, logout, refresh })
70
+ </script>
71
+ ```
72
+
73
+ ### 3. Development-Only Logging
74
+
75
+ ```js
76
+ // composables/useProvideWithLogging.js
77
+ import { provide, watch, getCurrentInstance } from 'vue'
78
+
79
+ export function useProvideWithLogging(key, value, name) {
80
+ provide(key, value)
81
+
82
+ if (import.meta.env.DEV) {
83
+ const instance = getCurrentInstance()
84
+ const componentName = instance?.type?.name || 'Unknown'
85
+
86
+ console.log(`[Provide] ${name} provided by <${componentName}>`)
87
+
88
+ // Log reactive changes
89
+ if (value && typeof value === 'object' && 'value' in value) {
90
+ watch(value, (newVal) => {
91
+ console.log(`[Provide] ${name} changed:`, newVal)
92
+ }, { deep: true })
93
+ }
94
+ }
95
+ }
96
+ ```
97
+
98
+ ```vue
99
+ <script setup>
100
+ import { ref } from 'vue'
101
+ import { useProvideWithLogging } from '@/composables/useProvideWithLogging'
102
+ import { ThemeKey } from '@/injection-keys'
103
+
104
+ const theme = ref('dark')
105
+
106
+ // In development, logs when provided and when changed
107
+ useProvideWithLogging(ThemeKey, theme, 'Theme')
108
+ </script>
109
+ ```
110
+
111
+ ### 4. Inject with Missing Provider Warnings
112
+
113
+ ```js
114
+ // composables/useSafeInject.js
115
+ import { inject, getCurrentInstance } from 'vue'
116
+
117
+ export function useSafeInject(key, fallback, keyName) {
118
+ const value = inject(key, undefined)
119
+
120
+ if (value === undefined) {
121
+ const instance = getCurrentInstance()
122
+ const componentName = instance?.type?.name || 'Unknown'
123
+
124
+ if (import.meta.env.DEV) {
125
+ console.warn(
126
+ `[Inject] ${keyName || String(key)} not provided. ` +
127
+ `Component <${componentName}> is using fallback value. ` +
128
+ `Ensure a provider exists in the ancestor chain.`
129
+ )
130
+ }
131
+
132
+ return typeof fallback === 'function' ? fallback() : fallback
133
+ }
134
+
135
+ return value
136
+ }
137
+ ```
138
+
139
+ ```vue
140
+ <script setup>
141
+ import { useSafeInject } from '@/composables/useSafeInject'
142
+ import { ThemeKey } from '@/injection-keys'
143
+
144
+ // Warns in dev if no provider found
145
+ const theme = useSafeInject(ThemeKey, () => ({ mode: 'light' }), 'ThemeConfig')
146
+ </script>
147
+ ```
148
+
149
+ ### 5. Create Provider Registry for Complex Apps
150
+
151
+ ```js
152
+ // utils/provider-registry.js
153
+ const providerRegistry = new Map()
154
+
155
+ export function registerProvider(key, componentName, value) {
156
+ if (import.meta.env.DEV) {
157
+ providerRegistry.set(key, {
158
+ componentName,
159
+ value,
160
+ timestamp: Date.now()
161
+ })
162
+ }
163
+ }
164
+
165
+ export function getProviderInfo(key) {
166
+ return providerRegistry.get(key)
167
+ }
168
+
169
+ // For DevTools custom plugin or debugging
170
+ export function getAllProviders() {
171
+ return Object.fromEntries(providerRegistry)
172
+ }
173
+
174
+ // Expose to window for console debugging
175
+ if (import.meta.env.DEV) {
176
+ window.__VUE_PROVIDERS__ = {
177
+ getAll: getAllProviders,
178
+ get: getProviderInfo
179
+ }
180
+ }
181
+ ```
182
+
183
+ ## When to Use Pinia Instead
184
+
185
+ If you find yourself needing extensive debugging for state:
186
+
187
+ | Use Provide/Inject | Use Pinia |
188
+ |-------------------|-----------|
189
+ | Component library internals | Application-wide state |
190
+ | Theme/locale configuration | User session data |
191
+ | Form context | Shopping cart |
192
+ | Simple parent-child sharing | Complex state with actions |
193
+ | Plugin configuration | State that needs time-travel debugging |
194
+
195
+ Pinia provides excellent DevTools integration with:
196
+ - State inspection
197
+ - Time-travel debugging
198
+ - Action logging
199
+ - Hot module replacement
200
+
201
+ ## Reference
202
+ - [Vue DevTools](https://devtools.vuejs.org/)
203
+ - [Pinia DevTools](https://pinia.vuejs.org/core-concepts/index.html#devtools)
@@ -0,0 +1,244 @@
1
+ ---
2
+ title: Use Factory Functions for Non-Primitive Inject Default Values
3
+ impact: MEDIUM
4
+ impactDescription: Using object literals as default values creates shared references across all consuming components
5
+ type: gotcha
6
+ tags: [vue3, provide-inject, composition-api, memory, shared-state]
7
+ ---
8
+
9
+ # Use Factory Functions for Non-Primitive Inject Default Values
10
+
11
+ **Impact: MEDIUM** - When providing default values for `inject()`, using an object literal creates a single shared reference. All components using that default will share the same object, leading to unexpected state sharing and bugs.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Always use factory functions for object/array default values in inject
16
+ - [ ] Pass `true` as the third argument to enable factory mode in Composition API
17
+ - [ ] Use the object syntax with factory function in Options API
18
+ - [ ] Only use literal defaults for primitive values (strings, numbers, booleans)
19
+
20
+ ## The Gotcha: Shared Default References
21
+
22
+ **Wrong - Object literal creates shared reference:**
23
+ ```vue
24
+ <script setup>
25
+ import { inject } from 'vue'
26
+
27
+ // WRONG: All components without a provider share this SAME object
28
+ const config = inject('config', { debug: false, apiUrl: '' })
29
+
30
+ // If one component does this:
31
+ config.debug = true
32
+
33
+ // ALL other components using this default now have debug: true!
34
+ </script>
35
+ ```
36
+
37
+ **Correct - Factory function creates unique instance:**
38
+ ```vue
39
+ <script setup>
40
+ import { inject } from 'vue'
41
+
42
+ // CORRECT: Each component gets its own object
43
+ // Third argument `true` indicates the second arg is a factory function
44
+ const config = inject('config', () => ({ debug: false, apiUrl: '' }), true)
45
+ </script>
46
+ ```
47
+
48
+ ## API Explanation
49
+
50
+ The `inject()` function has multiple signatures:
51
+
52
+ ```ts
53
+ // Simple default value (OK for primitives)
54
+ inject(key, defaultValue)
55
+
56
+ // Factory function for non-primitives (REQUIRED for objects/arrays)
57
+ inject(key, factoryFunction, true)
58
+ ```
59
+
60
+ The third argument `true` tells Vue that the second argument is a factory function, not the default value itself.
61
+
62
+ ## Examples
63
+
64
+ ### Primitive Defaults (No Factory Needed)
65
+
66
+ ```vue
67
+ <script setup>
68
+ import { inject } from 'vue'
69
+
70
+ // Primitives are safe without factory
71
+ const count = inject('count', 0)
72
+ const name = inject('name', 'Guest')
73
+ const enabled = inject('enabled', false)
74
+ </script>
75
+ ```
76
+
77
+ ### Object Defaults (Factory Required)
78
+
79
+ ```vue
80
+ <script setup>
81
+ import { inject } from 'vue'
82
+
83
+ // Objects MUST use factory
84
+ const user = inject('user', () => ({
85
+ id: null,
86
+ name: 'Anonymous',
87
+ preferences: {}
88
+ }), true)
89
+
90
+ const settings = inject('settings', () => ({
91
+ theme: 'light',
92
+ language: 'en',
93
+ notifications: true
94
+ }), true)
95
+ </script>
96
+ ```
97
+
98
+ ### Array Defaults (Factory Required)
99
+
100
+ ```vue
101
+ <script setup>
102
+ import { inject } from 'vue'
103
+
104
+ // Arrays MUST use factory
105
+ const items = inject('items', () => [], true)
106
+ const permissions = inject('permissions', () => ['read'], true)
107
+ </script>
108
+ ```
109
+
110
+ ### Class Instance Defaults (Factory Required)
111
+
112
+ ```vue
113
+ <script setup>
114
+ import { inject } from 'vue'
115
+ import { Logger } from '@/utils/logger'
116
+
117
+ // Class instances MUST use factory
118
+ const logger = inject('logger', () => new Logger({ level: 'warn' }), true)
119
+ </script>
120
+ ```
121
+
122
+ ## Options API Syntax
123
+
124
+ In Options API, use the object syntax with a `default` factory function:
125
+
126
+ ```js
127
+ export default {
128
+ inject: {
129
+ // Primitive - can use literal
130
+ theme: {
131
+ from: 'theme',
132
+ default: 'light'
133
+ },
134
+
135
+ // Object - MUST use factory
136
+ config: {
137
+ from: 'config',
138
+ default: () => ({ debug: false })
139
+ },
140
+
141
+ // Array - MUST use factory
142
+ permissions: {
143
+ from: 'permissions',
144
+ default: () => []
145
+ }
146
+ }
147
+ }
148
+ ```
149
+
150
+ ## Real-World Example: Form Context
151
+
152
+ ```vue
153
+ <!-- FormProvider.vue -->
154
+ <script setup>
155
+ import { provide, reactive } from 'vue'
156
+
157
+ const formContext = reactive({
158
+ values: {},
159
+ errors: {},
160
+ touched: {},
161
+ isSubmitting: false
162
+ })
163
+
164
+ provide('formContext', formContext)
165
+ </script>
166
+
167
+ <!-- FormField.vue (might be used outside FormProvider) -->
168
+ <script setup>
169
+ import { inject } from 'vue'
170
+
171
+ // Safe default that won't be shared
172
+ const formContext = inject('formContext', () => ({
173
+ values: {},
174
+ errors: {},
175
+ touched: {},
176
+ isSubmitting: false,
177
+ // Mark as standalone mode
178
+ isStandalone: true
179
+ }), true)
180
+
181
+ // Component works both inside and outside FormProvider
182
+ </script>
183
+ ```
184
+
185
+ ## TypeScript: Typing Factory Defaults
186
+
187
+ ```ts
188
+ import { inject } from 'vue'
189
+ import type { InjectionKey } from 'vue'
190
+
191
+ interface Config {
192
+ apiUrl: string
193
+ debug: boolean
194
+ features: string[]
195
+ }
196
+
197
+ const ConfigKey: InjectionKey<Config> = Symbol('config')
198
+
199
+ // TypeScript understands the factory return type
200
+ const config = inject(ConfigKey, () => ({
201
+ apiUrl: 'https://api.example.com',
202
+ debug: false,
203
+ features: []
204
+ }), true)
205
+ ```
206
+
207
+ ## Common Mistake in Testing
208
+
209
+ This gotcha often appears in tests where components are rendered without providers:
210
+
211
+ ```ts
212
+ // test.spec.ts
213
+ import { mount } from '@vue/test-utils'
214
+ import MyComponent from './MyComponent.vue'
215
+
216
+ // Without provider, all test instances share the wrong default
217
+ it('test 1', () => {
218
+ const wrapper = mount(MyComponent)
219
+ wrapper.vm.config.debug = true // Pollutes other tests!
220
+ })
221
+
222
+ it('test 2', () => {
223
+ const wrapper = mount(MyComponent)
224
+ // Might fail because debug is still true from test 1
225
+ })
226
+ ```
227
+
228
+ **Fix: Use factory functions in the component, or provide in tests:**
229
+
230
+ ```ts
231
+ it('test with provider', () => {
232
+ const wrapper = mount(MyComponent, {
233
+ global: {
234
+ provide: {
235
+ config: { debug: false, apiUrl: '' }
236
+ }
237
+ }
238
+ })
239
+ })
240
+ ```
241
+
242
+ ## Reference
243
+ - [Vue.js inject() API Reference](https://vuejs.org/api/composition-api-dependency-injection.html#inject)
244
+ - [Vue.js Provide/Inject Guide](https://vuejs.org/guide/components/provide-inject.html)
@@ -0,0 +1,226 @@
1
+ ---
2
+ title: Provide/Inject Values Are Not Reactive by Default
3
+ impact: HIGH
4
+ impactDescription: Provided primitive values lose reactivity, causing injecting components to not update when the source value changes
5
+ type: gotcha
6
+ tags: [vue3, provide-inject, reactivity, composition-api, options-api]
7
+ ---
8
+
9
+ # Provide/Inject Values Are Not Reactive by Default
10
+
11
+ **Impact: HIGH** - A common misconception is that provide/inject automatically maintains reactivity. By default, provided primitive values are NOT reactive. If the provided value changes in the provider, injecting components will NOT be updated.
12
+
13
+ ## Task Checklist
14
+
15
+ - [ ] Always wrap primitive values in `ref()` before providing
16
+ - [ ] Use `computed()` in Options API `provide()` for reactive data
17
+ - [ ] Never destructure refs when providing - pass the ref directly
18
+ - [ ] Understand that provided refs are NOT auto-unwrapped in injectors
19
+
20
+ ## The Gotcha: Primitives Lose Reactivity
21
+
22
+ **Wrong - Primitive loses reactivity:**
23
+ ```vue
24
+ <!-- Provider.vue -->
25
+ <script setup>
26
+ import { ref, provide } from 'vue'
27
+
28
+ const count = ref(0)
29
+
30
+ // WRONG: Providing the unwrapped value loses reactivity
31
+ provide('count', count.value) // Provides 0, not a reactive value
32
+
33
+ function increment() {
34
+ count.value++ // Injector will NOT see this change
35
+ }
36
+ </script>
37
+ ```
38
+
39
+ ```vue
40
+ <!-- Injector.vue -->
41
+ <script setup>
42
+ import { inject } from 'vue'
43
+
44
+ const count = inject('count') // Gets 0, forever static
45
+ </script>
46
+
47
+ <template>
48
+ <!-- This will always show 0 -->
49
+ <div>Count: {{ count }}</div>
50
+ </template>
51
+ ```
52
+
53
+ **Correct - Provide the ref itself:**
54
+ ```vue
55
+ <!-- Provider.vue -->
56
+ <script setup>
57
+ import { ref, provide } from 'vue'
58
+
59
+ const count = ref(0)
60
+
61
+ // CORRECT: Provide the ref, not the value
62
+ provide('count', count)
63
+
64
+ function increment() {
65
+ count.value++ // Injector WILL see this change
66
+ }
67
+ </script>
68
+ ```
69
+
70
+ ```vue
71
+ <!-- Injector.vue -->
72
+ <script setup>
73
+ import { inject } from 'vue'
74
+
75
+ // The ref is injected as-is, maintaining reactivity
76
+ const count = inject('count')
77
+ </script>
78
+
79
+ <template>
80
+ <!-- Access .value in script, auto-unwrapped in template -->
81
+ <div>Count: {{ count }}</div>
82
+ </template>
83
+ ```
84
+
85
+ ## Options API: Use computed() for Reactivity
86
+
87
+ In Options API, the `provide` option with plain properties is NOT reactive:
88
+
89
+ **Wrong - Options API without computed:**
90
+ ```js
91
+ export default {
92
+ data() {
93
+ return {
94
+ message: 'Hello'
95
+ }
96
+ },
97
+ // WRONG: This is NOT reactive
98
+ provide() {
99
+ return {
100
+ message: this.message // Provides 'Hello' as a static string
101
+ }
102
+ }
103
+ }
104
+ ```
105
+
106
+ **Correct - Use computed() in Options API:**
107
+ ```js
108
+ import { computed } from 'vue'
109
+
110
+ export default {
111
+ data() {
112
+ return {
113
+ message: 'Hello'
114
+ }
115
+ },
116
+ provide() {
117
+ return {
118
+ // CORRECT: Wrap in computed for reactivity
119
+ message: computed(() => this.message)
120
+ }
121
+ }
122
+ }
123
+ ```
124
+
125
+ ## Understanding Ref Behavior in Inject
126
+
127
+ When you provide a ref, it is injected as-is and NOT auto-unwrapped:
128
+
129
+ ```vue
130
+ <!-- Provider.vue -->
131
+ <script setup>
132
+ import { ref, provide } from 'vue'
133
+
134
+ const user = ref({ name: 'John' })
135
+ provide('user', user)
136
+ </script>
137
+ ```
138
+
139
+ ```vue
140
+ <!-- Injector.vue -->
141
+ <script setup>
142
+ import { inject } from 'vue'
143
+
144
+ const user = inject('user')
145
+
146
+ // In script, access with .value
147
+ console.log(user.value.name) // 'John'
148
+
149
+ function updateName(newName) {
150
+ user.value.name = newName // Works, but mutations should be in provider
151
+ }
152
+ </script>
153
+
154
+ <template>
155
+ <!-- In template, auto-unwrapped at top level -->
156
+ <div>{{ user.name }}</div>
157
+ </template>
158
+ ```
159
+
160
+ ## Providing Reactive Objects
161
+
162
+ Reactive objects (created with `reactive()`) maintain reactivity when provided:
163
+
164
+ ```vue
165
+ <!-- Provider.vue -->
166
+ <script setup>
167
+ import { reactive, provide } from 'vue'
168
+
169
+ const state = reactive({
170
+ count: 0,
171
+ message: 'Hello'
172
+ })
173
+
174
+ provide('state', state)
175
+ </script>
176
+ ```
177
+
178
+ ```vue
179
+ <!-- Injector.vue -->
180
+ <script setup>
181
+ import { inject } from 'vue'
182
+
183
+ const state = inject('state')
184
+ // state.count and state.message are reactive
185
+ </script>
186
+ ```
187
+
188
+ ## Common Mistake: Destructuring Breaks Reactivity
189
+
190
+ **Wrong - Destructuring provided reactive state:**
191
+ ```vue
192
+ <script setup>
193
+ import { inject } from 'vue'
194
+
195
+ // WRONG: Destructuring loses reactivity
196
+ const { count, message } = inject('state')
197
+ // count and message are now static values
198
+ </script>
199
+ ```
200
+
201
+ **Correct - Keep the reference intact:**
202
+ ```vue
203
+ <script setup>
204
+ import { inject, toRefs } from 'vue'
205
+
206
+ const state = inject('state')
207
+ // Use state.count and state.message directly
208
+
209
+ // Or use toRefs if you need destructured reactive refs
210
+ const { count, message } = toRefs(state)
211
+ </script>
212
+ ```
213
+
214
+ ## Debugging Tip
215
+
216
+ If your injected value isn't updating:
217
+
218
+ 1. Check if you provided `ref.value` instead of `ref`
219
+ 2. Check if you destructured a reactive object
220
+ 3. In Options API, ensure you used `computed()`
221
+ 4. Use Vue DevTools to inspect the provided values
222
+
223
+ ## Reference
224
+ - [Vue.js Provide/Inject - Working with Reactivity](https://vuejs.org/guide/components/provide-inject.html#working-with-reactivity)
225
+ - [How to make provide/inject reactive - LogRocket Blog](https://blog.logrocket.com/how-to-make-provide-inject-reactive/)
226
+ - [GitHub Issue: Inject/Provide is not reactive](https://github.com/vuejs/vue/issues/7017)