¿Qué es Svelte?
Svelte es un framework de componentes con un giro particular: es un compilador. En lugar de enviar un runtime que interprete tus componentes en el navegador, Svelte los analiza en tiempo de compilación y genera JavaScript puro que actualiza el DOM directamente. No existe un virtual DOM y casi no hay código del framework en el bundle final.
Este diseño cambia la experiencia del desarrollador. La reactividad es parte del lenguaje, los estilos están encapsulados (scoped) por defecto y las transiciones vienen integradas, por lo que los componentes resultan ser muy breves. La contrapartida es que necesitas un paso de compilación, pero con el tooling moderno, esto ya se da por sentado.
Componentes de archivo único
Un componente de Svelte es un archivo .svelte con un bloque de script, marcado y estilos opcionales con alcance limitado (scoped).
<!-- Card.svelte -->
<script>
let { title, children } = $props();
</script>
<article class="card">
<h3>{title}</h3>
{@render children?.()}
</article>
<style>
.card {
border-radius: 1rem;
padding: 1.5rem;
}
</style>
Los estilos en un componente tienen un alcance limitado a este por defecto, por lo que la regla .card no puede filtrarse. $props() lee las props pasadas por el padre, y los snippets (children) permiten que un padre pase marcado a un hijo.
Reactividad con runes
Svelte 5 introdujo los runes, primitivas explícitas que hacen que la reactividad sea predecible. $state declara el estado reactivo, $derived computa valores y $effect ejecuta efectos secundarios.
<!-- Search.svelte -->
<script>
let query = $state("");
let results = $state([]);
let hasResults = $derived(results.length > 0);
$effect(() => {
if (!query) return;
const controller = new AbortController();
fetch(`/api/search?q=${query}`, { signal: controller.signal })
.then((r) => r.json())
.then((data) => (results = data))
.catch(() => {});
return () => controller.abort();
});
</script>
<input bind:value={query} placeholder="Search" />
{#if hasResults}
<ul>
{#each results as item (item.id)}
<li>{item.name}</li>
{/each}
</ul>
{/if}
Los runes también funcionan en archivos .svelte.js y .svelte.ts, por lo que puedes extraer la lógica reactiva en módulos reutilizables de la misma manera que React utiliza los custom hooks.
Props, eventos y snippets
Las props fluyen hacia abajo y se declaran con $props(). En lugar de un sistema de eventos especial, Svelte 5 utiliza callback props para la comunicación de hijo a padre.
<!-- Child.svelte -->
<script>
let { label, onselect } = $props();
</script>
<button onclick={() => onselect(label)}>{label}</button>
<!-- Parent.svelte -->
<Child label="Save" onselect={(value) => save(value)} />
Los snippets reemplazan a los slots para regiones de marcado reutilizables, y {@render} los inserta donde desees.
Flujo de control
Svelte tiene bloques de plantilla dedicados para condicionales y bucles, y el bloque #each admite una expresión con clave (keyed expression) para actualizaciones eficientes.
<!-- list.svelte -->
{#if users.length > 0}
<ul>
{#each users as user (user.id)}
<li>{user.name}</li>
{/each}
</ul>
{:else}
<p>No users yet.</p>
{/if}
Debido a que el compilador conoce la estructura, estos bloques generan operaciones de DOM específicas en lugar de un proceso de reconciliación genérico.
Stores y estado compartido
Para el estado compartido entre muchos componentes, Svelte proporciona stores: un store writable mantiene un valor y notifica a los suscriptores, mientras que readable y derived cubren otros casos.
// counter.js
import { writable, derived } from "svelte/store";
export const count = writable(0);
export const double = derived(count, ($count) => $count * 2);
<!-- Display.svelte -->
<script>
import { count, double } from "./counter.js";
</script>
<p>{$count} doubled is {$double}</p>
El prefijo $ se encarga de suscribirse y cancelar la suscripción automáticamente por ti. Con runes, un módulo .svelte.js que exporte $state puede lograr lo mismo sin la API de stores, algo que muchos proyectos nuevos prefieren para valores globales de la aplicación.
Transiciones y animaciones
El movimiento ya viene integrado. Las directivas transition, animate y in/out añaden movimiento sin necesidad de una librería externa.
<!-- toast.svelte -->
<script>
import { fade, fly } from "svelte/transition";
let visible = $state(false);
</script>
<button onclick={() => (visible = !visible)}>Toggle</button>
{#if visible}
<div transition:fly={{ y: 20, duration: 200 }}>
Saved!
</div>
{/if}
Debido a que las transiciones se compilan, son eficientes y compatibles con tree-shaking, además de respetar la preferencia de movimiento reducido del usuario cuando utilizas los helpers integrados.
SvelteKit
SvelteKit es el framework oficial para aplicaciones. Añade enrutamiento basado en archivos, renderizado en el servidor, carga de datos y acciones de formulario sobre Svelte.
src/routes/
├── +page.svelte # a page
├── +layout.svelte # shared layout
├── about/+page.svelte # /about
└── blog/[slug]/+page.js # load data for /blog/:slug
Si estás construyendo algo más que un widget, SvelteKit es el punto de partida recomendado. Se encarga de las convenciones que toda aplicación real necesita para que puedas centrarte en las funcionalidades.
Mejores prácticas
- Usa runes (
$state,$derived,$effect) en el código nuevo. - Prefiere
$derivedpara valores computados y reserva$effectpara efectos secundarios. - Mantén los componentes pequeños y extrae la lógica reutilizable en módulos
.svelte.js. - Usa bloques
{#each}con claves cuando los elementos puedan cambiar de orden. - Mantén los estilos con scope por defecto y evita
:globala menos que sea necesario. - Comparte el estado entre componentes mediante stores o un módulo reactivo.
- Inicia aplicaciones nuevas con SvelteKit en lugar de configurar el build por tu cuenta.
Errores comunes
- Usar
$effectpara calcular un valor que$deriveddebería gestionar. - Olvidar la key en
{#each}y romper las actualizaciones de las listas. - Mutar una propiedad anidada de un objeto
$statede manera que se evite la reactividad en patrones antiguos. - Recurrir a un store global cuando el estado local sería suficiente.
- Asumir que Svelte no tiene runtime en absoluto; tiene uno pequeño.
- Ignorar la accesibilidad porque el compilador facilita la escritura rápida del markup.
Próximos pasos
Svelte es una forma rápida y elegante de construir interfaces, y SvelteKit lo convierte en un framework de aplicaciones completo. Compara el enfoque basado en compilador con React y Vue, y mantén tus conocimientos de JavaScript al día. Después, construye una aplicación pequeña con un store y una transición para notar la diferencia.