Files
shiftcraft/.claude/skills/vue-best-practices/references/component-async.md
2026-04-17 23:26:01 +00:00

2.5 KiB

title, impact, impactDescription, type, tags
title impact impactDescription type tags
Async Component Best Practices MEDIUM Poor async component strategy can delay interactivity in SSR apps and create loading UI flicker best-practice
vue3
async-components
ssr
hydration
performance
ux

Async Component Best Practices

Impact: MEDIUM - Async components should reduce JavaScript cost without degrading perceived performance. Focus on hydration timing in SSR and stable loading UX.

Task List

  • Use lazy hydration strategies for non-critical SSR component trees
  • Import only the hydration helpers you actually use
  • Keep loadingComponent delay near the default 200ms unless real UX data suggests otherwise
  • Configure delay and timeout together for predictable loading behavior

Use Lazy Hydration Strategies in SSR

In Vue 3.5+, async components can delay hydration until idle time, visibility, media query match, or user interaction.

BAD:

<script setup lang="ts">
import { defineAsyncComponent } from 'vue'

const AsyncComments = defineAsyncComponent({
  loader: () => import('./Comments.vue')
})
</script>

GOOD:

<script setup lang="ts">
import {
  defineAsyncComponent,
  hydrateOnVisible,
  hydrateOnIdle
} from 'vue'

const AsyncComments = defineAsyncComponent({
  loader: () => import('./Comments.vue'),
  hydrate: hydrateOnVisible({ rootMargin: '100px' })
})

const AsyncFooter = defineAsyncComponent({
  loader: () => import('./Footer.vue'),
  hydrate: hydrateOnIdle(5000)
})
</script>

Prevent Loading Spinner Flicker

Avoid showing loading UI immediately for components that usually resolve quickly.

BAD:

<script setup lang="ts">
import { defineAsyncComponent } from 'vue'
import LoadingSpinner from './LoadingSpinner.vue'

const AsyncDashboard = defineAsyncComponent({
  loader: () => import('./Dashboard.vue'),
  loadingComponent: LoadingSpinner,
  delay: 0
})
</script>

GOOD:

<script setup lang="ts">
import { defineAsyncComponent } from 'vue'
import LoadingSpinner from './LoadingSpinner.vue'
import ErrorDisplay from './ErrorDisplay.vue'

const AsyncDashboard = defineAsyncComponent({
  loader: () => import('./Dashboard.vue'),
  loadingComponent: LoadingSpinner,
  errorComponent: ErrorDisplay,
  delay: 200,
  timeout: 30000
})
</script>

Delay Guidelines

Scenario Recommended Delay
Small component, fast network 200ms
Known heavy component 100ms
Background or non-critical UI 300-500ms