All skills
hyf0 avatar

/vue-debug-guides

@a5fc891 official
by hyf0hyf0/vue-skills2.9k stars
167

Vue 3 debugging and error handling for runtime errors, warnings, async failures, and SSR/hydration issues. Use when diagnosing or fixing Vue issues.

Use this Skill: https://skilld.dev/gh/hyf0/vue-skills/vue-debug-guides

This session only. Nothing lands on disk.

referencecomposable-call-location-restrictions.md

≈1.2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Call Composables Only in Setup Context Synchronously

Impact: HIGH - Composables must be called synchronously within <script setup>, the setup() function, or lifecycle hooks. Calling composables asynchronously (after await), in callbacks, or outside component context prevents Vue from associating lifecycle hooks with the component instance, causing silent failures.

This is critical because composables often register onMounted and onUnmounted hooks internally. If called in the wrong context, these hooks are never registered, leading to uninitialized state or memory leaks.

Task Checklist

  • Call all composables at the top level of <script setup> or setup()
  • Never call composables inside async callbacks, setTimeout, or Promise.then
  • Never call composables conditionally (if/else) - call unconditionally and handle the condition inside
  • Never call composables inside loops - restructure to call once with array data
  • Exception: Composables CAN be called in lifecycle hooks like onMounted

Incorrect:

<script setup>
import { useFetch } from './composables/useFetch'
import { useAuth } from './composables/useAuth'

// WRONG: Composable called after await
const config = await loadConfig()
const { data } = useFetch(config.apiUrl)  // Lifecycle hooks won't register!

// WRONG: Composable called conditionally
if (someCondition) {
  const { user } = useAuth()  // Inconsistent hook registration!
}

// WRONG: Composable called in callback
setTimeout(() => {
  const { data } = useFetch('/api/delayed')  // No component context!
}, 1000)

// WRONG: Composable called in loop
for (const url of urls) {
  const { data } = useFetch(url)  // Creates multiple instances incorrectly
}
</script>

Correct:

<script setup>
import { ref, onMounted } from 'vue'
import { useFetch } from './composables/useFetch'
import { useAuth } from './composables/useAuth'

// CORRECT: Call composables synchronously at top level
const { user, isAuthenticated } = useAuth()
const apiUrl = ref('/api/default')
const { data, execute } = useFetch(apiUrl)

// Handle async config loading differently
onMounted(async () => {
  const config = await loadConfig()
  apiUrl.value = config.apiUrl  // Update the ref, composable reacts
})

// CORRECT: Handle condition inside, not outside
const showUserData = computed(() => isAuthenticated.value && someCondition)

// CORRECT: For multiple URLs, use a different pattern
const urls = ref(['/api/a', '/api/b', '/api/c'])
const results = ref([])

// Either fetch in onMounted or use a composable designed for arrays
onMounted(async () => {
  results.value = await Promise.all(urls.value.map(url => fetch(url)))
})
</script>

Exception: Calling in Lifecycle Hooks

Composables CAN be called inside lifecycle hooks because Vue maintains the component context:

<script setup>
import { onMounted } from 'vue'
import { useEventListener } from '@vueuse/core'

// CORRECT: Called in lifecycle hook - component context is available
onMounted(() => {
  // This works because we're still in the component's execution context
  useEventListener(document, 'visibilitychange', handleVisibility)
})
</script>

Special Case: Async Setup in <script setup>

Top-level await in <script setup> is special - Vue's compiler automatically preserves context:

<script setup>
import { useFetch } from './composables/useFetch'

// CORRECT: Top-level await in <script setup> preserves context
// Vue compiler handles this specially
const config = await loadConfig()
const { data } = useFetch(config.apiUrl)  // This works!

// But nested awaits still break context:
async function initLater() {
  await delay(1000)
  const { data } = useFetch('/api/late')  // WRONG: This won't work!
}
</script>

Why This Matters

When you call a composable, Vue needs to know which component instance to associate it with. This association happens through an internal "current instance" that's only set during synchronous setup execution.

// Inside a composable
export function useFetch(url) {
  const data = ref(null)

  // These need the current component instance!
  onMounted(() => { /* ... */ })
  onUnmounted(() => { /* cleanup */ })

  // If called outside setup context, Vue can't find the instance
  // and these hooks are silently ignored
  return { data }
}

Reference

Source: SKILL.md on GitHub

No alerts17d5 checks · Risk SAFE
  • Gen Agent Trust Hub17d

    This skill is a comprehensive collection of educational debugging guides and best practices for Vue 3 developers. It contains no executable code or malicious instructions and focuses solely on diagnosing common runtime errors and performance issues.

  • Socket17d

    No alerts

  • Snyk17d

    Risk: LOW · No issues

  • Runlayer7mo

    140 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at a5fc891. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 8 months ago

README badge

README badge for hyf0/vue-skills/vue-debug-guides

Guides for diagnosing and fixing Vue 3 runtime errors, reactivity bugs, async failures, and hydration issues across components, templates, watchers, forms, and lifecycle hooks. Covers specific failure modes like stale watchers, ref unwrapping edge cases, v-model sync problems, and SSR mismatches with concrete reference links for each issue.

Generated from the current SKILL.md.

Does this skill cover Vue 2?
No. This skill is specific to Vue 3 debugging and error handling.
What should I use for Vue development best practices instead of debugging?
The skill references a separate `vue-best-practices` skill for development best practices and common gotchas.
Does this cover SSR and hydration issues?
Yes. The skill includes guides for diagnosing and fixing SSR rendering differences and hydration bugs.
Can this help with async watcher and watchEffect problems?
Yes. The skill covers async operation stale data, dependency tracking after await, and proper flush timing for watchers.
Does this address v-model and form-related issues?
Yes. The skill includes guides for v-model initial values, textarea interpolation, IME composition, and custom checkbox form submission.

Generated from the current SKILL.md. These answers refresh after source changes.