Pulled ALL skills from 15 source repositories: - anthropics/skills: 16 (docs, design, MCP, testing) - obra/superpowers: 14 (TDD, debugging, agents, planning) - coreyhaines31/marketingskills: 25 (marketing, CRO, SEO, growth) - better-auth/skills: 5 (auth patterns) - vercel-labs/agent-skills: 5 (React, design, Vercel) - antfu/skills: 16 (Vue, Vite, Vitest, pnpm, Turborepo) - Plus 13 individual skills from various repos Mosaic Stack is not limited to coding — the Orchestrator and subagents serve coding, business, design, marketing, writing, logistics, analysis, and more. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5.0 KiB
5.0 KiB
title, impact, impactDescription, type, tags
| title | impact | impactDescription | type | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| KeepAlive with Nested Routes Double Mount Issue | HIGH | Using KeepAlive with nested Vue Router routes can cause child components to mount twice | gotcha |
|
KeepAlive with Nested Routes Double Mount Issue
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.
Task Checklist
- Test nested routes thoroughly when using KeepAlive
- Avoid mixing KeepAlive with deeply nested route structures
- Use workarounds if double mount is observed
- Consider alternative caching strategies for nested routes
The Problem
<!-- App.vue -->
<template>
<router-view v-slot="{ Component }">
<KeepAlive>
<component :is="Component" />
</KeepAlive>
</router-view>
</template>
// router.js
const routes = [
{
path: '/parent',
component: Parent,
children: [
{
path: 'child',
component: Child // This may mount TWICE!
}
]
}
]
Symptoms:
onMountedcalled twice in child component- Duplicate API requests
- State initialization runs twice
- Console logs appear doubled
Diagnosis
Add logging to confirm the issue:
<!-- Child.vue -->
<script setup>
import { onMounted, onActivated } from 'vue'
let mountCount = 0
onMounted(() => {
mountCount++
console.log('Child mounted - count:', mountCount)
// If you see "count: 2", you have the double mount issue
})
onActivated(() => {
console.log('Child activated')
})
</script>
Workarounds
Option 1: Use useActivatedRoute Pattern
Don't use useRoute() directly with KeepAlive:
<script setup>
import { ref, onActivated } from 'vue'
import { useRoute } from 'vue-router'
// Problem: useRoute() can cause issues with KeepAlive
// const route = useRoute()
// Solution: Get route info in onActivated
const routeParams = ref({})
onActivated(() => {
const route = useRoute()
routeParams.value = { ...route.params }
})
</script>
Option 2: Avoid KeepAlive for Nested Route Parents
Only cache leaf routes, not parent layouts:
<script setup>
import { computed } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
// Only cache specific leaf routes
const cachedRoutes = computed(() => {
// Don't cache parent routes that have children
return ['UserProfile', 'UserSettings'] // Only leaf components
})
</script>
<template>
<router-view v-slot="{ Component, route: currentRoute }">
<KeepAlive :include="cachedRoutes">
<component :is="Component" :key="currentRoute.fullPath" />
</KeepAlive>
</router-view>
</template>
Option 3: Guard Against Double Initialization
Protect your component from double mount effects:
<script setup>
import { ref, onMounted } from 'vue'
const isInitialized = ref(false)
onMounted(() => {
if (isInitialized.value) {
console.warn('Double mount detected, skipping initialization')
return
}
isInitialized.value = true
// Safe to initialize
fetchData()
setupEventListeners()
})
</script>
Option 4: Use Route-Level Cache Control
<!-- App.vue -->
<script setup>
import { computed } from 'vue'
import { useRoute } from 'vue-router'
const route = useRoute()
// Define which routes should be cached in route meta
const shouldCache = computed(() => {
return route.meta.keepAlive !== false
})
</script>
<template>
<router-view v-slot="{ Component }">
<KeepAlive v-if="shouldCache">
<component :is="Component" />
</KeepAlive>
<component v-else :is="Component" />
</router-view>
</template>
// router.js
const routes = [
{
path: '/parent',
component: Parent,
meta: { keepAlive: false }, // Don't cache parent routes
children: [
{
path: 'child',
component: Child,
meta: { keepAlive: true } // Cache leaf routes
}
]
}
]
Option 5: Flatten Route Structure
Avoid nesting if possible:
// Instead of nested routes
const routes = [
// Flat structure avoids the issue
{ path: '/users', component: UserList },
{ path: '/users/:id', component: UserDetail },
{ path: '/users/:id/settings', component: UserSettings }
]
Key Points
- Known Vue Router issue - Double mount with KeepAlive + nested routes
- Watch for symptoms - Duplicate API calls, doubled logs
- Avoid caching parent routes - Only cache leaf components
- Add initialization guards - Protect against double execution
- Test thoroughly - This issue may not appear immediately