--- title: Top-Level await in script setup Preserves Component Context impact: HIGH impactDescription: Misunderstanding async context causes lifecycle hooks and watchers to silently fail type: gotcha tags: [vue3, composition-api, script-setup, async, await, suspense] --- # Top-Level await in script setup Preserves Component Context **Impact: HIGH** - In ` ``` **Nested Async Breaks Context:** ```vue ``` **Correct Patterns:** ```vue ``` **setup() Function (Not script setup):** ```javascript // In regular setup(), await ALWAYS breaks context export default { async setup() { const data = ref(null) // WRONG: Hooks after await won't register const config = await fetchConfig() onMounted(() => { console.log('Never runs!') // Silent failure! }) return { data } } } // CORRECT: Register hooks before any await export default { async setup() { const data = ref(null) // Register hooks FIRST (synchronous) onMounted(async () => { const config = await fetchConfig() data.value = await fetchData(config) }) // Now you can await if needed // But hooks must be registered before this point return { data } } } ``` ## Why This Happens ```javascript // Vue tracks the "current component instance" during setup // This is like a global variable that gets set and cleared // During synchronous setup: function setup() { currentInstance = this // Vue sets this onMounted(cb) // Uses currentInstance to register // After await, JavaScript resumes in a microtask await something() // currentInstance is now null or different! onMounted(cb) // Can't find the instance - silently fails } //