Aus Linux-Magazin 07/2024

Web-Apps programmieren mit dem Javascript-Framework Svelte

© Aleksei Deviatov / 123RF.com

Mit dem Javascript-Framework Svelte bauen Sie auf einfache Weise leistungsfähige Webanwendungen. Dazu genügen solide Grundkenntnisse in Javascript, HTML und CSS.

Das unter der MIT-Lizenz entwickelte Open-Source-Framework Svelte [1] ist nicht nur ein Web-Framework, sondern bringt auch einen Compiler mit, der den spezifischen Svelte-Code in reines Javascript übersetzt. Als Resultat erhalten Sie je eine Javascript, HTML- und CSS-Datei, die Sie auf einen Webserver laden. Die Webanwendung läuft dann ohne weiteres Zutun und ohne Framework-spezifischen Code. Das ergibt schlanke und schnelle Applikationen für das Web. Svelte positioniert sich damit als leichtgewichtige Alternative zu den drei anderen großen Javascript-Frameworks Angular, React und Vue.js.

Svelte einrichten

Svelte kommt häufig zum Erstellen sogenannter Single Page Applications (SPAs) zum Einsatz. Diese Art von Webanwendung besteht lediglich aus einem HTML-Dokument, das die Inhalte dynamisch nachlädt, meist per Javascript.

Um Svelte zu installieren, benötigen Sie die Javascript-Laufzeitumgebung Node.js. Unter Ubuntu und dessen Derivaten spielen Sie sie mit »sudo apt install nodejs« ein. Zusätzlich benötigen Sie den Node Package Manager Npm von Node.js, den das Kommando »sudo apt install npm« installiert. Npm lässt sich mit den Paketmanagern Pip für Python- und Composer für PHP-Projekte vergleichen. Mit »node -v« und »npm -v« prüfen Sie, in welcher Version Node.js und Npm installiert wurden und ob alles ordnungsgemäß eingerichtet ist.

Zusätzlich ist für die Svelte-Entwicklung ein Codeeditor oder eine Entwicklungsumgebung sinnvoll. Geeignete Kandidaten wären etwa der kostenfreie Editor Visual Studio Code (VSCode [2]) von Microsoft oder dessen vollständig kompatibles Open-Source-Pendant VSCodium [3]. Der Unterschied besteht darin, dass VSCodium keine Nutzungsdaten an Microsoft sendet. Zudem ist nicht nur der Quellcode komplett frei, sondern auch die Binärpakete. Anleitungen zum Installieren von VSCode [4] und VSCodium [5] finden sich online.

Für beide Entwicklungsumgebungen gibt es eine offizielle Erweiterung namens Svelte for VSCode, die Sie ebenfalls einrichten sollten, weil sie Syntax-Highlighting und Code Completion für die Svelte-Syntax mitbringt. Zur Installation drücken Sie in beiden Editoren [Strg]+[Umschalt]+[X], geben “Svelte” in das Suchfeld ein, wählen die Extension aus und klicken abschließend auf die Schaltfläche Install.

Erste Schritte

Zuerst erstellen Sie ein lokales Verzeichnis für das Svelte-Projekt, zum Beispiel »Svelte-Projekte/«. Danach wechseln Sie im Terminal dorthin und legen mit »npm init vite« ein Svelte-Grundgerüst an. Alternativ generiert der Befehl »npm create svelte@latest Projekt« ein vollumfängliches SvelteKit-Projekt [6] inklusive fortgeschrittener Features wie Routing [7]. Für das hier angepeilte einfache Frontend-Beispiel genügt jedoch das vom Build-Tool Vite [8] erzeugte einfache Grundgerüst.

Nach dem Ausführen des Kommandos fragt Svelte nach dem Projekt- und Paketnamen, der in diesem Fall »converter« lautet, denn in unserem Beispiel geht es um einen Währungsrechner. Bei der Abfrage des zu verwendenden Frameworks wählen Sie Svelte aus, danach noch Javascript als Programmiersprache. Theoretisch könnten Sie stattdessen Svelte-Apps mit der aufstrebenden Skriptsprache Typescript programmieren, der Einfachheit halber setzt unser Beispiel aber auf Javascript.

Nun wechseln wir mit »cd converter« in das Projektverzeichnis und installieren mit dem Befehl »npm install« die notwendigen Pakete und Abhängigkeiten – fertig ist die Svelte-Projektstruktur. Später lässt sich mit »npm run dev« im Projektverzeichnis ein lokaler Entwicklungs-Server starten, mit dessen Hilfe Sie die Svelte-App testen. Sie erreichen ihn unter »localhost:5173«, mit [Strg]+[C] stoppen Sie ihn bei Bedarf wieder. Abbildung 1 zeigt die Startseite einer neuen Svelte-App.

Abbildung 1: Die Startseite eines Projekt-Templates.

Abbildung 1: Die Startseite eines Projekt-Templates.

Projektstruktur

Sehen wir uns nun die wichtigsten erzeugten Verzeichnisse und Dateien etwas genauer an. Als zentrale Datei jeder Svelte-App fungiert eine »index.html« wie die aus Listing 1.

Listing 1

index.html (Vite)

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Svelte</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="/src/main.js"></script>
  </body>
</html>

Hier ist der »div«-Tag mit der ID »app« besonders interessant: An dieser Stelle wird die Svelte-Applikation eingebunden. Außerdem referenziert die nächste Zeile die Datei »main.js« aus dem Ordner »src/«. Sie dient als Einstiegspunkt jeder Svelte-Anwendung und wird beim Ausführen der Webanwendung als Erstes gesucht.

Eine fertige Svelte-Anwendung erzeugen Sie mit dem Befehl »npm run build« im Projektordner, der das Verzeichnis »dist/« im Projektbaum generiert. Darin befinden sich eine neue Datei »index.html« (nicht zu verwechseln mit »index.html«, die Vite anfangs im Root-Verzeichnis erzeugt hat). Im Unterordner »assets/« liegen je eine CSS- und Javascript-Datei. Die Dateinamen erzeugt das Kompilieren stets dynamisch neu.

Für die »index.html« im Verzeichnis »dist/« wurde die gesamte Funktionalität der Svelte-App übersetzt, Zeile 8 von Listing 2 bindet sie als Javascript-Datei ein. Zeile 9 packt und integriert das Styling der App in Form einer CSS-Datei. Jedes Ausführen des Befehls »npm run build« überschreibt diese Dateien und erzeugt die Svelte-App neu.

Listing 2

index.html (Build)

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Svelte</title>
    <script type="module" crossorigin src="/assets/index-dacb742d.js"></script>
    <link rel="stylesheet" href="/assets/index-0a4a4f95.css">
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

Theoretisch könnten Sie den Ordner »dist« direkt auf einen Webserver hochladen, die Webanwendung würde bereits funktionieren. Der Ordner, mit dem wir uns im Folgenden am meisten beschäftigen werden, ist das Verzeichnis »src/«. Dort findet sich der eigentliche Code. Als Dreh- und Angelpunkt sowie Hauptkomponente einer Svelte-App fungiert hier die Datei »App.svelte«.

Svelte-Komponenten

Eine Svelte-App umfasst mehrere Komponenten. Dabei handelt es sich vereinfacht ausgedrückt um Dateien mit der Endung ».svelte«, die unter anderem den spezifischen Svelte-Code und oft auch Daten enthalten. Sie lassen sich mit den Komponenten in Angular, React oder Vue.js vergleichen.

Eine Svelte-Komponente besteht aus drei Sektionen: Javascript-Code im »script«-Tag für die Logik, HTML-Code im »main«-Tag für die Struktur und CSS-Code im »style«-Tag für die Gestaltung. Die Reihenfolge dieser Code-Blöcke spielt dabei keine Rolle (Abbildung 2).

Abbildung 2: Sektionen einer Svelte-Komponente.

Abbildung 2: Sektionen einer Svelte-Komponente.

Eine Komponente kann aus mehreren anderen Komponenten bestehen. Um die Funktionen einer Komponente in einer anderen zu nutzen, müssen Sie sie mit »import« importieren (Listing 3, erste zwei Zeilen).

Den Aufbau der Beispiel-Anwendung veranschaulicht Abbildung 3. Jede Komponente übernimmt dabei eine spezielle Funktion. Dank des modularen Aufbaus lassen sich Svelte-Apps einfach warten und Komponenten wiederverwenden. Bei größeren Projekten liegen die Komponenten meist in einem separaten Unterordner, der oft »components/« heißt.

Abbildung 3: Struktur der Beispiel-App.

Abbildung 3: Struktur der Beispiel-App.

Die Datei »app.css« nimmt globale CSS-Anweisungen auf, die für die gesamte Webanwendung gelten. CSS-Anweisungen in einer Svelte-Komponente haben aber Vorrang vor denen in der »app.css«. Der CSS-Code im »style«-Block einer Komponente gilt nur innerhalb dieser Komponente, es lässt sich dort nichts dynamisch zur Laufzeit ändern.

Main.js

Als Nächstes sehen wir uns die Datei »main.js« genauer an (Listing 3). Die ersten beiden Zeilen importieren die Dateien »app.css« und »App.svelte«. Die zweite Zeile legt die Hauptkomponente fest, in der Regel die Datei »App.svelte«. Zeile 3 initialisiert die App, wobei »new App« ein Objekt der App erzeugt. Der Parameter »target« (Zeile 4) stellt das Ziel der Svelte-App dar. Er legt fest, wo der Inhalt der Svelte-Komponenten zu rendern ist – hier im Tag mit der ID »app« in der Datei »index.html« im Root-Verzeichnis. Die letzte Zeile exportiert die Anwendung noch.

Listing 3

main.js

import './app.css'
import App from './App.svelte'
const app = new App({
  target: document.getElementById('app'),
})
export default app

Währungsrechner

Zum Vertiefen der Svelte-Kenntnisse soll ein Währungsrechner als Beispiel dienen. Die einfache Webapplikation besteht aus drei Komponenten, den Dateien »App.svelte«, »Converter.svelte« und »Footer.svelte«.

Die Datei »App.svelte« dient in der Regel als erste Komponente, die in verschachtelter Form die anderen Svelte-Komponenten aufnimmt. Man spricht auch von der Elternkomponente »App.svelte« und den Kindkomponenten »Converter.svelte« und »Footer.svelte«.

Beim Anlegen einer neuen Svelte-App wird die Datei »App.svelte« immer frisch erzeugt. Sie löschen den aktuellen Inhalt dieser Hauptkomponente und fügen stattdessen den Code aus Listing 4 ein. Der erste Skript-Block importiert die beiden anderen Komponenten und macht sie damit verfügbar.

Listing 4

App.svelte

<script>
  import Converter from './Converter.svelte'
  import Footer from './Footer.svelte'
</script>
<main>
  <Converter />
  <Footer />
</main>
<style>
</style>

Auf das Schlüsselwort »import« folgt jeweils die Bezeichnung der Komponente, mit der sie sich im Code ansprechen lässt. Es ist Konvention, für diese Bezeichnung den Namen der zu importierenden Svelte-Datei zu verwenden. Auf das Schlüsselwort »from« folgt der Pfad zur Komponente.

Die Tags »<Converter />« und »<Footer />« im HTML-Bereich der Root-Komponente »App.svelte« integrieren schließlich die Converter- respektive Footer-Komponente. Die Komponenten haben damit eigene Tags bekommen, wie man sie von HTML her kennt. Diese gesonderten Svelte-Tags erkennen Sie daran, dass sie mit einem Großbuchstaben beginnen.

Bei der Converter-Komponente (Abbildung 4) handelt es sich um den eigentlichen Währungsrechner, die Footer-Komponente dient lediglich zur Ausgabe der berechneten Werte.

Abbildung 4: Die grafische Oberfl&auml;che des W&auml;hrungsrechners.

Abbildung 4: Die grafische Oberfläche des Währungsrechners.

Stores

Damit Sie Zugriff auf Variablen einer anderen Komponente erhalten, deklarieren Sie die Variablen im »script«-Tag einer Komponente und exportieren sie mit dem Schlüsselwort »export«. Alle anderen Komponenten, die diese Komponente dann importieren, haben so Zugriff auf die exportierten Variablen, die sogenannten Props).

Bei komplexeren Anwendungen mit vielen Komponenten und Variablen lässt sich das Prozedere mit sogenannten Stores vereinfachen. Sie erleichtern die Kommunikation zwischen den Komponenten, indem sie alle Variablen an einer zentralen Stelle außerhalb aller Komponenten speichern und verfügbar machen. Sämtliche Komponenten haben dann Zugriff auf diese Variablen. Ändert eine Komponente eine solche Variable, wird deren Wert synchron in den anderen Komponenten ebenfalls geändert, was man als Reaktivität bezeichnet. Dazu legen Sie die fraglichen Daten in einer separaten Javascript-Datei namens »store.js« ab (Listing 5), die sich im Verzeichnis »src/« befinden sollte.

In Svelte gibt es drei verschiedene Store-Varianten. Im Readable-Store legt Svelte Werte nur lesbar initial ab. Daneben gibt es noch den Derived-Store, bei dem ein neuer Store aus einem bestehenden abgeleitet wird. Der meistgenutzte Store, den auch unser Beispiel nutzt, ist der Writable-Store. Dort können alle Komponenten Variablen lesen und schreiben.

Listing 5

store.js

import { writable } from "svelte/store";
export const convertfrom = writable("EUR");
export const convertto = writable("USD");
export const data = writable([]);
export const amount = writable(0);
export const total = writable(0);
export const countries = writable([
  { id: 1, name: "AUD", desc: "Australischer Dollar", flag: "http://www.geonames.org/flags/l/au.gif" },
  { id: 2, name: "BRL", desc: "Brasilianischer Real", flag: "http://www.geonames.org/flags/l/br.gif" },
  { id: 3, name: "BGN", desc: "Bulgarischer Lew", flag: "http://www.geonames.org/flags/l/bg.gif" },
  { id: 4, name: "DKK", desc: "Dänische Krone", flag: "http://www.geonames.org/flags/l/dk.gif" },
  { id: 5, name: "EUR", desc: "Euro", flag: "http://www.geonames.org/flags/l/de.gif" },
  { id: 6, name: "INR", desc: "Indische Rupie", flag: "http://www.geonames.org/flags/l/in.gif" },
  { id: 7, name: "CAD", desc: "Kanadischer Dollar", flag: "http://www.geonames.org/flags/l/ca.gif" },
  { id: 8, name: "GBP", desc: "Pfund Sterling", flag: "http://www.geonames.org/flags/l/uk.gif" },
  { id: 9, name: "CHF", desc: "Schweizer Franken", flag: "http://www.geonames.org/flags/l/ch.gif" },
  { id: 10, name: "CZK", desc: "Tschechische Krone", flag: "http://www.geonames.org/flags/l/cz.gif" },
  { id: 11, name: "USD", desc: "US Dollar", flag: "http://www.geonames.org/flags/l/us.gif" },
  ]);

Die erste Zeile von Listing 5 importiert solch einen Store. Alle mit der Anweisung »export« exportierten Variablen in der Datei »store.js« spiegeln jeweils einen eigenen Store wider. In diesem Fall gibt es folglich sechs Stores. Den initialen Wert eines solchen Stores geben Sie nach dem Wort »writable« in Klammern an. So handelt es sich bei »writable(“EUR”)« um den Store mit dem initialen String »EUR«, der für die Ausgangswährung steht.

Daneben gibt es noch den Store »convertto«, der die Währung angibt, in die umgerechnet werden soll. Der dritte Store »data« in Zeile 4, stellt ein noch leeres Array dar. Dieses Array nimmt später die Werte der aktuellen Kurse der Währungen im Datenformat JSON auf, anhand derer die App dann die Währungen umrechnet. Den aktuellen Kurs stellt die Open-Source-API Frankfurter [9] zur Verfügung.

Die beiden weiteren Variablen »amount« und »total« repräsentieren die korrespondierenden Beträge der Ausgangs- und der Zielwährung. Schließlich gibt es noch einen Store »$countries« mit einem Array, das die Kürzel und Namen der Währungen sowie eine URL zu GIF-Dateien mit den entsprechenden Nationalflaggen definiert. Die GIFs stammen aus der Online-Datenbank Geonames.org.

Die Daten bleiben nur temporär in einem Store gespeichert. Möchte man sie persistent über die Ausführung der Webanwendung hinaus speichern, benötigt man in Svelte einen sogenannten Local Storage, der die Daten im lokalen Speicher des Browsers ablegt. Außerdem lassen sich Daten in einer Datenbank wie MongoDB speichern. Das würde aber den Rahmen des Artikels sprengen.

Um Zugriff auf einen Store zu erhalten, muss man die gewünschte Store-Variable importieren. In Listing 6 importiert Zeile 3 alle sechs Variablen aus dem Store und macht sie in der Komponente »Converter.svelte« verfügbar. Wenn Sie außerhalb des Skriptblocks auf eine Variable aus dem Store zugreifen möchten, müssen Sie dem Variablennamen übrigens ein Dollarzeichen vorsetzen.

Lifecycles

Eine Komponente in Svelte durchläuft grundsätzlich vier verschiedene Phasen, die man Lifecycles nennt (Abbildung 5). Über Lifecycle-Funktionen kann man zu bestimmten Zeitpunkten im Lebenszyklus einer Svelte-Komponente Code ausführen.

Abbildung 5: Lifecycle-Events einer Svelte-App.

Abbildung 5: Lifecycle-Events einer Svelte-App.

Zunächst einmal wird eine Komponente mit der Lifecycle-Funktion »beforeUpdate« initialisiert. Die Funktion »onMount« führt man aus, wenn man eine Komponente erstmals dem DOM hinzufügt (siehe Kasten “Document Object Model”). Die dritte Phase »afterUpdate« kommt bei der Aktualisierung einer Komponente über das DOM zum Einsatz. Die letzte Phase »onDestroy« wird aufgerufen, nachdem eine Komponente wieder aus dem DOM entfernt wurde.

Document Object Model

Beim DOM (Document Object Model) handelt es sich um eine unabhängige Programmierschnittstelle, bei der HTML-Dokumente als Baumstruktur dargestellt werden. Jeder Knoten bildet dabei ein Element der Webseite, zum Beispiel eine Überschrift. Dadurch lässt sich die Struktur der Webseite standardisiert ändern. Einige Javascript-Frameworks wie React oder Vue.js nutzen ein sogenanntes Virtual DOM zum Bearbeiten des DOM. Dabei vergleichen sie das virtuelle mit dem tatsächlichen DOM und gleichen nur etwaige Änderungen ab, was die Performance steigern kann. Svelte verzichtet auf ein Virtual DOM, da sein Erfinder Rich Harris dies als Overhead ansieht [13].

Javascript-Block

Die zweite Zeile von Listing 6 importiert die am meisten genutzte Lifecycle-Funktion »onMount«, was zunächst die Daten beim Online-Dienst »frankfurter.app« abruft. Dazu führt die Zeile 5 »onMount« aus, um beim Programmstart mittels einer asynchronen Callback-Funktion die aktuellen Kurse für die Ausgangswährung Euro und die Zielwährung US-Dollar im Datenformat JSON zu erhalten. Das Schlüsselwort »await« bewirkt bei Funktionen, dass sie auf eine Antwort warten, ohne den Programmfluss zu blockieren.

In Zeile 9 folgt eine weitere asynchrone Funktion namens »updateRate«, die immer ausgeführt wird, wenn der Anwender über die Ausklapplisten aus Zeile 36 und 54 die Währung ändert. Dann werden die Variablen »amount« und »total« aus dem Store mittels der Methode »set« wieder auf null gesetzt. Es folgt eine Aktualisierung der aktuellen Kurse mit den Werten von »convertfrom« und »convertto«, damit die Funktion »fetch()« sie von »frankfurter.app« abrufen und in der Variablen »$data« im Store speichern kann.

Zu guter Letzt deklariert der Skriptblock der Komponente »Converter.svelte« noch die beiden Funktionen »changeAmount« und »changeTotal«. Sie kommen zur Ausführung, wenn sich über die Eingabefelder in Zeile 34 und 52 der Betrag der Ausgangs- respektive der Zielwährung ändert. Der Inline-Event-Handler beziehungsweise das Attribut »on:input« koppelt diese Eingabefelder mit den jeweiligen Funktionen.

Beachten Sie, dass nach den Funktionsnamen hier keine Klammern stehen. Anderenfalls würde die Funktion direkt ausgeführt und nicht erst, wenn sich der Betrag eines Eingabefelds ändert. Außerdem verbindet »bind:value« den Wert der Eingabefelder mit den Variablen »$amount« und »$total«. Das bedeutet, dass diese Variablen in Echtzeit mit den entsprechenden Werten angepasst und wieder via »set« im Store gespeichert werden, sobald sich der Betrag ändert. Das Prinzip nennt man Datenbindung.

Die zwei Funktionen »changeAmount« und »changeTotal« lesen mit »event.target.value« den aktuellen Wert des jeweiligen Eingabefelds aus und multiplizieren es mit beziehungsweise dividieren es durch den aktuellen Kurs. Die Funktion »toFixed()« rundet das Ergebnis auf zwei Nachkommastellen. Da »toFixed()« die gerundete Zahl in einen String konvertiert, gilt es, das Ergebnis anschließend mit »Number()« wieder in eine Zahl umzuwandeln.

Die Methode »set« aktualisiert die Variablen »$amount« und »$total« und speichert sie im Store. Damit hat die Komponente »Footer.svelte« Zugriff auf die aktualisierten Werte und kann sie anzeigen (Listing 7). Dafür muss diese Komponente die Stores in Zeile 2 von Listing 7 wieder importieren. Zeile 5 von Listing 7 gibt dann die Werte der Variablen aus, wofür man deren Namen in geschweifte Klammern setzt.

Listing 6

Converter.svelte

<script>
  import {onMount} from 'svelte';
  import {data, convertfrom, convertto, amount, total, countries} from './store';
  onMount (async () => {
    $data = await fetch('https://api.frankfurter.app/latest?amount=1&from=EUR&to=USD').then(resp => resp.json());
  })
  async function updateRate(){
    amount.set(0);
    total.set(0);
    $data = await fetch('https://api.frankfurter.app/latest?amount=1&from=' + $convertfrom + '&to=' + $convertto).then(resp => resp.json());
  }
  const changeAmount = (event) => {
    total.set(Number((event.target.value * $data['rates'][$convertto]).toFixed(2)));
  }
  const changeTotal = (event) => {
    amount.set(Number((event.target.value / $data['rates'][$convertto]).toFixed(2)));
  }
</script>
<svelte:head><title>Währungsrechner</title></svelte:head>
<main>
  <h1>Währungsrechner</h1>
  {#each $countries as countrie}
    {#if $convertfrom == countrie.name}
      <img src={countrie.flag} alt='Flagge'>
    {/if}
  {/each}
  <input type='number' min=0 on:input={changeAmount} bind:value={$amount}>
  <select bind:value={$convertfrom} on:change={updateRate}>
    {#each $countries as countrie}
      <option value={countrie.name}>
        {countrie.desc}
      </option>
    {/each}
  </select>
  <br><br>
  {#each $countries as countrie}
    {#if $convertto == countrie.name}
      <img src={countrie.flag} alt='Flagge'>
    {/if}
  {/each}
  <input type='number' min=0 on:input={changeTotal} bind:value={$total}>
  <select bind:value={$convertto} on:change={updateRate}>
    {#each $countries as countrie}
      <option value={countrie.name}>
        {countrie.desc}
      </option>
    {/each}
  </select>
</main>
<style>
  input,
  select,
  option {
    vertical-align: middle;
    font-size: 18px;
  }
  img {
    vertical-align: middle;
    height: 26px;
  }
  h1 {
    font-size: 40px;
  }
  main {
    text-align: center;
    font-family: system-ui, sans-serif;
  }
</style>

HTML-Block

Ab Zeile 26 von Listing 6 beginnt mit dem »main«-Tag der HTML-Block der Komponente »Converter.svelte«. Er reicht bis zur Zeile 61. Hier strukturiert gewöhnliches HTML in Kombination mit Svelte-spezifischen Anweisungen die Oberfläche und baut die Logik auf. Svelte-Anweisungen erkennt man an den geschweiften Klammern.

Zeile 24 von Listing 6 legt über »<svelte:head>« den Fenstertitel fest. Mit dieser Direktive lässt sich alles manipulieren, was im Head-Bereich der Datei »index.html« im Root-Verzeichnis steht. Die Angaben in einer Komponente haben dabei immer Priorität. Zeile 27 von Listing 6 deklariert die Überschrift “Währungsrechner” mit dem HTML-Tag »h1«. Danach folgt eine Schleife, die man in Svelte mit dem Schlüsselwort »each« kennzeichnet. Die Anweisungen im Schleifenkörper stehen im Konstrukt »{#each…}« mit dem schließenden Tag »{/each}«.

Zeile 28 iteriert über das Array »$countries«, das in Zeile 3 aus dem Store importiert wurde. Seine Elemente, jeweils assoziative Arrays, enthalten für jedes Land eine ID, ein Währungskürzel, den ausgeschriebenen Währungsnamen und eine URL für die Nationalflagge. Jede Iteration in Zeile 29 prüft, ob das aktuelle Währungskürzel mit jenem übereinstimmt, das gerade in der Ausklappliste aus Zeile 36 ist.

If-Statements kapselt Svelte mit »{#if…}« und »{/if}«. Ist die Bedingung erfüllt, bindet Zeile 30 über das HTML-Tag »img« und die Svelte-Anweisung »{countrie.flag}« die passende Nationalflagge ein. Die Variable »$countrie« steht dabei für das aktuelle assoziative Array und »flag« für das Element mit der URL zur Landesfahne. Um auf eine Variable aus dem Store zuzugreifen, muss man wie schon erwähnt im HTML-Block dieser Variablen ein Dollarzeichen voranstellen.

Zeile 36 zeichnet eine Ausklappliste mit dem HTML-Tag »select« aus. Auch hier bindet die Svelte-Direktive »bind:value« die ausgewählte Währung an die Variable »$convertfrom«. Wurde eine neue Währung ausgewählt, aktualisiert sich synchron die Variable »$convertfrom«. Die zweite Svelte-Direktive »on:change« verbindet die Auswahl mit der bereits erwähnten asynchronen Funktion »updateRate« aus Zeile 9.

Zeile 37 iteriert nochmals mit einer Svelte-Schleife über das Array »$countries«, um die wählbaren Optionen in die Ausklappliste einzufügen. Dabei werden innerhalb der HTML-Tags »option« die Bezeichnungen der Währungen eingefügt. Das Array »$countries« enthält die Bezeichnungen jeweils im Schlüssel »desc«.

Alles bisher Beschriebene (Zeile 28 bis Zeile 42) bezog sich auf die Ausgangswährung. Das Gleiche programmieren Sie in Zeile 46 bis Zeile 60 noch einmal, angepasst an die Zielwährung. Das umfasst eine Schleife, in der die Flagge der Zielwährung ermittelt wird, ein Eingabefeld für den Betrag sowie ein HTML-Select-Element für die Zielwährung.

CSS-Block

Die CSS-Sektion der Komponente »Converter.svelte« ab Zeile 63 von Listing 6 zentriert lediglich die HTML-Elemente »input«, »select« und »option« vertikal und legt die Schriftgröße auf 18 Pixel fest. Dazu bindet sie die Nationalflaggen durch das »img«-Tag ebenfalls vertikal zentriert ein und stellt als Höhe 26 Pixel ein. Zusätzlich definiert das Tag »h1« die Schriftgröße mit 40 Pixel.

Für das »main«-Tag wurde allgemein die System-Schriftart mit »font-family: system-ui;« zugewiesen und mit »text-align: center;« alles horizontal zentriert. Der CSS-Block der Komponente »Footer.svelte« ab Zeile 7 von Listing 7 legt für alles, was sich im HTML-Tag »p« befindet, die Schriftgröße auf 18 Pixel fest und bestimmt die System-Schriftart. Die Datei »app.css«, die wir eingangs beim Anlegen der Svelte-App standardmäßig erstellt haben, benötigen wir nicht mehr und können sie jetzt löschen. Damit entfällt die erste Zeile der Datei »main.js«.

Listing 7

Footer.svelte

<script>
  import {data, convertfrom, convertto, amount, total} from './store';
</script>
<p>{$amount} {$convertfrom} entspricht {$total} {$convertto} (Stand: {$data['date']})</p>
<style>
  p {
    font-size: 18px;
    font-family: system-ui, sans-serif;
    text-align: center;
    }
</style>

Deployment

Die Svelte-Anwendung kompilieren Sie mit dem Befehl »npm run build« im Projektordner. Um die fertige Webanwendung online zu stellen, können Sie die Hosting-Plattformen Surge [10] und Vercel [11] nutzen. Beide sind in der Basisversion kostenlos.

Um die App auf Surge hochzuladen, installieren Sie zuerst Surge global mit »sudo npm install –global surge«. Als Nächstes wechseln Sie in das Verzeichnis »dist/« und führen den Befehl »surge« aus. Nach Eingabe einer E-Mail-Adresse und eines Passworts verfügen Sie nun über einen Account auf Surge. Anschließend definieren Sie noch einen Projektnamen und eine Domain, unter der die Svelte-Applikation verfügbar sein soll. Je nach Größe des Projekts präsentiert sich innerhalb weniger Sekunden die fertige Anwendung unter der angegebenen URL online.

Um Änderungen an der Webanwendung hochzuladen, führen Sie einfach erneut »npm run build« im Projektordner und danach noch einmal »surge –domain URL« im Ordner »dist/« aus. Mit dem Parameter »–domain« geben Sie die zuvor zugewiesene URL an, unter der Sie das Projekt bei Surge hochgeladen haben.

Alternativ könnten Sie auch die Dateien aus dem Ordner »dist/« auf einen eigenen Webspace transferieren und die Svelte-Anwendung dort durch Aufruf der »index.html« starten. Dazu müssten Sie aber gegebenenfalls in der »index.html« in »dist/« die Links anpassen, falls Sie die Dateien nicht direkt ins Root-Verzeichnis des Webspaces hochladen.

Dazu entfernen Sie die am Anfang stehenden Schrägstriche bei den Links in den Zeilen 5, 8 und 9 von Listing 2, um die Dateien korrekt zu referenzieren. Ansonsten würde der Webserver die Dateien im Wurzelverzeichnis suchen.

Fazit

Svelte überzeugt durch Einfachheit, ist aber trotzdem relativ mächtig. Es macht einfach Spaß, damit zu arbeiten und Websites zu entwickeln. Das hier vorgestellte Beispiel vermittelt lediglich einen ersten Eindruck.

Svelte wirkt ausgereift und kann Angular, React und Vue.js durchaus Konkurrenz machen. Nicht ohne Grund belegt es einer Umfrage von Stack Overflow zufolge aktuell den zweiten Platz der beliebtesten Web-Frameworks [12]. Falls Sie das eine oder andere von den etablierten Mitbewerbern unterstützte Feature vermissen, sollten Sie sich das Meta-Framework SvelteKit ansehen, das Svelte um etliche Funktionen ergänzt. (jcb/jlu)

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDFUmfang: 7 HeftseitenPreis €0,99
(inkl. 19% MwSt.)
LINUX-MAGAZIN KAUFEN
EINZELNE AUSGABE Print-Ausgaben Digitale Ausgaben
ABONNEMENTS Print-Abos Digitales Abo
TABLET & SMARTPHONE APPS Readly Logo
E-Mail Benachrichtigung
Benachrichtige mich zu:
0 Kommentare
Älteste
Neuste Beste Bewertung
Nach oben