Back

Mejores prácticas para trabajar con Svelte

Mejores prácticas para trabajar con Svelte

Si ya has superado los conceptos básicos de Svelte y has comenzado a construir aplicaciones reales, probablemente hayas notado que la documentación oficial cubre qué hacen las cosas, pero no siempre cuándo o por qué usarlas. Este artículo se centra en las mejores prácticas de Svelte 5 que mejoran la mantenibilidad, el rendimiento y la claridad en código de producción, asumiendo que ya entiendes cómo funcionan los componentes y la reactividad.

Puntos clave

  • Usa $state solo cuando un valor impulse actualizaciones de la UI, y recurre a $state.raw cuando reemplaces valores en lugar de mutarlos.
  • Prefiere $derived sobre $effect para valores computados; reserva $effect para sincronizar con sistemas externos.
  • Evita el estado a nivel de módulo en entornos SSR. Usa la API de contexto de Svelte con $state basado en clases para un estado compartido tipado y limitado al alcance de la petición.
  • En SvelteKit, usa +page.server.js para datos de página del lado del servidor y +server.js para endpoints de API independientes.
  • Adopta la sintaxis moderna de Svelte 5 (onclick, {#snippet}, $props()) en lugar de patrones heredados en código nuevo.

Runes de Svelte 5: úsalas con precisión

Las runes de Svelte 5 son el modelo principal de reactividad, y usarlas correctamente importa más que usarlas en todas partes.

Recurre a $state solo cuando una variable necesite impulsar actualizaciones de la UI. Las variables simples son más económicas y más claras para todo lo demás.

Cuando tu estado es un objeto o array grande que se reemplaza en lugar de mutarse, usa $state.raw en su lugar:

// ❌ Sobrecarga innecesaria de proxy para datos de API que solo reasignarás
let users = $state(await fetchUsers());

// ✅ Sin costo de proxy cuando estás reemplazando, no mutando
let users = $state.raw(await fetchUsers());

Usa $state cuando necesites mutar propiedades anidadas directamente (como cart.items[0].quantity++). Usa $state.raw cuando estés intercambiando el valor completo.

Prefiere $derived sobre $effect para valores computados

Este es uno de los errores más comunes en el desarrollo moderno con Svelte:

let num = $state(0);

// ❌ Evítalo — crea un efecto secundario innecesario
let square = $state(0);
$effect(() => { square = num * num; });

// ✅ Correcto — declarativo y con seguimiento de dependencias
let square = $derived(num * num);

$effect es una vía de escape. Resérvalo para sincronizar con sistemas externos (como D3), y considera {@attach} para integraciones a nivel del DOM donde encaje naturalmente.

Trata las props como dinámicas

Los valores derivados de props deben usar $derived, no una asignación simple:

let { type } = $props();

// ✅ Se mantiene sincronizado cuando `type` cambia
let color = $derived(type === 'danger' ? 'red' : 'green');

Contexto tipado en lugar de módulos compartidos

Para el estado compartido entre un subárbol de componentes, prefiere la API de contexto de Svelte sobre el estado a nivel de módulo. El estado de módulo persiste entre peticiones en entornos SSR, lo que puede provocar que los datos se filtren entre usuarios.

El patrón moderno usa una clase con campos $state:

// lib/theme.svelte.ts
import { getContext, setContext } from 'svelte';

class ThemeContext {
  current = $state('light');

  toggle() {
    this.current = this.current === 'light' ? 'dark' : 'light';
  }
}

const KEY = Symbol('theme');

export const setTheme = () => setContext(KEY, new ThemeContext());

export const getTheme = () => getContext<ThemeContext>(KEY);

Esto te brinda seguridad de tipos, estado reactivo y un alcance adecuado para SSR en un solo patrón.

Carga de datos en SvelteKit: eligiendo el patrón correcto

Un punto común de confusión en SvelteKit es cuándo usar +page.server.js frente a +server.js:

EscenarioUsar
Obtener datos para una página con SSR o acceso solo del servidor+page.server.js con load()
Construir un endpoint de API para uso externo+server.js
Datos solo del cliente después de la hidrataciónonMount + fetch

Para datos de página que necesiten acceso al servidor, secretos o SSR, +page.server.js suele ser la opción predeterminada correcta. Se ejecuta en el servidor, mantiene los secretos fuera del cliente y se integra limpiamente con las form actions de SvelteKit para mejora progresiva.

Pequeñas victorias prácticas

Los bloques {#each} con clave previenen errores sutiles de reciclaje del DOM. Siempre usa como clave un ID único y estable, nunca el índice.

$inspect.trace está infrautilizado para depurar la reactividad. Colócalo al inicio de cualquier $effect o $derived.by para ver exactamente qué dependencia provocó una nueva ejecución.

Snippets en lugar de slots para fragmentos de marcado reutilizables. Los snippets se componen mejor y pueden pasarse como props, haciendo las APIs de los componentes más limpias.

Evita la sintaxis heredada en código nuevo. Reemplaza on:click con onclick, <slot> con {#snippet}, y export let con $props(). Estos patrones se alinean con las convenciones modernas de Svelte 5 y el comportamiento actual del compilador.

Conclusión

Svelte 5 recompensa la moderación. Cuanto más precisamente delimites el alcance de la reactividad, usando $state solo donde sea necesario, $derived en lugar de $effect, y contexto en lugar de globales de módulo, más predecible y eficiente será tu aplicación. Empieza con la primitiva reactiva más simple que resuelva el problema, y recurre a herramientas más potentes solo cuando las más simples realmente se queden cortas.

Preguntas frecuentes

Usa $state.raw cuando planees reemplazar el valor completo en lugar de mutar partes de él, como al almacenar respuestas de API obtenidas o arrays grandes que reasignas íntegramente. Omite la sobrecarga del proxy reactivo, lo que mejora el rendimiento para grandes conjuntos de datos. Usa $state simple cuando necesites reactividad granular para mutaciones anidadas, como actualizar un elemento dentro de un array.

$derived es declarativo, rastrea automáticamente sus dependencias y produce un valor de solo lectura que se mantiene sincronizado. $effect se ejecuta de forma imperativa como un efecto secundario y es más difícil de razonar, ya que puede introducir errores de temporización y nuevas ejecuciones innecesarias. Reserva $effect para sincronizar con sistemas fuera de la reactividad de Svelte, como bibliotecas de terceros, APIs de canvas o trabajo manual con el DOM.

No en entornos SSR como SvelteKit. El estado a nivel de módulo se comparte entre todas las peticiones que maneja el servidor, lo que puede filtrar los datos de un usuario a la sesión de otro. Usa la API de contexto de Svelte con setContext y getContext, idealmente respaldada por una clase que contenga campos $state. Esto delimita el alcance del estado por petición y por árbol de componentes, preservando la reactividad y la seguridad de tipos.

Usa +page.server.js cuando los datos pertenezcan a una página específica y se beneficien de SSR, SEO, acceso del lado del servidor o form actions. Usa +server.js cuando necesites un endpoint HTTP independiente, como una API JSON consumida por clientes externos, webhooks o llamadas fetch que no provienen de una página. Si los datos solo son renderizados por una página y necesitan capacidades del lado del servidor, +page.server.js suele ser la mejor opción predeterminada.

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