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>
145 lines
3.8 KiB
Markdown
145 lines
3.8 KiB
Markdown
# Use suspensible Prop for Nested Suspense (Vue 3.3+)
|
|
|
|
## Rule
|
|
|
|
When nesting `<Suspense>` components, use the `suspensible` prop on the inner Suspense to properly coordinate with the parent Suspense. Without this prop, nested async components may render empty nodes until resolved instead of showing fallback content.
|
|
|
|
## Why This Matters
|
|
|
|
Without the `suspensible` prop, the inner `<Suspense>` is treated as a synchronous component by the parent. This causes:
|
|
- Empty nodes appearing briefly during async resolution
|
|
- Multiple patching cycles as the component tree updates
|
|
- Inconsistent loading states that confuse users
|
|
|
|
## Bad Code
|
|
|
|
```vue
|
|
<template>
|
|
<Suspense>
|
|
<component :is="DynamicAsyncOuter">
|
|
<!-- DynamicAsyncInner renders EMPTY until resolved! -->
|
|
<component :is="DynamicAsyncInner" />
|
|
</component>
|
|
|
|
<template #fallback>
|
|
Loading...
|
|
</template>
|
|
</Suspense>
|
|
</template>
|
|
```
|
|
|
|
```vue
|
|
<template>
|
|
<Suspense>
|
|
<OuterLayout>
|
|
<!-- Inner Suspense not coordinated with parent -->
|
|
<Suspense>
|
|
<AsyncWidget />
|
|
<template #fallback>Loading widget...</template>
|
|
</Suspense>
|
|
</OuterLayout>
|
|
|
|
<template #fallback>
|
|
Loading layout...
|
|
</template>
|
|
</Suspense>
|
|
</template>
|
|
```
|
|
|
|
## Good Code
|
|
|
|
```vue
|
|
<template>
|
|
<Suspense>
|
|
<component :is="DynamicAsyncOuter">
|
|
<!-- Inner Suspense with suspensible prop -->
|
|
<Suspense suspensible>
|
|
<component :is="DynamicAsyncInner" />
|
|
<template #fallback>
|
|
<InnerLoadingState />
|
|
</template>
|
|
</Suspense>
|
|
</component>
|
|
|
|
<template #fallback>
|
|
<OuterLoadingState />
|
|
</template>
|
|
</Suspense>
|
|
</template>
|
|
```
|
|
|
|
## Complex Layout Example
|
|
|
|
```vue
|
|
<template>
|
|
<Suspense>
|
|
<DashboardLayout>
|
|
<template #sidebar>
|
|
<!-- Sidebar has its own Suspense boundary -->
|
|
<Suspense suspensible>
|
|
<AsyncSidebar />
|
|
<template #fallback>
|
|
<SidebarSkeleton />
|
|
</template>
|
|
</Suspense>
|
|
</template>
|
|
|
|
<template #main>
|
|
<!-- Main content has its own Suspense boundary -->
|
|
<Suspense suspensible>
|
|
<AsyncMainContent :key="contentKey" />
|
|
<template #fallback>
|
|
<ContentSkeleton />
|
|
</template>
|
|
</Suspense>
|
|
</template>
|
|
|
|
<template #widgets>
|
|
<!-- Each widget can load independently -->
|
|
<Suspense suspensible>
|
|
<AsyncWidgets />
|
|
<template #fallback>
|
|
<WidgetsSkeleton />
|
|
</template>
|
|
</Suspense>
|
|
</template>
|
|
</DashboardLayout>
|
|
|
|
<template #fallback>
|
|
<FullPageLoader />
|
|
</template>
|
|
</Suspense>
|
|
</template>
|
|
```
|
|
|
|
## How suspensible Works
|
|
|
|
| Configuration | Behavior |
|
|
|--------------|----------|
|
|
| No `suspensible` prop | Inner Suspense treated as sync; parent doesn't wait for inner async deps |
|
|
| `suspensible` on inner | Inner async deps bubble up to parent Suspense for coordinated loading |
|
|
|
|
## When to Use Nested Suspense
|
|
|
|
**Use nested Suspense with `suspensible`** when:
|
|
- Different page sections should show their own loading states
|
|
- You want granular control over which parts show loading indicators
|
|
- Sections can load at different speeds and should update independently
|
|
|
|
**Avoid nested Suspense** when:
|
|
- A single loading state for the whole component is sufficient
|
|
- The complexity isn't worth the UX benefit
|
|
- You're targeting Vue versions before 3.3
|
|
|
|
## Key Points
|
|
|
|
1. Always add `suspensible` prop when nesting Suspense components
|
|
2. Without `suspensible`, expect empty nodes and multiple patching cycles
|
|
3. This feature requires Vue 3.3 or later
|
|
4. Use nested Suspense boundaries strategically for better UX, not everywhere
|
|
5. Each Suspense can have its own fallback for section-specific loading states
|
|
|
|
## References
|
|
|
|
- [Vue.js Suspense Nested Documentation](https://vuejs.org/guide/built-ins/suspense#nested-suspense)
|