Back

Cómo Cargar Componentes de Forma Diferida en Svelte

Cómo Cargar Componentes de Forma Diferida en Svelte

Tu aplicación Svelte puede ser rápida por defecto, pero si estás empaquetando un editor de texto enriquecido, una librería de gráficos o un widget complejo de dashboard en tu carga inicial de JavaScript, los usuarios están descargando código que quizás nunca utilicen. La carga diferida de componentes en Svelte soluciona esto al postergar esas importaciones pesadas hasta que realmente se necesiten.

A diferencia de React, Svelte no tiene un helper lazy() integrado. En su lugar, la carga diferida se basa directamente en la función nativa import() de JavaScript combinada con renderizado condicional. Es más manual, pero también más flexible.

Puntos Clave

  • Svelte carece de un helper lazy() integrado, por lo que la carga diferida utiliza el import() nativo de JavaScript con renderizado condicional
  • SvelteKit maneja la división de código a nivel de rutas automáticamente, pero la carga diferida a nivel de componentes sigue siendo necesaria para widgets pesados dentro de una sola página
  • Vite divide las importaciones dinámicas en chunks separados sin necesidad de configuración
  • Tres patrones principales cubren la mayoría de casos de uso: cargar bajo demanda con {#await}, precargar al pasar el cursor, y diferir hasta que el navegador esté inactivo

Por Qué la Carga Diferida a Nivel de Componentes Sigue Siendo Importante en SvelteKit

SvelteKit ya maneja la división de código a nivel de rutas automáticamente. Cada ruta obtiene su propio chunk, por lo que navegar entre páginas no infla el bundle inicial. Pero dentro de una sola página, todo lo que importas en la parte superior de un archivo .svelte se empaqueta junto y se carga por adelantado.

Ahí es donde la carga diferida a nivel de componentes se vuelve valiosa. Si una página contiene un componente de gráfico pesado, un reproductor de video o un modal que solo aparece después de la interacción del usuario, no hay razón para cargar ese código al llegar a la página.

SvelteKit se construye con Vite, que maneja las importaciones dinámicas de forma nativa. Cuando Vite ve import('./HeavyChart.svelte'), automáticamente divide ese módulo en un chunk separado. No se necesita configuración adicional.

Cómo Cargar Componentes Svelte de Forma Diferida: Patrones Principales

Carga Diferida Básica con {#await}

El enfoque más simple utiliza el bloque {#await} de Svelte directamente en la plantilla:

<!-- src/routes/+page.svelte -->
<script>
  let showChart = false;
  let chartData = [1, 2, 3];
</script>

<button onclick={() => showChart = true}>Load Chart</button>

{#if showChart}
  {#await import('$lib/components/HeavyChart.svelte')}
    <p>Loading chart...</p>
  {:then Chart}
    <Chart.default data={chartData} />
  {:catch error}
    <p>Failed to load chart: {error.message}</p>
  {/await}
{/if}

Esto funciona tanto en Svelte 4 como en Svelte 5. El bloque {:catch} es importante — las fallas de red ocurren, y los errores silenciosos hacen que la depuración sea dolorosa. En Svelte 4, cambiar componentes dinámicamente típicamente usa <svelte:component this={Component}>. En Svelte moderno, cambiar la referencia del componente también puede activar el re-renderizado directamente.

El navegador almacena en caché el módulo después de la primera importación. Los renderizados posteriores del mismo componente no desencadenan una nueva solicitud de red.

Cargar al Pasar el Cursor para un Rendimiento Percibido Más Rápido

Un patrón común es comenzar a cargar cuando el usuario señala intención — al pasar el cursor sobre un elemento disparador:

<!-- src/routes/+page.svelte -->
<script lang="ts">
  import type { Component } from 'svelte';

  let HeavyWidget: Component<{ message: string }> | null = $state(null);

  async function loadWidget() {
    if (!HeavyWidget) {
      const module = await import('$lib/components/HeavyWidget.svelte');
      HeavyWidget = module.default;
    }
  }
</script>

<div onmouseenter={loadWidget}>
  <p>Hover to preload the widget</p>
</div>

{#if HeavyWidget}
  <HeavyWidget message="Ready!" />
{/if}

Esto funciona bien para tooltips, popovers y barras laterales. El componente comienza a cargarse antes de que el usuario haga clic, por lo que para cuando interactúan, a menudo ya está en caché.

Cargar Cuando el Navegador Esté Inactivo

Para componentes no críticos que mejoran la página pero no se necesitan inmediatamente, usa requestIdleCallback:

<script lang="ts">
  import { onMount } from 'svelte';
  import type { Component } from 'svelte';

  let FeedbackWidget: Component | null = $state(null);

  onMount(() => {
    const load = () =>
      import('$lib/components/FeedbackWidget.svelte').then(
        (m) => (FeedbackWidget = m.default)
      );

    if ('requestIdleCallback' in window) {
      requestIdleCallback(load);
    } else {
      setTimeout(load, 300); // fallback para Safari
    }
  });
</script>

{#if FeedbackWidget}
  <FeedbackWidget />
{/if}

Ten en cuenta que el soporte de Safari para requestIdleCallback ha sido históricamente inconsistente, por lo que se recomienda el fallback con setTimeout.

Cuándo No Usar Carga Diferida

No todos los componentes se benefician de la carga diferida. Evítala para:

  • UI above-the-fold — navegación, secciones hero, contenido principal
  • Componentes pequeños — la sobrecarga asíncrona supera los ahorros
  • Componentes necesarios inmediatamente al montar — el parpadeo de carga degrada la UX

La división excesiva crea muchos chunks asíncronos pequeños. Los bundlers modernos como Vite manejan esto eficientemente, pero aún hay un punto de rendimientos decrecientes.

Conclusión

La carga diferida de componentes Svelte se reduce a una cosa: usar import() en lugar de una importación estática, y luego renderizar el resultado condicionalmente. La construcción basada en Vite de SvelteKit maneja la división de código automáticamente. Los tres patrones anteriores — bajo demanda, al pasar el cursor y en inactividad — cubren la mayoría de escenarios del mundo real. Elige el disparador que coincida con cuándo los usuarios realmente necesitan el componente, añade manejo de errores, y tu bundle inicial se mantiene ligero.

Preguntas Frecuentes

La importación dinámica funciona en ambas versiones. En Svelte 4, típicamente renderizas el componente cargado usando svelte:component con el atributo this. En Svelte 5, puedes usar el componente resuelto directamente como una etiqueta en la plantilla. El mecanismo de importación subyacente es el mismo en ambos casos.

Las importaciones dinámicas se ejecutan durante el SSR también, ya que Node.js las soporta. Sin embargo, la carga diferida es principalmente una optimización del lado del cliente destinada a reducir la carga inicial de JavaScript del navegador. Si un componente debe renderizarse en el servidor por razones de SEO o first-paint, una importación estática es la mejor opción.

Revisa la salida de tu build o usa un analizador de bundles para identificar chunks grandes. Los componentes que incorporan librerías de terceros pesadas como renderizadores de gráficos, editores de texto enriquecido o widgets de mapas son candidatos fuertes. Si un componente añade menos de unos pocos kilobytes, la sobrecarga de una solicitud de red adicional probablemente supera los ahorros.

No. El navegador almacena en caché el módulo después de que la primera importación dinámica se resuelva. En renderizados posteriores, el módulo en caché se devuelve inmediatamente, por lo que el estado de carga aparece solo en la primera obtención. También puedes precargar el módulo al pasar el cursor o durante el tiempo de inactividad para eliminar el retraso visible por completo.

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay