El Lazy Loading tradicionalmente se aplicaba a nivel de rutas. Si entrabas a una ruta, cargabas todo el módulo. ¿Pero qué pasa si tienes un componente muy pesado (como un gráfico complejo o un mapa) que está visible solo si el usuario hace scroll hacia abajo?
Aquí entra @defer. Esta sintaxis permite diferir la carga de partes específicas de tu plantilla de manera declarativa.
Sintaxis Básica y Bloques
@defer (on viewport) {
<heavy-chart-component />
} @loading (minimum 1s) {
<p>Cargando gráfico...</p>
} @placeholder {
<img src="chart-placeholder.png" alt="Placeholder" />
} @error {
<p>Hubo un error al cargar el componente.</p>
}
Desglose de los bloques:
- @defer: El contenido principal que se cargará perezosamente.
- @placeholder: Lo que se muestra antes de que comience la carga.
- @loading: Lo que se muestra mientras se descarga el código JS.
- @error: Si falla la red o la carga del script.
Triggers (Disparadores)
on idle: (Por defecto) Se carga cuando el navegador está inactivo.on viewport: Se carga cuando el placeholder entra en la pantalla visible.on interaction: Se carga cuando el usuario hace clic o interactúa.on hover: Se carga al pasar el mouse por encima.on immediate: Se carga inmediatamente en un chunk separado.when condition: Se carga cuando una expresión booleana sea verdadera.
Exemplo Práctico: Dashboard con widgets pesados
<app-header />
<app-kpi-cards />
@defer (on viewport) {
<app-interactive-map />
} @placeholder {
<div class="h-96 bg-gray-100 animate-pulse rounded-xl"></div>
}
@defer (on viewport) {
<app-chart-dashboard />
} @loading (minimum 500ms) {
<div class="flex items-center gap-2">
<spinner /> Cargando gráficos...
</div>
}
@defer (on interaction) {
<app-data-table />
} @placeholder {
<button class="btn">Haz clic para cargar la tabla completa</button>
}
Prefetching: Anticipar la carga
@defer (on interaction; prefetch on hover) {
<app-heavy-editor />
} @placeholder {
<button>Abrir editor</button>
}
Impacto en Core Web Vitals
Usar @defer correctamente mejora drásticamente:
- LCP: Se reduce porque el contenido visible carga primero.
- TBT: Menos JS para parsear al inicio.
- FID: El hilo principal queda libre más rápido.
En aplicaciones reales, se han visto reducciones del 30-50% en el bundle inicial.