204 lines
5.5 KiB
Markdown
204 lines
5.5 KiB
Markdown
---
|
|
title: Provide/Inject Has Limited DevTools Support - Plan for Debugging
|
|
impact: LOW
|
|
impactDescription: Unlike props and state, provided values are harder to trace in Vue DevTools, making debugging more challenging
|
|
type: gotcha
|
|
tags: [vue3, provide-inject, debugging, devtools, architecture]
|
|
---
|
|
|
|
# Provide/Inject Has Limited DevTools Support - Plan for Debugging
|
|
|
|
**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.
|
|
|
|
## Task Checklist
|
|
|
|
- [ ] Document provided values at the provider component level
|
|
- [ ] Use descriptive Symbol descriptions for easier identification
|
|
- [ ] Consider adding development-only logging for provided state changes
|
|
- [ ] Keep provide/inject chains shallow when possible
|
|
- [ ] Prefer Pinia for complex state that needs DevTools integration
|
|
|
|
## The Challenge
|
|
|
|
Unlike props which are clearly visible in Vue DevTools for each component, provided values:
|
|
|
|
1. Don't show which ancestor provided them
|
|
2. Require manual navigation to find the provider
|
|
3. Don't show in the standard props/data panels
|
|
4. Can be shadowed by closer ancestors using the same key
|
|
|
|
## Strategies for Better Debugging
|
|
|
|
### 1. Use Descriptive Symbol Names
|
|
|
|
```js
|
|
// injection-keys.js
|
|
|
|
// BETTER: Descriptive names appear in errors and debugging
|
|
export const UserAuthKey = Symbol('UserAuthenticationState')
|
|
export const ThemeConfigKey = Symbol('ThemeConfiguration')
|
|
export const FormContextKey = Symbol('FormValidationContext')
|
|
|
|
// WORSE: Generic names are harder to trace
|
|
export const UserKey = Symbol()
|
|
export const ThemeKey = Symbol('theme')
|
|
```
|
|
|
|
### 2. Document Providers Clearly
|
|
|
|
```vue
|
|
<!-- AuthProvider.vue -->
|
|
<script setup>
|
|
/**
|
|
* Authentication Provider
|
|
*
|
|
* Provides:
|
|
* - UserAuthKey: Current user state (Ref<User | null>)
|
|
* - AuthActionsKey: { login, logout, refresh }
|
|
*
|
|
* Must wrap any component that needs authentication state.
|
|
*/
|
|
import { provide, ref, readonly } from 'vue'
|
|
import { UserAuthKey, AuthActionsKey } from '@/injection-keys'
|
|
|
|
const user = ref(null)
|
|
|
|
// ... implementation
|
|
|
|
provide(UserAuthKey, readonly(user))
|
|
provide(AuthActionsKey, { login, logout, refresh })
|
|
</script>
|
|
```
|
|
|
|
### 3. Development-Only Logging
|
|
|
|
```js
|
|
// composables/useProvideWithLogging.js
|
|
import { provide, watch, getCurrentInstance } from 'vue'
|
|
|
|
export function useProvideWithLogging(key, value, name) {
|
|
provide(key, value)
|
|
|
|
if (import.meta.env.DEV) {
|
|
const instance = getCurrentInstance()
|
|
const componentName = instance?.type?.name || 'Unknown'
|
|
|
|
console.log(`[Provide] ${name} provided by <${componentName}>`)
|
|
|
|
// Log reactive changes
|
|
if (value && typeof value === 'object' && 'value' in value) {
|
|
watch(value, (newVal) => {
|
|
console.log(`[Provide] ${name} changed:`, newVal)
|
|
}, { deep: true })
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
```vue
|
|
<script setup>
|
|
import { ref } from 'vue'
|
|
import { useProvideWithLogging } from '@/composables/useProvideWithLogging'
|
|
import { ThemeKey } from '@/injection-keys'
|
|
|
|
const theme = ref('dark')
|
|
|
|
// In development, logs when provided and when changed
|
|
useProvideWithLogging(ThemeKey, theme, 'Theme')
|
|
</script>
|
|
```
|
|
|
|
### 4. Inject with Missing Provider Warnings
|
|
|
|
```js
|
|
// composables/useSafeInject.js
|
|
import { inject, getCurrentInstance } from 'vue'
|
|
|
|
export function useSafeInject(key, fallback, keyName) {
|
|
const value = inject(key, undefined)
|
|
|
|
if (value === undefined) {
|
|
const instance = getCurrentInstance()
|
|
const componentName = instance?.type?.name || 'Unknown'
|
|
|
|
if (import.meta.env.DEV) {
|
|
console.warn(
|
|
`[Inject] ${keyName || String(key)} not provided. ` +
|
|
`Component <${componentName}> is using fallback value. ` +
|
|
`Ensure a provider exists in the ancestor chain.`
|
|
)
|
|
}
|
|
|
|
return typeof fallback === 'function' ? fallback() : fallback
|
|
}
|
|
|
|
return value
|
|
}
|
|
```
|
|
|
|
```vue
|
|
<script setup>
|
|
import { useSafeInject } from '@/composables/useSafeInject'
|
|
import { ThemeKey } from '@/injection-keys'
|
|
|
|
// Warns in dev if no provider found
|
|
const theme = useSafeInject(ThemeKey, () => ({ mode: 'light' }), 'ThemeConfig')
|
|
</script>
|
|
```
|
|
|
|
### 5. Create Provider Registry for Complex Apps
|
|
|
|
```js
|
|
// utils/provider-registry.js
|
|
const providerRegistry = new Map()
|
|
|
|
export function registerProvider(key, componentName, value) {
|
|
if (import.meta.env.DEV) {
|
|
providerRegistry.set(key, {
|
|
componentName,
|
|
value,
|
|
timestamp: Date.now()
|
|
})
|
|
}
|
|
}
|
|
|
|
export function getProviderInfo(key) {
|
|
return providerRegistry.get(key)
|
|
}
|
|
|
|
// For DevTools custom plugin or debugging
|
|
export function getAllProviders() {
|
|
return Object.fromEntries(providerRegistry)
|
|
}
|
|
|
|
// Expose to window for console debugging
|
|
if (import.meta.env.DEV) {
|
|
window.__VUE_PROVIDERS__ = {
|
|
getAll: getAllProviders,
|
|
get: getProviderInfo
|
|
}
|
|
}
|
|
```
|
|
|
|
## When to Use Pinia Instead
|
|
|
|
If you find yourself needing extensive debugging for state:
|
|
|
|
| Use Provide/Inject | Use Pinia |
|
|
|-------------------|-----------|
|
|
| Component library internals | Application-wide state |
|
|
| Theme/locale configuration | User session data |
|
|
| Form context | Shopping cart |
|
|
| Simple parent-child sharing | Complex state with actions |
|
|
| Plugin configuration | State that needs time-travel debugging |
|
|
|
|
Pinia provides excellent DevTools integration with:
|
|
- State inspection
|
|
- Time-travel debugging
|
|
- Action logging
|
|
- Hot module replacement
|
|
|
|
## Reference
|
|
- [Vue DevTools](https://devtools.vuejs.org/)
|
|
- [Pinia DevTools](https://pinia.vuejs.org/core-concepts/index.html#devtools)
|