feat: Complete fleet — 94 skills across 10+ domains
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>
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user