Was ist Svelte?
Svelte ist ein Komponenten-Framework mit einem besonderen Clou: Es ist ein Compiler. Anstatt eine Runtime auszuliefern, die deine Komponenten im Browser interpretiert, analysiert Svelte diese zur Build-Zeit und generiert einfaches JavaScript, das das DOM direkt aktualisiert. Es gibt kein virtuelles DOM und fast keinen Framework-Code im finalen Bundle.
Dieses Design verändert die Developer Experience. Reaktivität ist Teil der Sprache, Styles sind standardmäßig scoped und Transitions sind integriert, wodurch die Komponenten sehr kompakt bleiben. Der Kompromiss besteht darin, dass ein Build-Schritt erforderlich ist, was jedoch durch modernes Tooling heutzutage selbstverständlich ist.
Single-file components
Eine Svelte-Komponente ist eine .svelte-Datei mit einem Script-Block, Markup und optionalen scoped Styles.
<!-- 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>
Styles in einer Komponente sind standardmäßig auf diese beschränkt (scoped), sodass die .card-Regel nicht nach außen dringen kann. $props() liest die vom Parent übergebenen Props, und Snippets (children) ermöglichen es einem Parent, Markup an ein Child zu übergeben.
Reaktivität mit Runes
Svelte 5 hat Runes eingeführt – explizite Primitive, die Reaktivität vorhersagbar machen. $state deklariert reaktiven State, $derived berechnet Werte und $effect führt Side Effects aus.
<!-- 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}
Runes funktionieren auch in .svelte.js und .svelte.ts Dateien. So können Sie reaktive Logik in wiederverwendbare Module auslagern, ähnlich wie React es mit Custom Hooks macht.
Props, Events und Snippets
Props fließen nach unten und werden mit $props() deklariert. Anstelle eines speziellen Event-Systems nutzt Svelte 5 Callback-Props für die Kommunikation vom Kind- zum Eltern-Element.
<!-- Child.svelte -->
<script>
let { label, onselect } = $props();
</script>
<button onclick={() => onselect(label)}>{label}</button>
<!-- Parent.svelte -->
<Child label="Save" onselect={(value) => save(value)} />
Snippets ersetzen Slots für wiederverwendbare Markup-Bereiche, und {@render} fügt sie dort ein, wo sie benötigt werden.
Kontrollfluss
Svelte bietet dedizierte Template-Blöcke für Bedingungen und Schleifen, und der #each-Block unterstützt einen keyed expression für effiziente Updates.
<!-- 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}
Da der Compiler die Struktur kennt, generieren diese Blöcke gezielte DOM-Operationen anstelle eines generischen Reconciliation-Passes.
Stores und shared state
Für Zustände, die über viele Komponenten hinweg geteilt werden, bietet Svelte Stores: Ein writable Store hält einen Wert und benachrichtigt Abonnenten, während readable und derived andere Anwendungsfälle abdecken.
// 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>
Das $ Präfix übernimmt das Abonnieren und Deabonnieren automatisch für dich. Mit Runes kann ein .svelte.js Modul, das $state exportiert, dasselbe erreichen, ohne die Store-API zu nutzen – was viele neue Projekte für anwendungsweite Werte bevorzugen.
Transitionen und Animationen
Bewegungen sind bereits integriert. Die Direktiven transition, animate und in/out ermöglichen Animationen ohne eine externe Library.
<!-- 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}
Da Transitionen kompiliert werden, sind sie effizient und tree-shakeable. Zudem berücksichtigen sie die „Reduced Motion“-Einstellungen des Nutzers, sofern die integrierten Helper verwendet werden.
SvelteKit
SvelteKit ist das offizielle Application Framework. Es ergänzt Svelte um dateibasiertes Routing, Server Rendering, Data Loading und Form Actions.
src/routes/
├── +page.svelte # a page
├── +layout.svelte # shared layout
├── about/+page.svelte # /about
└── blog/[slug]/+page.js # load data for /blog/:slug
Wenn Sie mehr als nur ein Widget bauen, ist SvelteKit der empfohlene Startpunkt. Es übernimmt die Konventionen, die jede echte App benötigt, sodass Sie sich voll und ganz auf die Features konzentrieren können.
Best Practices
- Verwende Runen (
$state,$derived,$effect) in neuem Code. - Bevorzuge
$derivedfür berechnete Werte und reserviere$effectfür Side Effects. - Halte Komponenten klein und extrahiere wiederverwendbare Logik in
.svelte.js-Module. - Verwende keyed
{#each}-Blöcke, wenn sich die Reihenfolge von Elementen ändern kann. - Nutze standardmäßig scoped Styles und vermeide
:global, sofern nicht unbedingt erforderlich. - Teile State zwischen Komponenten über Stores oder ein reaktives Modul.
- Starte neue Apps mit SvelteKit, anstatt den Build-Prozess selbst aufzusetzen.
Häufige Fehler
- Verwendung von
$effectzur Berechnung eines Wertes, den$derivedübernehmen sollte. - Vergessen des Keys in
{#each}, was zu Fehlern bei Listen-Updates führt. - Mutation einer verschachtelten Eigenschaft eines
$state-Objekts auf eine Weise, die in älteren Mustern die Reaktivität umgeht. - Rückgriff auf einen globalen Store, obwohl ein lokaler State ausreichen würde.
- Die Annahme, dass Svelte überhaupt keine Runtime besitzt – es gibt eine kleine.
- Vernachlässigung der Barrierefreiheit, weil der Compiler das Schreiben von Markup so einfach und schnell macht.
Wie geht es weiter?
Svelte ist ein schneller und eleganter Weg, um Interfaces zu bauen, und SvelteKit macht daraus ein vollständiges Application Framework. Vergleiche den Compiler-Ansatz mit React und Vue und halte dein JavaScript auf dem neuesten Stand. Baue anschließend eine kleine App mit einem Store und einer Transition, um den Unterschied selbst zu erleben.