2. Jan 2023
Lesedauer 35 Min.
SvelteKit – Framework und Tools
Svelte – ein Ökosystem für Vanilla-JavaScript (Teil 4)
SvelteKit erweitert Svelte um zusätzliche Features und Tools zu einem effizienten und produktiven Werkzeugkasten von der Entwicklung bis zum Betrieb.

Im Mittelpunkt von SvelteKit (ursprünglich Sapper genannt) steht Svelte als Compiler, der im Unterschied zu den gängigen JavaScript-Frameworks (Angular, React, Vue.js) reinen JavaScript-Quellcode unabhängig von Framework-Spezifika erzeugt. Rund um diesen Compiler kommen mit SvelteKit weitere wichtige Features wie Layouting, Routing, Preloading/Prefetching, Prerendering, Server-Side-Rendering (SSR), Static-Sites-Generation (SSG), Configurable Rendering, Code Splitting/Build Optimizations (derzeit mittels Vite) und automatisches Deployment hinzu. Damit deckt SvelteKit neben dem Frontend auch zunehmend das Backend ab und entwickelt sich so kontinuierlich zu einem Full-Stack-Framework.Bei der Konzeption der Features legt das SvelteKit-Entwicklungsteam rund um Rich Harris besonderen Wert auf die Produktivität gemäß der eigenen Devise »The fastest Way to build Svelte Apps«. SvelteKit befindet sich immer noch im Beta-Status, derzeit ist noch offen, wann ein erstes freigegebenes Produktrelease erreicht wird.Aufgrund des dann anstehenden Migrationsaufwands eignet sich das Web-Framework noch nicht für den produktiven Betrieb großer Anwendungen. Wobei im Unterschied zu früheren Releaseständen mit der jetzigen Beta-Version der Aufwand sich eher in Grenzen halten wird. Vermutlich steht SvelteKit Version 1.0 Mitte Dezember 2022 für den produktiven Einsatz zur Verfügung.
SvelteKit als Startpunkt für ein Projekt
Ausgangspunkt eines Projekts mit SvelteKit stellt ein mittels Scaffolding erzeugtes Grundgerüst (Skeleton) dar. Scaffolding mit SvelteKit setzt grundsätzlich die Installation von Node.js ab Version 16.14 voraus. Bei dem Open-Source-Produkt Node.js handelt es sich um eine plattformübergreifende JavaScript-Laufzeitumgebung (siehe Teil 1).Der Terminalbefehl npm create svelte@latest my-app mit der Antwort 'y' legt bei vollständiger Ausführung einen neuen Projektordner my-app im aktuellen Verzeichnis an, installiert in diesen die aktuellsten Meta-Informationen für das SvelteKit-Ökosystem und erzeugt dort (entsprechend der nachfolgend vorgenommenen Festlegungen) das Scaffolding-Projekt. Als Projekttyp bietet dieser Terminalbefehl dem Entwickler eine Demo-App, ein Skeleton-Projekt für eine Starter-App oder ein Library Skeleton-Projekt für eine Bibliothek zur Auswahl an.Bei der Auswahl des Projekttyps legt der Entwickler auch die gewünschte Unterstützung für das Type-Checking fest: Die Auswahl No erzeugt reinen JavaScript-Quellcode ohne Type-Checking, Yes, using JavaScript with JSDoc comments bietet eingeschränktes Type-Checking mittels JSDoc-Annotations (basierend auf TypeScript), und Yes, using TypeScript syntax führt vollständiges Type-Checking über TypeScript aus. Wobei die letzten beiden Optionen eine Unterstützung in der IDE für das jeweilige Type-Checking voraussetzen. Für das Code-Linting lässt sich ESLint dem Projekt hinzufügen, für Code-Formatting bietet SvelteKit Prettier an, für das Testing über einen Browser Playwright (von Microsoft) und für Unit-Tests mittels JavaScript/TypScript Vitest (vom Vue-Team).Als alternative Projekttypen stehen über verschiedene GitHub-Repositories weitere Starter-Templates für SvelteKit zur Verfügung. Diese zeigt die Homepage der Svelte Society im Bereich Templates durch Auswahl von SvelteKit über die Drop-Down-Liste Category an. Ein Cloning mittels git lädt ein solches Starter-Template direkt in ein Projekt herunter. Danach führt in allen genannten Fällen der Terminalbefehl npm install im Projektordner eine Installation der erforderlichen npm-Pakete durch; was auch die anfänglich angezeigten Fehlermeldungen in der Entwicklungsumgebung beseitigt.
Die Demo-App von SvelteKitläuft im Webbrowser standardmäßig auf der lokalen Hardware (localhost) am Port 5173(Bild 1)
Simon
Um den Quellcode der App im Projektordner auszuführen, kommt der Terminalbefehl npm run dev zum Einsatz. Dieser startet einen SvelteKit-Entwicklungsserver mit HMR (Hot Module Replacement), so dass parallele Änderungen im Quellcode sich sofort zur Laufzeit in der App widerspiegeln. Den Entwicklungsserver zur Ausführung des Skeleton-Code erreicht der Webbrowser über localhost:5173 (Bild 1). Dabei unterscheidet SvelteKit zwischen Entwicklungs- und Preview-Server; wobei letzterer zur Ausführung von Tests mit der produktiven App dient. Anhand der Konfigurationsdatei vite.config.js im Projektordner stellt man den TCP-Port für Entwicklungs- und Preview-Server ein. Dazu deklariert man dort die beiden Einträge server und preview:
<span class="hljs-keyword">import</span> { sveltekit } from <span class="hljs-string">'@sveltejs/kit/vite'</span>;
<span class="hljs-keyword">import</span> type { UserConfig } from <span class="hljs-string">'vite'</span>;
const <span class="hljs-string">config:</span> UserConfig = {
<span class="hljs-string">plugins:</span> [sveltekit()],
<span class="hljs-string">server:</span> {
<span class="hljs-string">port:</span> <span class="hljs-number">5000</span>,
<span class="hljs-string">strictPort:</span> <span class="hljs-literal">false</span>,
},
<span class="hljs-string">preview:</span> {
<span class="hljs-string">port:</span> <span class="hljs-number">4000</span>,
<span class="hljs-string">strictPort:</span> <span class="hljs-literal">false</span>,
},
};
export <span class="hljs-keyword">default</span> config;
SvelteKit orientiert sich beim Aufbau der App an der gängigen Projektstruktur einer Svelte-App (siehe Teil 1) und überträgt deren Konventionen auf das SvelteKit-Projekt. Fürs Arbeiten im Projekt benötigt ein Entwickler grundsätzlich Kenntnisse zu den Konventionen eines der gängigen npm-Package-Managers (npm, pnpm, yarn), zu den Programmiersprachen JavaScript/TypeScript mit HTML, CSS und Svelte. Im Wurzelverzeichnis des Projekts befinden sich neben der für Node-Projekte zentralen package.json-Datei zusätzlich die bei einer Svelte-App übliche svelte.config.js-Datei.Die dortigen Einträge dienen auch zur Konfiguration von SvelteKit wie dem Hinzufügen von Saas/SCSS und dem Arbeiten mit Adapter/Plugins. Defaultmäßig setzt SvelteKit für die CSS-Transformation (wie Svelte) PostCSS ein. Hinweise für das Arbeiten mit SvelteKit und dem neu erzeugten Entwicklungsprojekt gibt die README.md-Datei. Die Einstellungen für den JavaScript/TypeScript-Compiler enthält die Datei jsconfig.json beziehungsweise tsconfig.js. Wichtige Projektaufgaben für Build, Test und Deployment erledigen die Vorgaben in der package.json-Datei.
Unveränderliche Ressourcen des Projekts
Der Hauptordner des SvelteKit-Projekts unterteilt sich in die beiden Unterverzeichnisse static und src: In static legt Vite alle unveränderlichen Ressourcen des Projekts wie Bilder, Icons und Ähnliches ab. Die Datei app.html im src-Ordner entspricht einem HTML-Template, in welches SvelteKit den Quellcode eines Entwicklers injiziert: Dies erfolgt im Bereich <body> durch die Anweisung %sveltekit.body%, im <link>-Bereich über das href-Attribut durch %sveltekit.assets% und im <head>-Bereich über %sveltekit.head%. Die app.html-Datei nimmt auch Meta-Angaben für die Sprache, Titel, Beschreibung der Webseite und Informationen für die Suchmaschinen-Optimierung (SEO) auf. Als wichtiges Meta-Tag legt viewport (unter anderem) die Skalierung für die Anzeige des Webcontent in einer aufgerufenen Seite über das Ansichtsfenster/Anzeigebereich fest; diese erleichtert auch die Portierung der Web-App auf eine Mobil-Version der Software.Der Ordner src mit dem eigenen Quellcode besteht aus zwei weiteren Unterverzeichnissen: lib und routes. Dabei dient der Ordner src/lib der Ablage wiederverwendbarer Komponenten, von Utility-Funktionen und im Unterverzeichnis images deren statische Ressourcen (Bilder, Icons). Der Quellcode im lib-Unterverzeichnis zielt auf die Wiederverwendung zwischen den verschiedenen Webseiten ab. Dabei handelt es sich um eigene, selbst programmierte Svelte-Komponenten mit .svelte als Dateityp.Zugriff auf dieses Directory erhält der Programmierer über den von SvelteKit definierten $lib-Alias – SvelteKit nutzt für den Import über diesen Ordner einen Automatismus. Über das Verzeichnis src/routes führt SvelteKit das Routing aus. In diesem Verzeichnis befinden sich alle Svelte-Komponenten für Webseiten und SvelteKit-Dateien für Routing und Layouting. Dazu gehören als wichtigste Dateien für das User-Interface +page.svelte, für das Layouting (Aufbau der Webseiten) +layout.svelte und für das Fehlerhandling +error.svelte.Einen einheitlichen Aufbau für Webseiten mit Header, Navigationsleiste, Inhalt und Footer (Fußleiste), sprich das Layout der App, definiert im Verzeichnis src/routes die Datei +layout.svelte. Wobei diese Layout-Datei derzeit nur für die Demo-App automatisch erzeugt wird; im Falle eines Skeleton-Projekts legt der Entwickler diese im Bedarfsfall von Hand an. Als Svelte-Komponente orientiert sich +layout.svelte beim Dateiaufbau an den Konventionen von Svelte mit <script>-, <HTML>- und <style>-Tag.Der <script>-Bereich stellt (mittels import-, export-Anweisungen sowie Deklarationen) Datenstrukturen und Variablen bereit. Ein <div>-Tag baut über eine <Header />-Komponente den Header, mit einem obligatorischen <slot/>- und einem optionalen <main>-Tag den Inhalt der Homepage, mit einem <nav>-Tag die Navigationsleiste und mit einem <footer>-Tag den Footer (die Fußleiste) auf. Das zugehörende Styling definiert der <style>-Tag und die dortigen CSS-Anweisungen.Das Command Line Interface (CLI) von SvelteKit
Aktuell besitzt SvelteKit noch kein vollständig eigenes Command Line Interface (CLI) es greift vorwiegend auf das Frontend-Tooling von Vite zurück. Vite stammt ursprünglich von Evan You dem Entwickler des Vue.js-Framework. Dabei verfolgt Vite seitens der Architektur eine durchgängige Tooling-Umgebung von der Übersetzung des Quellcode, dessen Test bis zum Build der App für deren produktiven Betrieb (mit Vorbereitungen für eine Überführung in die Produktionsplattform).Inzwischen nutzen viele bekannte Werkzeuge wie Astro, Cypress, Hydrogen, Playwright, SolidJS oder Svelte/SvelteKit dieses Vite-Tooling. Dabei nutzen alle Tools entweder direkt Vite-Befehle oder stellen ein spezielles Vite-Plugin in ihrer eigenen Ausführungsumgebung bereit.Zur Erzeugung eines Starter-Projekts/Template für eine Demo-App, ein Skeleton- oder Library-Projekt und für deren Packaging als npm-Paket bietet SvelteKit ein eigenständiges CLI an. Für diese drei Projekttypen erzeugt der Terminalbefehl npm create svelte@latest ein Starter/Template-Projekt (Bild 2). Leider existieren bisher noch keine eigenen CLI-Befehle, um neue, weitere Bestandteile wie Komponenten, Layouts, Routes, Endpoints oder ähnliches in ein vorhandenes SvelteKit-Projekt hinzuzufügen. Bei Einsatz der VS Code/VSCodium-IDE bietet die Marketplace-Extension Svelte for VS Code für einige dieser Aufgaben eine rudimentäre Unterstützung an.
SvelteKit besitztderzeit den Befehl create, um Bestandteile für ein Starter/Template-Projekt wie Demo-App, Skeleton- oder Library-Projekt erzeugen zu können(Bild 2)
Simon
Die SvelteKit-Unterstützung in der Svelte for VS Code-Extension erreicht der Programmierer in deren Kontextmenü über den Eintrag SvelteKit-Files. Allerdings erscheint dieser Menüeintrag nur, wenn man ein Unterverzeichnis im Projektordner ausgewählt hat. Weitere, notwendige Arbeitsschritte für die Unterstützung in Entwicklung und Test wickelt SvelteKit analog Svelte über die scripts-Section der package.json-Datei ab. Dazu kommen verschiedene auf Vite oder SvelteKit basierende Scripts zum Einsatz. Ein Entwickler oder Tester startet in einem Terminalfenster mittels des npm run-Befehls das gewünschte Script. Zu den wichtigsten Scripts gehören die nachfolgenden:Alle für das Routing relevanten Dateien der von SvelteKit erzeugten Demo-App beziehungsweise dem Skeleton-Projekt befinden sich im Ordner src/routes und dessen Unterverzeichnissen. Die dortige +page.svelte-Datei entspricht dem Einstiegspunkt der App, die SvelteKit unter Berücksichtigung einer eventuellen +layout.svelte-Datei zuerst rendert und so die Homepage anzeigt. Die Unterverzeichnisse von src/routes spiegeln die Routing-Struktur der kompletten App wider – man spricht von sogenanntem Filesystem/Directory/Folder-based Routing.So gehört ein Ordner mit dem Namen about zur gleichnamigen Route, die man in der Svelte-App über <a href="/about"… oder im Browser über localhost:5173/about erreicht. SvelteKit greift beim Verfolgen dieser Route auf den about-Ordner in src/routes zu und startet das Rendering beginnend mit der dortigen +page.svelte unter Einbezug von +layout.svelte-Datei (falls vorhanden).Ergänzend greift SvelteKit für das Rendering auf die Datei +page.js/ts zurück – diese exportiert die load-Funktion, um die Webseite mit eventuell dynamischen Werten zu bestücken. Dabei liefert die load-Funktion in der Datei +page.js/ts die Werte in JavaScript/TypeScript-Datenstrukturen zurück – Prop-Attribute müssen keine deklariert werden. Die +page.svelte-Datei erhält über das data-Prop Zugriff auf die von load exportierte Datenstruktur. Sollte die App zusätzlich Werte von einem Backend-Server benötigen, so besorgt diese eine spezielle load-Funktion über eine zusätzliche Datei +page.server.js/ts.In diesem Fall führt SvelteKit die load-Funktion vollständig auf dem Server aus. SvelteKit verwaltet automatisch einen Page-Store, den man über die import-Anweisung import { page } from '$app/stores' erreicht. Der Page-Store enthält alle Daten einer Webseite wie url, data, errors et cetera. Für jede Anforderung ist page einzigartig, daher muss ein Subscribe während der Initialisierung der Komponente stattfinden. Parameter in einer Route deklariert eine in [] stehende Bezeichnung beim Verzeichnis im Route-Namen src/routes/about/[parameter].

In der +error.svelte-Dateihinterlegt der Programmierer eine eigene individuelle Fehlermeldung, die SvelteKit anzieht, sollte die Ausführung von load() zu einem Error führen(Bild 3)
Simon
Sollte während der load()-Funktion ein Fehler entstehen, so rendert SvelteKit eine Default-Error-Seite. Diese Fehlerseite passt man für jede Route über die Datei +error.svelte an eigene Vorstellungen an (Bild 3) und legt sie im Ordner der Route oder oberhalb in einem anderen Order im src/route-Verzeichnis ab. Sollte eine Fehlerkonstellation vorliegen, so sucht SvelteKit beginnend von der betroffenen Route solange aufsteigend in der Hierarchie der Ordner bis eine +error.svelte-Datei gefunden wird. Fehlt die +error.svelte-Datei erscheint die Standard-Fehlermeldung des Browsers. Analog der Layout-Datei im Skeleton-Projekt programmiert der Entwickler im Bedarfsfall die +error.svelte-Datei:
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">script</span>></span></span>
<span class="xml"><span class="actionscript"> <span class="hljs-meta"><span class="hljs-meta-keyword">import</span> </span></span></span><span class="hljs-template-variable">{ page }</span><span class="xml"><span class="javascript"> <span class="hljs-keyword">from</span> <span class="hljs-string">'$app/stores'</span>;</span></span>
<span class="xml"><span class="hljs-tag"></<span class="hljs-name">script</span>></span></span>
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">h1</span>></span></span><span class="hljs-template-variable">{$page.status}</span><span class="xml">: </span><span class="hljs-template-variable">{$page.error.message}</span><span class="xml"><span class="hljs-tag"></<span class="hljs-name">h</span>></span></span>
Preloading als Technik dient dem Laden von Inhalten (Ressourcen) einer Webseite bereits vorab durch den Browser. Seit Jahren schon befasst sich das World Wide Web Consortium (W3C) mit dieser Technik, aber auch CSS und JavaScript bieten dazu Alternativen an. Der dahinterstehende Mechanismus läuft im Grunde gleich ab: Im Quellcode der Webseite befindet sich eine entsprechende Anweisung, die das Preloading anstößt. Die wohl bekannteste Implementierung von Preloading ist mit dem HTML-Element <link> verbunden, das einen Verweis auf eine externe Ressource spezifiziert. Am häufigsten kommt das HTML-Element <link> mit Stylesheets, Icons oder anderen statischen Daten einer Webseite zum Einsatz.
Mit Prefetching Daten vom Backend holen
SvelteKit setzt Preloading im Zusammenhang mit einer load-Funktion ein. Dabei führt SvelteKit eine load-Funktion immer vor dem Anlegen einer Komponente teilweise sowohl auf dem Client als auch auf dem Server aus. Daher sollte man auf APIs verzichten, die nur auf einer der beiden Seiten bekannt ist. Häufig bezeichnet SvelteKit diese Technik als Prefetching – sie ermöglicht es, Daten vom Backend zu holen und eventuell zu verändern bevor das Rendering einer Seite stattfindet. Damit entfällt die Notwendigkeit, mittels zusätzlicher Nachrichten oder Informationen den Endbenutzer über die Notwendigkeit eines Ladevorgangs zu informieren. Diese Information sieht der Programmierer in der Regel bei der Svelte-Lifecycle-Funktion (siehe Teil 1) onMount.Grundsätzlich gilt für SvelteKit die folgende Priorisierung: Die Ausführung einer load()-Funktion findet immer vor dem Rendering einer Komponente statt. Damit rendert SvelteKit eine Komponente erst, wenn load() sein Return-Ergebnis geliefert hat. Insofern sollte man load() typischerweise zum Bereitstellen von Daten einer Komponente verwenden. Die load()-Funktion stellt also ein spezielles Hilfsmittel dar, um Daten in die App vorausschauend zu laden. Beim Vorgänger Sapper von SvelteKit hieß das Pendant preload; Anwender von Netxt.js kennen das Konstrukt unter der Bezeichnung getInitialProps und Nuxt.js-Anwender unter dem Namen asyncData.Was das Preloading mittels HTML betrifft, so muss die Konvention von SvelteKit beachtet werden: Der Einsatz dieser Technik für das Routing mit einer URL erfolgt immer zusammen mit dem <a>-Element und der Anweisung rel="prefetch". Im Unterschied dazu verwendet man für das Preloading von statischen Ressourcen wie zum Beispiel Bilder oder Icons das übliche <link>-Tag von HTML: <link rel="preload" as="image" hreft=…/>.Diese Technik eignet sich auch zum Einfügen von Ressourcen mittels Preload in den <head>-Tag mit dem speziellen Svelte-Element <svelte:head>. Besonders performant arbeitet Svelte (im Unterschied zu den Frameworks Angular, React oder Vue.js), wenn der Programmierer Preloading von SvelteKit zusammen mit Reactive Statements von Svelte (die mit dem $:-Zeichen beginnen) kombiniert.Prerendering und Hydration
SvelteKit definiert in einer +page.svelte-Komponente eine Webseite der App. Das vollständige Rendering einer Webseite auf dem Server nennt man Server-Side-Rendering (SSR) – findet es nur auf dem Client statt, so spricht man von Client-Side-Rendering (CSR). Bei SSR handelt es sich keinesfalls um eine neue Software-Technik – tatsächlich stammt sie bereits aus der Zeit der ersten Web-Apps mit PHP. Für die Optimierung einer Suchmaschine (Search-Engine-Optimization (SEO)) eignet sich SSR besser.Im Normalfall rendert SvelteKit alle Seiten anfangs auf dem Server und aufgrund der anschließenden Navigation auch auf dem Client (CSR) (Bild 4). Für dieses CSR benutzt der Client den für den Webbrowser generierten JavaScript-Code. Häufig benötigt die Web-App vor dem Rendering noch zusätzliche Daten, diese liefert eine innerhalb einer page.js/ts-Datei programmierte load()-Funktion. Kann diese load()-Funktion ausschließlich auf dem Server ausgeführt werden, so legt der Entwickler diese in einer +page.server.js/ts-Datei ab.
Die Arbeitsweise eines Browsersbeim Client-Side-Rendering (CSR) einer SPA (Single-Page-Application)(Bild 4)
Simon
Häufig lassen sich einige Webseiten und ihre Routes bereits zum Zeitpunkt ihrer Übersetzung (Build-Time) als einfache HTML-Datei darstellen. In einem derartigen Fall findet sogenanntes Prerendering statt. Um in SvelteKit Prerendering explizit anzustoßen, exportiert man in der +page.js/ts oder auch in der +page.server.js/ts eine Konstante prerender=true. Damit stellt man für den Build-Prozess sicher, dass diese Dateien/Routes für dynamisches SSR ausgeschlossen werden, was gleichzeitig den Server-Code minimiert. Besteht eine Web-App aus rein statische Seiten, so setzt man mit dem adapter-static durchgängig Prerendering ein. Bei einem Adapter handelt es sich um eine Erweiterung von SvelteKit in Form eines Plugins, den man über die svelte.config-Datei einbindet.Sendet SvelteKit nach dem SSR die Webseite an den Client, so führt dieser nochmals ein Rendering der betroffenen Komponente durch. Diese Form des Rendering übernimmt der Browser, er fügt der Komponente quasi die seitens des Endbenutzers benötigte Interaktivität hinzu. Die zugehörige Software-Technik auf der Client-Seite nennt man Hydration. Eine mit SvelteKit programmierte App erlaubt es, die verschiedenen Rendering-Optionen bedarfsgerecht auszuwählen – darin liegt eine wesentliche Stärke beziehungsweise Vorteil beim Einsatz von SvelteKit. Neben der oben genannten Konstanten prerender besitzt SvelteKit zusätzliche wie ssr und csr. Für reines HTML ohne Einsatz von JavaScript/TypeScript schaltet man CSR aus (csr=false). Für eine reine SPA (Single-Page-Application), die nur CSR durchführt, setzt man ssr auf false.Ein Web API stellt eine Application Program Interface (Anwendungsprogrammschnittstelle/API) eines Webservers oder Browsers dar. Dabei handelt es sich um Software-Techniken, die sich speziell für die Programmierung von Web-Apps eignen. Browser besitzen eine Menge von Built-in-Web APIs für komplexe Operationen und Datenzugriffe.Zu diesen Web APIs gehören beispielsweise das Web Forms API, Web Fetch API oder das Web Geolocation API. Das Web Forms API hilft bei der Verarbeitung von Eingabedaten, mit dem Web Fetch API setzt man HTTP-Requests an den Webserver ab, das Web Geolocation API bestimmt mittels des Browsers die geographische Position des Benutzers. Auch in anderen Umgebungen des Webs stehen Web APIs zur Verfügung, zum Beispiel: Cloudflare Workers, Deno oder Vercel Edge Functions.Ein serverseitiges Web API stellt eine Programmierschnittstelle zur Verfügung, die aus einer Menge öffentlich zugänglicher Endpoints besteht. Softwaretechnisch gesehen, handelt es sich um ein über das Web implementiertes Request-Response-Message-System auf Basis von JSON oder XML. Damit ermöglichen Endpoints Interaktionen mit dem Server für Zugriffe auf dessen Ressourcen. Endpoints benutzen HTTP-Methoden für Zugriffe mit URL-kodierten Parametern, um über JSON oder XML, Daten auszutauschen. SvelteKit benutzt das Fetch API für Zugriffe auf Daten im Netz. Das Fetch API kennt die Funktion fetch() mit den Interfaces: Request, Response und Headers. Dabei liefert das Fetch API auf einen Request einen Response zurück. Der Response entspricht einem Promise, den man mit den Methoden then() und catch() verarbeitet. SvelteKit unterstützt auch das Web Forms API (FormData), die Stream APIs und URL APIs.Eine spezielle fetch()-Funktion von SvelteKit steht über die load()-Funktion zur Verfügung, um Endpoints direkt während dem Server-Side-Rendering aufzurufen. Da die load()-Funktion, um Daten über den Server zu holen, nur auf dem Server ausgeführt werden kann, sollte diese in der Datei +page.server.js/ts im zugehörigen Route-Verzeichnis implementiert sein. Die Verarbeitung und Darstellung der Daten erfolgt nach wie über die Svelte-Komponente in der Datei +page.svelte, die sich im selben Route-Verzeichnis befindet. Zusätzlich zum Export einer load()-Funktion kann die +page.server.js/ts-Datei auch actions exportieren. Im Unterschied zur load()-Funktion, die Daten vom Server holt/liest, schreiben oder übertragen actions mittels <form>-Element beschriebene Daten auf den oder vom Server.
APIs für die Entwicklung bereitstellen
Während der Programmierung eines Frontends stehen häufig einige der zu verwendenden APIs noch nicht zur Verfügung. Um dennoch das Frontend entwickeln und testen zu können, setzt man die Softwaretechnik des Mocking ein. Mocking macht noch nicht realisierte Programmteile über Platzhalter in der Entwicklung verfügbar. Ein derartiger Platzhalter nennt sich Mock, er implementiert eine Schnittstelle, die sich aktuell selbst noch in Entwicklung befindet. Eine Funktion, die bei bestimmten Parameterwerten eine fix definierte Rückgabe liefert, stellt die einfachste Art dar, einen Mock für ein API bereitzustellen.Damit man derartige Dummy-Implementierungen nicht selbst programmieren muss, kann man ein Mocking-Framework einsetzen. Für JavaScript bekannte Mocking-Frameworks stellen Sinon.JS oder JsMockito dar. Diese zielen primär auf die Durchführung von Tests, ähnlich den low-level Mocking-Tools Pretender und FakeRest. Für die Ausführung des Programms während der Entwicklung verwendet man eher Mocking-Libraries wie Mirage JS oder MSW. Jedoch entsteht ein ähnlicher Aufwand für deren Implementierung wie bei Verwendung eines Mocking-Frameworks oder Mocking-Tools. In Web- oder Mobile-Apps setzt man in der Regel REST-APIs ein, die einen Endpoint implementieren.REST (Representational State Transfer) ist eine Programmiertechnik des Internets – quasi eine einfache Variante des RPC (Remote Procedure Calls). Bei einem REST-API handelt es sich um eine einheitliche Schnittstelle, die gewissen Prinzipien genügt: So sprechen Client und Server gewissermaßen die gleiche Sprache; dabei fordert der Client mittels eines HTTP-Requests Daten vom Server an oder führt Funktionen auf ihm aus. Der HTTP-Request setzt sich aus dem Endpoint und den entsprechenden Parametern zusammen. Eine derartige HTTP-Anfrage greift mittels PUT, GET, POST oder DELETE auf die Daten zu. Damit sind zahlreiche Web-Dienste per se REST-konform.Um den Aufwand, vor allem aber die Wartezeit für die API-Bereitstellung zu reduzieren, greifen Programmierer auf bereits fertige APIs zurück, die über das Web bereitgestellt werden. Die einheitliche Schnittstelle der REST-APIs prädestiniert sie für diese Vorgehensweise. Im Web findet man zahlreiche, häufig frei zugängliche, APIs, auch Public APIs genannt, die man direkt im Quellcode einsetzen kann. Bekannte Beispiele sind Bored API (boredapi.com), IP Geolocation API (ipbase.com), JSONPlaceholder (jsonplaceholder.typicode.com) oder DummyJSON (dummyjson.com) oder Alpha Vantage (alphavantage.co). Das nachfolgende Beispiel-Projekt greift auf ein API von JSONPlaceholder zurück.Empfehlungen beim Arbeiten mit Endpoints in einer SvelteKit-App
Aus zwei Gründen empfiehlt es sich, die Verarbeitung von Daten nicht immer direkt in der load()-Funktion auf dem Client vorzunehmen. Der erste Grund stellt die Performance dar – muss zum Beispiel ein Update sehr vieler Server-Daten stattfinden, so sollte dies ausgelagert asynchron auf dem Sever erfolgen. Der zweite Grund stellt die Sicherheit dar – benötigt zum Beispiel die Ausführung eines Endpoints ein Authentifizierungstoken (OAuth-Token), so sollte dies nur auf dem Server aber nicht auf dem Client zugänglich sein. Damit sind auf dem Client keine Daten verfügbar, mit denen potentielle Angreifer die Sicherheit der Web-App umgehen könnten.Aus diesem Grund sollten Endpoints als Funktion immer auf dem Server ausgeführt und clientseitig lediglich die Daten übertragen werden. Der Endpoint fungiert als Vermittler zwischen dem extern zugänglichen Client und den schutzbedürftigen Daten auf dem Server.Damit der Endpoint eine Anfrage/Request effektiv verarbeitet, muss der Client einen URL (Uniform Resource Locator), eine Methode, eine Header-Liste und einen Body angeben. Der Header enthält die Metadaten der Anfrage und der Body die vom Client an den Server oder umgekehrt gesendeten Daten. In einer SvelteKit-App greift der Entwickler auf Endpoints mittels der fetch()-Funktion in einer +page.server.js/ts-Dateien zu und führt diese asynchron aus:
<span class="hljs-regexp">//</span> +page.server.js
export async <span class="hljs-keyword">function</span> load ({ fetch }) {
const response = await fetch (<span class="hljs-string">'https://jsonplaceholder.typicode.com/users'</span>);
<span class="hljs-regexp">//</span> Rueckgabewerte von response <span class="hljs-keyword">in</span> Console fuer Tests ausgeben
<span class="hljs-regexp">//</span> console.log(response.status); <span class="hljs-regexp">//</span> <span class="hljs-number">200</span>
<span class="hljs-regexp">//</span> console.log(response.statusText); <span class="hljs-regexp">//</span> OK
<span class="hljs-keyword">if</span> (response.status === <span class="hljs-number">200</span>) {
const users = await response.json();
return {
<span class="hljs-regexp">//</span> Daten an die page.svelte-Komponente uebergeben
users: users
}
}
}
Dabei erzeugt SvelteKit in der fetch()-Funktion automatisch die passende Methode und Header-Liste. Als Ergebnis liefert die fetch()-Funktion anhand des abgesetzten http(s)-Aufrufs asynchron eine response-Datenstruktur zurück. Das zugehörige response-Objekt entspricht dem API-Wrapper für die gelesene Ressource.

Skeleton-Projekt von SvelteKiterweitert um einen Endpoint zum Lesen von Daten auf einem Server mit deren Ausgabe in Listenform(Bild 5)
Simon
Deshalb besitzt das response-Objekt Methoden wie text(), json(), blob(), formData() oder arrayBuffer() für Zugriffe auf die zugehörigen Daten. Ein erfolgreicher request liefert den Wert 200 im status und OK im statusText zurück. Der Quellcode übergibt die vom Endpoint erhaltene response-Datenstruktur und dessen Body mittels return-Anweisung an die Client-Seite, diese verarbeitetet die so erhaltenen Daten in der +page.svelte-Komponente und zeigt diese in der Webseite im Beispiel als Liste an (Bild 5):
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">script</span>></span></span>
<span class="xml"><span class="javascript"> <span class="hljs-keyword">export</span> <span class="hljs-keyword">let</span> data;</span></span>
<span class="xml"><span class="javascript"> <span class="hljs-comment">// Zum Testen die erhaltenen Daten in der Console ausgeben</span></span></span>
<span class="xml"><span class="javascript"><span class="hljs-comment"> // console.log(data)</span></span></span>
<span class="xml"><span class="hljs-tag"></<span class="hljs-name">script</span>></span></span>
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">h1</span>></span>Welcome to SvelteKit<span class="hljs-tag"></<span class="hljs-name">h1</span>></span></span>
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">p</span>></span>Visit <span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://kit.svelte.dev"</span>></span>kit.svelte.dev<span class="hljs-tag"></<span class="hljs-name">a</span>></span> to read the documentation<span class="hljs-tag"></<span class="hljs-name">p</span>></span></span>
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">h3</span>></span>Liste der Benutzer<span class="hljs-tag"></<span class="hljs-name">h3</span>></span></span>
<span class="xml"><span class="hljs-comment"><!-- Benutzer als unsortierte Liste ausgeben--></span></span>
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">ul</span>></span></span>
<span class="xml"> </span><span class="hljs-template-tag">{#<span class="hljs-name">each</span> data.users as user}</span>
<span class="xml"> <span class="hljs-tag"><<span class="hljs-name">li</span>></span></span>
<span class="xml"> <span class="hljs-tag"><<span class="hljs-name">strong</span>></span>Name: <span class="hljs-tag"></<span class="hljs-name">strong</span>></span></span><span class="hljs-template-variable">{user.name}</span><span class="xml"><span class="hljs-tag"><<span class="hljs-name">br</span>></span> </span>
<span class="xml"> <span class="hljs-tag"><<span class="hljs-name">strong</span>></span>E-Mail: <span class="hljs-tag"></<span class="hljs-name">strong</span>></span></span><span class="hljs-template-variable">{user.email}</span><span class="xml"><span class="hljs-tag"><<span class="hljs-name">br</span>></span></span>
<span class="xml"> <span class="hljs-tag"><<span class="hljs-name">strong</span>></span>Website: <span class="hljs-tag"></<span class="hljs-name">strong</span>></span></span><span class="hljs-template-variable">{user.website}</span>
<span class="xml"> <span class="hljs-tag"></<span class="hljs-name">li</span>></span></span>
<span class="xml"> </span><span class="hljs-template-tag">{/<span class="hljs-name">each</span>}</span>
<span class="xml"><span class="hljs-tag"></<span class="hljs-name">ul</span>></span></span>
Im Zentrum für das Layouting einer SvelteKit-App steht die im Verzeichnis /src/routes stehende +layout.svelte-Datei. Dabei handelt es sich um eine Svelte-Komponente, die der Startprozess einer App anzieht und deren Deklarationen in der Regel für alle nachfolgenden Webseiten für deren Layouting greifen. Die +layout.svelte-Datei enthält HTML-Elemente, welche die Gestaltung einer Webseite beschreiben – dazu gehören unter anderem <header>, <nav> und <footer>. Einziges obligatorisches Element innerhalb der +layout.svelte-Datei ist ein <slot />-Eintrag, der in einem <main>-Bereich eingebettet ist:
<span class="hljs-tag"><<span class="hljs-name">script</span>></span>
<span class="javascript"> <span class="hljs-keyword">import</span> Footer <span class="hljs-keyword">from</span> <span class="hljs-string">"$lib/Footer.svelte"</span>;</span>
<span class="hljs-tag"></<span class="hljs-name">script</span>></span>
<span class="hljs-comment"><!-- Navigation im Header-Bereich --></span>
<span class="hljs-tag"><<span class="hljs-name">nav</span>></span>
<span class="hljs-tag"><<span class="hljs-name">ul</span>></span>
<span class="hljs-tag"><<span class="hljs-name">li</span>></span><span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/"</span>></span>Home&nbsp;&nbsp;<span class="hljs-tag"></<span class="hljs-name">a</span>></span><span class="hljs-tag"></<span class="hljs-name">li</span>></span>
<span class="hljs-tag"><<span class="hljs-name">li</span>></span><span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/about/"</span>></span>Über&nbsp;&nbsp;<span class="hljs-tag"></<span class="hljs-name">a</span>></span><span class="hljs-tag"></<span class="hljs-name">li</span>></span>
<span class="hljs-tag"></<span class="hljs-name">ul</span>></span>
<span class="hljs-tag"></<span class="hljs-name">nav</span>></span>
<span class="hljs-tag"><<span class="hljs-name">main</span>></span>
<span class="hljs-comment"><!-- Einbindung der +page.svelte-Datei beim Rendern --></span>
<span class="hljs-tag"><<span class="hljs-name">slot</span> /></span>
<span class="hljs-tag"></<span class="hljs-name">main</span>></span>
<span class="hljs-comment"><!-- Navigation im Footer-Bereich --></span>
<span class="hljs-tag"><<span class="hljs-name">nav</span>></span>
<span class="hljs-tag"><<span class="hljs-name">ul</span>></span>
<span class="hljs-tag"><<span class="hljs-name">li</span>></span><span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/impressum"</span>></span>Impressum&nbsp;&nbsp;<span class="hljs-tag"></<span class="hljs-name">a</span>></span><span class="hljs-tag"></<span class="hljs-name">li</span>></span>
<span class="hljs-tag"><<span class="hljs-name">li</span>></span><span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/kontakt/"</span>></span>Kontakt&nbsp;&nbsp;<span class="hljs-tag"></<span class="hljs-name">a</span>></span><span class="hljs-tag"></<span class="hljs-name">li</span>></span>
<span class="hljs-tag"></<span class="hljs-name">ul</span>></span>
<span class="hljs-tag"></<span class="hljs-name">nav</span>></span>
<span class="hljs-tag"><<span class="hljs-name">style</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"scss"</span>></span>
<span class="css"> <span class="hljs-selector-tag">nav</span> <span class="hljs-selector-tag">ul</span> { </span>
<span class="css"> <span class="hljs-attribute">list-style</span>: none;</span>
<span class="css"> <span class="hljs-attribute">padding</span>: <span class="hljs-number">3px</span> <span class="hljs-number">5px</span>;</span>
<span class="css"> <span class="hljs-attribute">background</span>: <span class="hljs-built_in">rgb</span>(202, 198, 198);</span>
<span class="css"> }</span>
<span class="css"> <span class="hljs-selector-tag">nav</span> <span class="hljs-selector-tag">a</span> {</span>
<span class="css"> <span class="hljs-attribute">color</span>: <span class="hljs-built_in">rgb</span>(6, 6, 6);</span>
<span class="css"> <span class="hljs-attribute">text-decoration</span>: none;</span>
<span class="css"> }</span>
<span class="css"> <span class="hljs-selector-tag">nav</span> <span class="hljs-selector-tag">a</span><span class="hljs-selector-pseudo">:hover</span> {</span>
<span class="css"> <span class="hljs-attribute">text-decoration</span>: underline;</span>
<span class="css"> }</span>
<span class="css"> <span class="hljs-selector-tag">nav</span> <span class="hljs-selector-tag">li</span> {</span>
<span class="css"> <span class="hljs-attribute">display</span>: inline;</span>
<span class="css"> }</span>
<span class="hljs-tag"></<span class="hljs-name">style</span>></span>
In diesen <main>-Bereich zieht SvelteKit die +page.svelte-Webseite an und rendert deren Inhalt an dieser Stelle.SvelteKit kann auch eine +layout.svelte-Datei mit externen Daten bestücken – in Anlehnung an die +page.js/ts-Datei kommt dabei eine +layout.js/ts zum Einsatz. Die +layout.js/ts-Datei deklariert eine load()-Funktion, welche die Daten aus externen Quellen bereitstellt und damit die +layout.svelte-Komponente bestückt. Die über eine load()-Funktion bestimmten Daten stehen auch allen Kind-Komponenten der nachfolgenden Webseiten zur Verfügung. Für das Layouting unterstützt SvelteKit automatisches SSR über eine +layout.server.js/ts-Datei. Innerhalb des Quellcode von +layout.js/ts und +layout.server.js/ts kann ein Programmierer Page-Optionen wie prerender, ssr oder csr für die zugehörige Webseite exportieren.Zusätzlich zur initialen +layout.svelte-Datei erlaubt SvelteKit einem Programmierer für jede Route eine weitere +layout.svelte-Datei. Dabei gilt: Jede in der Routing-Hierarchie tiefer stehende +layout.svelte-Datei erbt, das heißt übernimmt die Gestaltungselemente der in der Verzeichnisstruktur höher stehenden +layout.svelte-Datei. Dadurch entsteht eine Gruppierung oder Verschachtelung der +layout.svelte-Dateien. Diese Vererbungshierarchie reicht quasi alle Deklarationen eines Layouts beginnend beim Einstiegspunkt des Routing unter Einbezug weiterer .layout.svelte-Dateien an alle nachfolgenden Webseiten weiter. Damit berücksichtigt SvelteKit beginnend bei der ersten +layout.svelte-Datei alle weiteren Layout-Deklarationen automatisch für die nachfolgenden Webseiten, die sich unterhalb der jeweiligen Route befinden.Enthält eine Routing-Hierarchie src/routes/gruppe/[artikel] eine +page.svelte-Datei, so erbt diese sämtliche Layouts aus den beiden Unterverzeichnissen gruppe und [artikel]. Damit erfolgt die Vererbung von einer Route zu einer anderen: Route-by-Route. Um innerhalb einer App das Layouting für eine bestimmte Webseite zu steuern, greift man auf die +page@-Notation zurück. Erhält eine Webseite den Dateinamen +page@[artikel].svelte, so berücksichtigt SvelteKit für das Layouting dieser Seite das Root-Layout und die +layout.svelte-Datei im Route-Ordner mit dem Namen [artikel]. Eine Komponente mit dem Dateinamen +page@.svelte übernimmt die Layouts der +layout.svelte-Datei im /src/routes-Ordner. Nachdem selben Verfahren, das heißt mittels dieser Notation, beeinflusst ein Programmierer über den Namen einer Layout-Datei auch die Vererbung innerhalb der Layouts. Eine Layout-Datei mit dem Namen +layout@.svelte im Ordner src/routes/dekan/fachbereich unterbricht ein Weiterreichen der Layout-Deklarationen indem es die oberhalb des eigenen Ordners fachbereich enthaltene +layout.svelte-Dateien nicht an die Unterverzeichnisse weiterreicht. Für das Layouting der +page.svelte-Datei in einem tieferstehenden Ordner src/routes/dekan/fachbereich/student zieht SvelteKit die +layout.svelte-Datei des eigenen und des Ordners fachbereich an – eine Vererbung darüberstehender Layouts findet nicht statt.
Ressourcen-schonende, effiziente Formulare auf dem Client und Server
Für die Programmierung von Formularen unterstützt Svelte(Kit) die in HTML spezifizierten Konstrukte: Beginnend mit dem form-Element und sämtliche Form-Controls mittels des <input>-Tags. Natürlich stehen auch alle für die <input>-Tags bekannten Attribute wie type, name, min/maxlength, placeholder und so weiter zur Verfügung:
<span class="hljs-tag"><<span class="hljs-name">script</span>></span>
<span class="actionscript"><span class="hljs-comment">// +page.svelte</span></span>
<span class="actionscript"><span class="hljs-comment"> /** @type {import('./$types').ActionData} */</span></span>
<span class="actionscript"><span class="hljs-comment"> import { enhance, applyAction } from '$app/forms';</span></span>
<span class="actionscript"><span class="hljs-comment"> import InteressentenTabelle from "$lib/components/InteressentenTabelle.svelte";</span></span>
<span class="actionscript"><span class="hljs-comment"> export let form;</span></span>
<span class="actionscript"><span class="hljs-comment"> export let data;</span></span>
<span class="hljs-tag"></<span class="hljs-name">script</span>></span>
<span class="hljs-tag"><<span class="hljs-name">h1</span>></span>Beispiel Formular-Management<span class="hljs-tag"></<span class="hljs-name">h1</span>></span>
<span class="hljs-tag"><<span class="hljs-name">div</span>></span>
<span class="hljs-tag"><<span class="hljs-name">form</span> <span class="hljs-attr">method</span>=<span class="hljs-string">"POST"</span> </span>
<span class="hljs-tag"> <span class="hljs-attr">use:enhance</span>=<span class="hljs-string">{({</span> <span class="hljs-attr">form</span> }) =></span> {
// Vor Uebertragung des Formulars auf den Server
return async ({ result, update }) => {
// Bei 'result' handelt es sich um ein 'ActionResult'-Objekt
// Nach der Uebetragung des Formulars auf den Server
if (result.type === 'success') {
form.reset();
}
if (result.type === 'invalid') {
await applyAction(result);
}
update();
};
}}
>
<span class="hljs-tag"><<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"name"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">span</span>></span>Name<span class="hljs-tag"></<span class="hljs-name">span</span>></span>
<span class="hljs-tag"></<span class="hljs-name">label</span>></span>
<span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"name"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Name eingaben"</span> <span class="hljs-attr">required</span> /></span>
<span class="hljs-tag"><<span class="hljs-name">label</span> <span class="hljs-attr">for</span>=<span class="hljs-string">"email"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">span</span>></span>E-Mail<span class="hljs-tag"></<span class="hljs-name">span</span>></span>
<span class="hljs-tag"></<span class="hljs-name">label</span>></span>
<span class="hljs-tag"><<span class="hljs-name">input</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"email"</span> <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"adresse@beispiel.com"</span> <span class="hljs-attr">required</span> /></span>
<span class="hljs-tag"><<span class="hljs-name">button</span>></span>Hinzufügen<span class="hljs-tag"></<span class="hljs-name">button</span>></span>
<span class="hljs-tag"></<span class="hljs-name">form</span>></span>
<span class="hljs-comment"><!-- Weiterreichen der Daten an die Svelte-Kompontente InteressentenTabelle --></span>
<span class="hljs-tag"><<span class="hljs-name">InteressentenTabelle</span> <span class="hljs-attr">interessenten</span>=<span class="hljs-string">{data?.interessenten}/</span>></span>
<span class="hljs-tag"></<span class="hljs-name">div</span>></span>
Ebenso lassen sich alle HTML-Tags mit ihren Elementen und Attributen innerhalb eines form-Elements nutzen. Von Vorteil erweist sich der Einsatz der bedingten HTML-Anweisung, die der Svelte-Compiler mittels des {#if-Statements bereitstellt. Damit führt der Webbrowser innerhalb eines <form>-Tags abhängig von der Auswertung des {#if-Statements bedarfsorientiert weitere HTML-Konstrukte aus.Zusätzlich zu diesen Features besitzt SvelteKit weitere, um Formulare ressourcen-schonend und effizient über die App zu behandeln. So führt SvelteKit sogenannte Form-Actions ein, um vom Client mittels POST-Request die Daten des Formulars auf dem Server zu verarbeiten. Bei den Form-Actions kennt SvelteKit grundsätzlich zwei verschiedene Typen, die über eine Export-Anweisung in einer +page.server.js/ts-Datei der zugehörigen Webseite +page.svelte zugänglich sind:
<span class="hljs-regexp">// +page.server.js</span>
<span class="hljs-regexp">/** @type {import('./$types').Actions} */</span>
<span class="hljs-regexp">let interessenten = []</span>
<span class="hljs-regexp">//</span> Definition der Form-Action default
export <span class="hljs-keyword">const</span> actions = {
default: async ({ request }) => {
<span class="hljs-keyword">const</span> formData = await request.formData()
<span class="hljs-keyword">const</span> name = formData.get(<span class="hljs-string">'name'</span>)
<span class="hljs-keyword">const</span> email = formData.get(<span class="hljs-string">'email'</span>)
<span class="hljs-keyword">const</span> interessent = {
name,
email
}
<span class="hljs-regexp">// Aufbau eines Interessenten-Arrays</span>
<span class="hljs-regexp"> interessenten.push(interessent)</span>
<span class="hljs-regexp"> //</span> Testen ueber die JavaScript-Console
<span class="hljs-regexp">// console.log('default:', interessenten)</span>
<span class="hljs-regexp"> return {</span>
<span class="hljs-regexp"> success: true,</span>
<span class="hljs-regexp"> }</span>
<span class="hljs-regexp"> }</span>
<span class="hljs-regexp">}</span>
<span class="hljs-regexp">//</span> Bereitstellen/Lesen von Daten ueber den Server fuer den Client
export <span class="hljs-keyword">const</span> load = () => {
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'load:'</span>, interessenten);
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'length: '</span>, interessenten.length);
<span class="hljs-keyword">return</span> {interessenten}
}
Der erste Typ der Form-Actions stellt die Default-Action dar, diese stößt der Client an, sobald er die Formulardaten über einen POST-Request an den Server weiterreicht. Anderen Svelte-Komponenten macht man eine Default-Action über eine Action-Anweisung auf eine Route-Link verfügbar.Den zweiten Typ von Form-Actions deklariert der Programmierer selbst; es handelt sich dabei um eine sogenannte Named-Action. Anstatt einer Default-Action kann es von den Named-Actions beliebig viele in der +page.server.js/ts-Datei geben. Damit innerhalb des form-Elements der Client für den POST-Request die relevante Form-Action anstößt, übergibt man diesem nach dem method="POST"-Attribut die zugehörige Named-Action in einem action-Attribut: action="?/bekannt". In diesem Beispiel kommt die Named-Action mit dem Namen bekannt in der +page.server.js/ts-Datei der Webseite zur Ausführung.Soll eine andere Svelte-Komponente eine Named-Action ausführen, so verknüpft man diese mit deren Route: action="/route… ?/bekannt". Jetzt führt der von SvelteKit generierte Code die Named-Action bekannt in der +page.server.js/ts-Datei aus, die über die Route /route… erreicht wird. Zusätzlich führt SvelteKit für HTML-Elemente innerhalb eines <form… >-Blocks ein sogenanntes formaction-Attribut ein. Über das formaction-Attribut bei einem HTML-Element deklariert der Programmierer, welche Named-Action ein POST-Request anzieht: <button formaction="?unbekannt">… – ein Klick auf die mit dem <button>-Tag verknüpfte Schaltfläche führt die Named-Action unbekannt aus.
Verarbeitung der einzelnen Formularfelder über die Web API
SvelteKit bietet über serverseitige Aktionen die Möglichkeit, auch wenn der Endbenutzer im Browser JavaScript ausgeschaltet, weiterhin eine Verarbeitung der App vorzunehmen. Für den Einsatz von TypeScript in der +page.server.ts-Datei benötigt man die Import-Anweisung: import type { Action } from "./$types". Der Entwickler programmiert innerhalb einer Form-Action die zugehörige Funktionalität und macht diese über den Funktionsnamen als Named-Action durch Export dem Client zugänglich. Anhand des request-Parameters der async Named-Action erhält der Programmierer Zugriff auf die Daten der Form: request.formData(). Dieser Aufruf liefert ein FormData-Objekt form zurück, dass sich anschließend mit dessen Methoden bearbeiten lässt.So greift man auf die einzelnen Felder des Formulars im Quellcode mittels form.get('nameFeld') zu; bei Einsatz von TypeScript fallen noch Konvertierungen auf einen bestimmten Datentyp an. Handelt es sich beim 'nameFeld' um Auswahllisten oder Checkboxen, so bestimmt die Methode getAll('nameFeld') über ein Array alle ausgewählten Datenwerte. Um alle Datenfelder des Formulars zusammen mit ihren Eingabewerte als Matrix zu erhalten, hilft die Anweisung: [...form.entries()], nur die Bezeichnungen der Datenfelder als Array: [...form.keys()] oder nur die Eingabewerte als Array liefert: [...form.values()]. Entsprechend dem request-Parameter steht in der Form-Action auch der event-Parameter zur Verfügung.Der Import: import { page } from '$app/stores' erschließt innerhalb der App über $page.form die Formulardaten und über $page.status den Zustand der jeweiligen Webseite. Bindet der Quellcode eine import-Anweisung für @sveltejs/kit ein, so erhält man Zugriff auf die Methoden zum Arbeiten mit Cookies. Dieser Import macht in SvelteKit-Actions für Redirects die redirect()-Funktion und für das Fehlerhandling die invalid()-Funktion verfügbar. Soll über ein Redirect eine andere Route angesteuert werden, so übergibt man invalid() als ersten Parameter einen Status-Code und als zweiten Parameter die gewünschte Route. Liegen keine Fehler vor, so liefert die Action return {success: true } zurück. Im Fehlerfall gibt return invalid() einen Status-Code für den Fehler zusammen mit den fehlerhaften Daten zurück.Einbezug der Client-Seite durch zusätzliche SvelteKit-Erweiterungen
Die Koordination zwischen der Verarbeitung am Server und am Client übernimmt SvelteKit. Innerhalb einer Webseite +page.svelte reicht eine load()-Funktion des Servers die Formulardaten an eine Svelte-Komponente des Clients weiter. Im Fallbeispiel gibt die Svelte-Komponente InteressentenTabelle.svelte die Formulardaten auf der Webseite über eine HTML-Tabelle aus (Bild 6):
<span class="hljs-tag"><<span class="hljs-name">script</span>></span>
<span class="actionscript"> <span class="hljs-comment">// InteressentenTabelle.svelte</span></span>
<span class="actionscript"><span class="hljs-comment"> export let interessenten = [];</span></span>
<span class="hljs-tag"></<span class="hljs-name">script</span>></span>
<span class="hljs-tag"><<span class="hljs-name">h1</span>></span>Tabelle der Interessenten<span class="hljs-tag"></<span class="hljs-name">h1</span>></span>
<span class="hljs-tag"><<span class="hljs-name">style</span>></span>
<span class="css"> <span class="hljs-selector-tag">table</span>, <span class="hljs-selector-tag">th</span>, <span class="hljs-selector-tag">td</span> {</span>
<span class="css"> <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span>;</span>
<span class="css"> <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid black; </span>
<span class="css"> <span class="hljs-attribute">border-collapse</span>: collapse;</span>
<span class="css"> }</span>
<span class="hljs-tag"></<span class="hljs-name">style</span>></span>
<span class="hljs-tag"><<span class="hljs-name">table</span> <span class="hljs-attr">align</span>=<span class="hljs-string">"left"</span>></span>
<span class="hljs-tag"><<span class="hljs-name">tbody</span>></span>
<span class="hljs-tag"><<span class="hljs-name">tr</span>></span>
<span class="hljs-tag"><<span class="hljs-name">th</span> <span class="hljs-attr">align</span>=<span class="hljs-string">"left"</span>></span>Name<span class="hljs-tag"></<span class="hljs-name">th</span>></span>
<span class="hljs-tag"><<span class="hljs-name">th</span> <span class="hljs-attr">align</span>=<span class="hljs-string">"left"</span>></span>E-Mail<span class="hljs-tag"></<span class="hljs-name">th</span>></span>
<span class="hljs-tag"></<span class="hljs-name">tr</span>></span>
<span class="hljs-comment"><!-- Das Array interessenten ausgeben --></span>
{#each interessenten as interessent}
<span class="hljs-tag"><<span class="hljs-name">tr</span>></span>
<span class="hljs-tag"><<span class="hljs-name">td</span>></span>{interessent.name}<span class="hljs-tag"></<span class="hljs-name">td</span>></span>
<span class="hljs-tag"><<span class="hljs-name">td</span>></span>{interessent.email}<span class="hljs-tag"></<span class="hljs-name">td</span>></span>
<span class="hljs-tag"></<span class="hljs-name">tr</span>></span>
{/each}
<span class="hljs-tag"></<span class="hljs-name">tbody</span>></span>
<span class="hljs-tag"></<span class="hljs-name">table</span>></span>
Prinzipiell rendert im Fehlerfall der Client die einer +page.svelte- oder einer +layout.svelte-Seite zugehörige +error.svelte-Komponente. Um der App auf dem Client eine bessere Reaktionsfähigkeit für die Interaktionen des Endbenutzers zu bieten, greift SvelteKit auf die use-Directive von Svelte zurück.

Die Daten von Interessentenüber ein Formular erfassen und über eine HTML-Tabelle ausgeben(Bild 6)
Simon
Dabei handelt es sich um eine sogenannte Svelte-Action, die der Svelte-Compiler als eigenständige Funktion dem DOM/HTML-Knoten einer Komponente zum Mount-Zeitpunkt hinzufügt. SvelteKit implementiert eine enhance-Funktion, um dem HTML form-Element zusätzliche Features hinzuzufügen. Dazu benötigt der <script>-Bereich neben dem export let form-Statement eine import { enhance applyAction } from '$app/forms'-Anweisung. Anschließend erhält der Programmierer im <form…-Tag mittels use:enhance… Zugriff auf verschieden SvelteKit-Features; diese bewirken eine Verarbeitung auf der Client-Seite ohne einen zusätzlich notwendigen Page-Reload.Zur Vermeidung eines Page-Reloads setzt SvelteKit also eine über use:enhance deklarierte Funktion ein. Diese mittels use:enhance deklarierte Funktion kommt vor der Übertragung der Formulardaten zur Ausführung; sie kennt die folgenden Parameter:Grundsätzlich aktualisiert der Client über use:enhance das form-Element sowohl im Erfolgs- als auch im Fehlerfall; ebenso den $page.status. Im Falle eines deklarierten Redirects kommt dieser zur Ausführung. Optional liefert die use:enhance-Funktion über ein Callback return async ({ result }) ein ActionResult-Objekt zurück, das anschließend die applyAction(result)-Methode bearbeitet. Dabei erhält die App anhand von result.type Zugriff auf den Erfolgs- (success) oder Fehlerfall (error). Natürlich lassen sich die Formulardaten auch clientseitig wie mit Svelte üblich in einem beim <form… on:…>-Attribut angegebenen Custom-Event-Listener verarbeiten.
Module und Environment-Variables in Svelte und SvelteKit
Der context="module"-Eintrag beim <script>-Tag zeichnet eine Svelte-Komponente als Modul aus. Mithilfe eines Moduls exportiert der Programmierer Funktionen, um sie in anderen Komponenten zu benutzen. Per Standard exportiert jede .svelte-Datei sich selbst als Komponente, daher gibt es keine default export-Anweisung in einer Svelte-Komponente. Von einer Komponente mit module-context exportierte Funktionen sind unabhängig von der Komponente selbst. Um dies zu gewährleisten, kommt der Quellcode in einem <script context="module">-Block sofort bei dessen erstmaliger Evaluierung zur Ausführung – eine Instanz der Komponente wird nicht benötigt. Im Normalfall führt Svelte den Quellcode innerhalb eines <script>-Blocks erst aus, wenn eine Instanz der Komponente initialisiert wird.Zusätzlich zu den im Svelte-Quellcode seitens des Programmierers implementierten Moduln macht SvelteKit eine Reihe weitere Moduln verfügbar. Für den Zugriff mittels einer Import-Anweisung auf diese Moduln nutzt SvelteKit den von Framework bereitgestellten Directory-Alias $app:Neben den über den Directory-Alias $app bereitgestellten Moduln erschließt SvelteKit noch weitere Moduln. Dazu gehört das Modul $service-worker; welches nur Service-Workern einer PWA (Progressive Web-App) zur Verfügung steht – es erschließt diesen Informationen über die App. Zusätzlich über stellt der Directory-Alias $env weitere bereit.So erhält der Programmierer abhängig vom jeweils importierten Modul Zugriff auf Umgebungsvariablen des Runtime ($env/dynamic/private, $env/dynamic/public) und auf von Vite geladene Umgebungsvariable ($env/static/private, $env/static/public). Kommt die App in der Entwicklungsumgebung zur Ausführung, greift $env/dynamic auf die Umgebungsvariablen der .env-Datei zurück. Eine in der .env-Datei deklarierte Umgebungsvariable ändert der Terminalbefehl npm run dev MY_VAR="wert" explizit ab. Beim Betrieb der App in der Produktion verwaltet der verwendete Adapter den Zugriff auf die Umgebungsvariable.Cookies für Identifizierung der Webseiten-Besucher
Beim zustandlosen HTTP-Protokoll sind für den Webserver die Seitenaufrufe immer als voneinander unabhängig anzusehen. Sollen Informationen über mehrere HTTP-Requests hinweg verwendet werden, so greift der Programmierer auf Cookies zurück. Ein Cookie entspricht einer Textinformation, die eine Web-App im Browser auf dem Endgerät des Seitenbesuchers speichert. Dabei übernimmt ein Cookie innerhalb der Web-App verschiedene Aufgaben; dazu zählen: Abspeichern eines Logins, die Identifizierung des Seitenbesuchers oder das Speichern eines Warenkorbs. Um einem Missbrauch von Cookies vorzubeugen, muss beim Nutzer die Einwilligung für deren Einsatz abgefragt werden. Zusätzlich erlauben alle gängigen Browser, dem Benutzer mehr oder weniger detailliert den Umgang mit Cookies über Web-Apps hinweg festzulegen.Um einen Webseiten-Besucher zuverlässig und möglichst unverwechselbar zu identifizieren, eignet sich der Einsatz einer UUID (Universally Unique Identifier). Bei der UUID handelt es sich um einen Standard für Identifikationsnummern, der von der OSF (Open Software Foundation) konzipiert wurde. Im Laufe der Zeit haben sich verschiedene Versionen der UUID etabliert; wobei die Version 4 relativ häufig zum Einsatz kommt. UUID in der Version 4 füllt alle frei belegbaren Stellen durch zufällig generierte Zeichen auf. Doppelte UUIDs können zwar auftreten, die Wahrscheinlichkeit dafür ist jedoch sehr gering. Beim Einsatz von UUID in Version 4 gelten doppelte UUIDs praktisch als irrelevant und sind daher in der Software nicht zu berücksichtigen. Um UUIDs in einer Web-App zu erzeugen, steht in der JavaScript-Welt das npm-Paket uuid zur Verfügung (Bild 7).
Das npm-Paket uuid besitzt ein Command-Line-Interface (CLI):Der Befehl uuid erzeugt eine UUDI, die aus einer 16-Byte-Zahl besteht, hexadezimal notiert und in fünf Gruppen unterteilt wird(Bild 7)
Simon
Da ein Cookie innerhalb der kompletten Web-App verfügbar sein soll, setzt man für deren Realisierung in SvelteKit sogenannte Hooks ein. Der Quellcode in einem Hook kommt beim Start der Web-App zum ersten Mal zur Ausführung. Insofern eignet sich der Einsatz eines Hooks für alle Initialisierungen wie zum Beispiel dem Aufbau einer Datenbank-Verbindung oder der Generierung einer UUID und deren Ablage in einem Cookie. Hooks, die auf dem Server ausgeführt werden, programmiert man in der src/hooks.server.js-Datei – für die Ausführung auf dem Client steht die src/hooks.client.js-Datei zur Verfügung. Die hooks.server.js-Datei kennt die handle()-Funktion, die SvelteKit immer ausführt, wenn der Server einen Request erhält. Dabei spielt es keine Rolle, ob dieser Request während der Ausführung der App oder mittels Prerendering entsteht. Als Ergebnis liefert handle() immer einen Response zurück.Beim Aufruf in hooks.server.js erhält handle() zwei Parameter: ein event-Objekt, welches den Request repräsentiert und eine resolve-Funktion, welche nachgelagert die Route rendert und einen response generiert. Mit dem response lassen sich header oder bodies verändern, oder SvelteKit vollständig umgehen, um eine Route direkt über das Programm zu erzeugen:
<span class="hljs-regexp">// hooks.server.js</span>
<span class="hljs-regexp">//</span> Zufaellig generierte UUIDs (Version <span class="hljs-number">4</span>)
<span class="hljs-keyword">import</span> { v4 as uuidv4 } <span class="hljs-keyword">from</span> <span class="hljs-string">'uuid'</span>;
<span class="hljs-comment">/** @type {import("@sveltejs/kit").Handle} */</span>
<span class="hljs-keyword">export</span> async <span class="hljs-keyword">function</span> handle({ event, resolve }) {
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">'Ausführung von hooks.server.js'</span>);
<span class="hljs-regexp">// Lesen der Cookie "session"</span>
<span class="hljs-regexp"> event.locals.user = event.cookies.get('session');</span>
<span class="hljs-regexp"> //</span> Ausgabe <span class="hljs-keyword">in</span> der JavaScript-Console
<span class="hljs-built_in">console</span>.log(<span class="hljs-string">"session: "</span>, event.locals.user);
<span class="hljs-regexp">// Keine session-Cookie vorhanden?</span>
<span class="hljs-regexp"> if (!event.locals.user) {</span>
<span class="hljs-regexp"> //</span> Neue session-Cokkie anlegen
event.cookies.set(<span class="hljs-string">'session'</span>, uuidv4(), { secure: <span class="hljs-literal">false</span>, httpOnly: <span class="hljs-literal">false</span> });
}
<span class="hljs-keyword">let</span> response = await resolve(event);
<span class="hljs-keyword">return</span> response;
}
Der Quellcode im Fallbeispiel gibt in der Console zu Testzwecken einen Text 'Ausführung von hooks.server.js' aus und bestimmt mittels get den Inhalt/Wert des Cookies mit dem Namen session. Sollte das Cookie nicht existieren, erscheint in der Console der Text "session: undefinded" – ansonsten der Wert des session-Cookies. Existiert die Cookie "session" noch nicht, erzeugt event.cookies.set diese; sie erhält als Wert eine UUID über den Aufruf von uuidv4().
Deployment einer SvelteKit-App automatisieren
Das Fallbeispiel soll über die Webseite den Wert des session-Cookies ausgegeben. Dies übernimmt im Quellcode der +page.server.js-Datei eine load()-Funktion. Anhand des Import von PageServerLoad erhält diese load()-Funktion als Parameter cookies übergeben. Mithilfe der get-Funktion von cookies bestimmt das Programm den Wert der Cookie "session" und macht diesen durch eine return-Anweisung über die sessionid der zugehörigen +page.svelte-Datei verfügbar:
// +page.server.js
/** @<span class="hljs-keyword">type</span> {import('./$types').<span class="hljs-type">PageServerLoad</span>} */
export async function load({ cookies }) {
// <span class="hljs-type">Die</span> <span class="hljs-type">Cookie</span> mit dem <span class="hljs-type">Namen</span> "session" lesen
const sessionid = cookies.get('session');
return {
sessionid
};
}
Der Name der Variable mit dem Wert der Cookie "session" muss sessionid lauten, da die Svelte-Komponente +page.svelte in der zugehörigen Webseite über PageData diese Variable bereitstellt:
<script>
<span class="hljs-comment">/** @type {import('./$types').PageData} */</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">let</span> data;
<span class="xml"><span class="hljs-tag"></<span class="hljs-name">script</span>></span></span>
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">h1</span>></span>Welcome to SvelteKit<span class="hljs-tag"></<span class="hljs-name">h1</span>></span></span>
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">p</span>></span>Visit <span class="hljs-tag"><<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"https://kit.svelte.dev"</span>></span>kit.svelte.dev<span class="hljs-tag"></<span class="hljs-name">a</span>></span> to read the documentation<span class="hljs-tag"></<span class="hljs-name">p</span>></span></span>
<span class="xml"><span class="hljs-tag"><<span class="hljs-name">h2</span>></span>Session-Cookie: {data.sessionid} <span class="hljs-tag"></<span class="hljs-name">h2</span>></span></span>
Um über die Svelte-Komponente den Wert der Cookie "session" auszugeben (Bild 8), greift man auf data.sessionid zu, das Dictionary data macht ebenfalls der Import von PageData zugänglich.

Die DevTools im Webbrowserzeigen über das Register Application bei Storage Cookies an, das dortige Kontextmenü hilft beim Bearbeiten ihrer Werte für Testzwecke(Bild 8)
Simon
Die im Wurzelverzeichnis eines Projekts enthaltene svelte.config.js-Datei deklariert alle wichtigen Aufgaben aus Sicht von Svelte und SvelteKit. Standardmäßig handelt es sich dabei um das Parsing der .svelte-Dateien und das Deployment einer App. Beim Compile-Vorgang nutzt SvelteKit auch den Preprocessor svelte-preprocess von Svelte. Über den zugehörigen Aufruf preprocess() lässt sich mittels optionaler Parameter das Parsing steuern. Dabei berücksichtigt Svelte grundsätzlich alle bekannten Preprozessoren wie Babel, CoffeeScript, Less, PostCSS, scss/sass, Stylus oder TypeScript. SvelteKit unterstützt auch den Einbezug von CSS-Frameworks in die Programmierung. Für den Einsatz zum Beispiel von Tailwind CSS bindet man über die svelte.config.js-Datei den postcss-Preprozessor ein (Bild 9) und nimmt die Tailwind-Direktiven in der app.css-Datei auf.

Das Web-Framework SvelteKitunterstützt die Programmierung mit CSS-Frameworks wie Tailwind CSS(Bild 9)
Simon
Das Deployment eine SvelteKit-App steuert der per Default eingestellte adapter-auto, den die Anweisung import adapter from '@sveltejs/adapter-auto' in die svelte.config.js-Datei importiert. Ein gleichzeitiges Deployment auf verschiedenen Plattformen unterstützt SvelteKit derzeit nicht. Eine derartige Anforderung muss im jeweiligen Projektumfeld selbst realisiert werden. Für ein Deployment über adapter-auto stehen die Plattformen: Azure Static Web App (derzeit im Beta-Status), Cloudflare Pages, Netlify und Vercel zur Verfügung. Für alle der genannten Plattformen gibt es auch einen speziellen eigenen Adapter: svelte-adapter-azure-swa, adapter-cloudflare, adapter-netlify und adapter-vercel.Auf den jeweils betroffenen Adapter greift der adapter-auto eigenständig zurück und nutzt dabei die für die jeweilige Plattform typischen Vorgaben. Nur besondere Einstellungen beim Deployment in die jeweilige Plattform benötigten den direkten Einsatz des speziellen Adapters in der svelte.config.js-Datei. In diesem Fall erfolgt zum einen ein Import des spezifischen Adapters und zum anderen eine Übergabe der gewünschten Einstellungen über optionale Parameter. Diese deklariert der DevOps-Mitarbeiter beim adapter()-Aufruf, um die vorgegebenen Standardeinstellungen zu überschreiben. Eventuell müssen auch weitere Konfigurationsdateien für den jeweiligen Adapter im SvelteKit-Projekt angelegt werden. Dabei handelt es sich in der Regel um Konfigurationsdateien für die jeweilige Deployment-Plattform.Eine derartige Konfigurationsdatei beschreibt die für das Deployment auf einer Plattform durchzuführenden Aufgaben. Somit kennt der jeweils spezifische Adapter die Besonderheiten der Deployment-Plattform und setzt diese über dessen Schnittstelle um.Neben dem Adapter adapter-auto enthält SvelteKit auch zwei weitere: adapter-node und adapter-static. Um einen der beiden anstatt dem standardmäßigen adapter-auto zu nutzen, importiert der DevOps-Mitarbeiter ihn in die svelte.config.js-Datei und übergibt dem adapter()-Aufruf die benötigten Parameter-Einstellungen. Während adapter-node auf das Deployment der SvelteKit-App in eine Node-Server-Umgebung abzielt, deckt adapter-static das Deployment statischer Websites und SPAs (Single-Page-Applications) ab.adapter-static führt ein vollständiges Prerendering der kompletten Website durch. Für teilweises Prerendering aufgrund der prerender-Option im Quellcode muss ein anderer Adapter eingesetzt werden.Für eine SPA unterstützt SvelteKit über die Einstellungen des Adapters verschiedene Strategien, um Probleme mit Performance und JavaScript zu umgehen. Insgesamt gesehen, deckt SvelteKit mit den drei Adapter adapter-auto, adapter-node und adapter-static bereits eine große Bandbreite an Deployment-Plattformen ab.Zudem berücksichtigt SvelteKit aufgrund der Implementierung dieser Adapter beim Deployment spezielle Einstellungen der jeweiligen Plattform. Ergänzend zu diesen Adaptern können DevOps-Mitarbeiter auch eigene Adapter implementieren und in den Deployment-Prozess mit SvelteKit integrieren. Als Alternative zu einem Adapter bietet sich ein eigenständiges Deploy-Script in der package.json-Datei an.
Programmierung einer Component-Library
Erst der Einsatz einer Component/Svelte-Library ermöglicht eine Automatisierung der Wiederverwendung: Änderungen in einer Komponente spiegeln sich automatisch in allen Programmteilen wider, die sie verwenden. Handelt es sich bei Änderungen nur um die Bereinigung von Fehlern, so fallen in der Regel auch keine Anpassungen im Quellcode an, solange die Schnittstelle der Komponente gleichbleibt. Ausgangspunkt für die Erstellung einer Component/Svelte-Library ist ein SvelteKit-Projekt das ein Library-Skeleton enthält. Dazu setzt der Entwickler in einem Terminal den Befehl npm create svelte@latest zusammen mit einem Library-Namen zum Beispiel comp-pool ab.Bei der ersten Frage von SvelteKit nach dem App-Template wählt man Library skeleton project für ein Library-Projekt aus. Soll die Bibliothek sowohl für JavaScript- als auch TypeScript-Projekte wiederverwendbar sein, legt man bei der zweiten Frage zum Type-Checking mit TypeScript die erste angebotene Option fest: JavaScript with JSDoc comments. Die Beantwortung der nachfolgenden Fragen zur statischen Quellcode-Analyse mit ESLint, der Code-Formatierung mit Prettier oder dem Browser-Testing mit Playwright orientiert sich an den Anforderungen des Projekts. Danach generiert SvelteKit den Projekt-Ordner und der Entwickler installiert über einen Paket-Manager (npm, pnpm, yard) die für das Library-Projekt benötigten npm-Pakete.Bei der Programmierung einer Komponenten-Bibliothek hilft ein CCM/Change-Configuration-Management-System beim Aufbau eines systematisches Änderungsmanagements für den Quellcode. Je höher der Grad an Wiederverwendung und die Einsatzbreite der in der Bibliothek enthaltenen Komponenten, umso schwieriger gestaltet sich deren Versionsverwaltung. Insofern erfordern bereits die initialen Phasen des Projekts eine detaillierte Planung des Änderungsmanagements. SvelteKit schlägt für diese Versionsverwaltung eine Git-basierte Lösung vor, was einen lokalen Git-Client voraussetzt. Zugriffe auf einen Git-Server beispielsweise GitHub erfordern einen individuellen Benutzer-Account.Infrastruktur für Versionsmanagement der Component-Library aufbauen
Direkt nach der Installation der für die Programmierung der Komponenten-Bibliothek erforderlichen npm-Pakete initialisieren die beiden Terminalbefehle: git init und git add [--all | -A] ein Git-Repository im Projekt-Ordner. Dabei erzeugt der erste Befehl git init im Projekt-Ordner ein .git-Unterverzeichnis mit den erforderlichen Metadaten für das Git-Repository. Der zweite Befehl git add [--all | -A] überführt die geänderten Dateien in einen Arbeits- oder Wartebereich zur Zwischenspeicherung der geänderten Projekt-Dateien für einen späteren Commit. Manche IDEs machen diesen Zustand dem Programmierer durch ein besonderes Icon-Symbol ersichtlich.Ein darauffolgender git commit -m "Initial commit"-Befehl erzeugt eine neue lokale Version der dort zwischengespeicherten Dateien. Üblicherweise fügt man beim ersten Commit der lokalen Version über den Parameter -m als Kommentar "Initial commit" hinzu. Einen derart definierten Kommentar zeigt git branch -vv dem Entwickler an. Für die Übertragung eines lokalen Repositorys muss das Library-Projekt mit einem konkreten Remote-Repository verknüpft sein. Dies erfordert ein Login beim Git-System (zum Beispiel GitHub), die Neuanlage eines Git-Repositorys und die Definition einer Verbindung des Git-Repositorys mit dem lokalen Library-Projekt (Bild 10).
GitHub gibt dem Projekt-Managermehrere Hilfestellungen bei der Anlage eines neuen Repositorys aus – hier: Für die Verknüpfung mit dem lokalen Library-Projekt(Bild 10)
Simon
Diese Verknüpfung trägt der git remote add origin-Befehl anhand der übergebenen URL zum GitHub-Repository in die .git-Meta-Daten ein. Vorhandene Verknüpfungen zeigt der Befehl git remote -v an. Danach überträgt der git push-Befehl die Änderungen in das Remote-Repository auf GitHub und übernimmt dabei "Initial commit" als beschreibenden Kommentar. Anschließend sehen andere Entwickler durchgeführte Änderungen im Quellcode und übernehmen diese über einen git pull-Befehl in ihr lokales Repository. Dazu muss vorher ein neuer Branch mittels git branch<name> erstellt und dieses durch git checkout <name> ausgecheckt werden. Ein git pull <remote> <branch>-Befehl lädt einen Remote-Branch in den lokalen Branch <branch> herunter.
Komponenten mit SvelteKit programmieren und testen
Das von SvelteKit generierte Library-Projekt besitzt im Unterschied zu einem App-Projekt im Verzeichnis src einen zusätzlich angelegten Ordner lib. Damit verschiebt sich der Arbeitsschwerpunkt in einem Library-Projekt eines Entwicklers vom Ordner /src/routes auf den Ordner /src/lib. Im lib-Unterzeichnis erfolgt die Programmierung aller Komponenten, die nach der Bereitstellung der Library als npm-Paket andere Entwickler wiederverwenden. Eine Component-Library besteht normalerweise aus mehreren Komponenten: Für jede Komponente legt ihr Programmierer in /src/lib eine .svelte-Datei an und stattet diese mit dem erforderlichen SvelteKit-Quellcode aus.Im Unterschied zu einem Entwicklungsprojekt für eine SvelteKit-App verwendet der Komponenten-Entwickler den Ordner /src/routes zur Ablage von Testfällen. Somit enthält das Entwicklungsprojekt der Component-Library eine SvelteKit-App, um die einzelnen Komponenten zu testen. Dies entspricht einer in das Projekt integrierten Testumgebung, in der ein Tester die von der jeweiligen Komponente bereitgestellte Schnittstelle auf die Erfüllung ihrer Anforderungen prüft. In einigen Fällen macht es auch Sinn, diese isolierte Testumgebung so zu erweitern, dass sie sich gleichzeitig für die Ablage der Dokumentation der Komponenten-Bibliothek eignet.Im neu angelegten lib-Ordner befindet sich zusätzlich eine neu generierte index.js-Datei. Parallel mit dem Schreiben des Quellcodes einer Komponente trägt der Programmierer in diese .js-Datei über eine import-Anweisung jede Komponente ein und macht sie mittels einer export-Anweisung extern zugänglich.Den generierten Inhalt der vorhandenen README.md-Datei löscht der Programmierer und dokumentiert mittels Markdown als Auszeichnungssprache Features und Handhabung der Komponenten-Bibliothek. Damit erfüllt das Library-Projekt alle Konventionen für den Einsatz von GitHub als CCM-System und die Ablage des npm-Pakets in der offiziellen npm-Registry. Die Verbindung zwischen dem npm-Package und dem Repository auf GitHub definiert der Eintrag repository in der package.json-Datei:<span class="hljs-string">"repository"</span>: {
<span class="hljs-string">"type"</span>: <span class="hljs-string">"git"</span>,
<span class="hljs-string">"url"</span>: <span class="hljs-string">"https://github.com/user-name/repo-url.git"</span>
},
Für eine Komponenten-Bibliothek erzeugt der Skeleton-Generator npm create svelte@latest von SvelteKit in der package.json-Datei einen anderen build-Befehl. Anstatt wie in einem Entwicklungsprojekt für eine SvelteKit-App üblich deren Build über vite build auszuführen, greift der build-Befehl im Falle eines Library-Projekts auf zwei andere Befehle zurück. Der Terminalbefehl npm run build im Projektverzeichnis führt das Package-Script svelte-kit sync && svelte-package aus. Der dabei verwendete &&-Operator führt zwei npm-Scripts sequentiell, eines nach dem anderen aus. Dabei stellt svelte-kit sync sicher, dass die aktuell benötigten Typ-Deklarationen und eine tsconfig.json-Datei vorliegen.Anschließend erzeugt svelte-package ausgehend vom Inhalt des Ordners src/lib ein neues Verzeichnis mit dem Namen package. In diesen package-Ordner legt der von SvelteKit eingesetzte Builder alle für das npm-Paket der Component-Library benötigten Dateien ab.Diesen Vorgang automatisiert der optionale Parameter [-w | --watch], so dass SvelteKit bei jeder Änderung in einer Datei des Ordners src/lib einen erneuten Build des npm-Pakets vornimmt. Dieses npm-Pakets macht die Komponenten des Library-Projekts anderen Entwicklern zugänglich. In der Regel kommt in JavaScript/TypeScript-Projekten für das Paket-Management von Bibliotheken und deren Bestandteile eine npm-Registry zum Einsatz.
Komponenten der Library wiederverwenden
Deshalb benötigt der Library-Manager (Entwickler der Componenten-Bibliothek) einen Account für den Zugriff auf eine npm-Registry. Die bekannteste npm-Registry stellt die Website npmjs.com zur Verfügung. Deren Betreiber die Firma npm Inc. bietet neben einer kostenlosen Free-, eine Pro- und eine Teams-Edition an.Ein Upgrade von der Free-Version auf eine der beiden anderen ist jederzeit möglich. Während die Free-Edition nur öffentlich zugängliche Packages unterstützt, erlauben Pro und Teams auch private Packages und Teams zusätzlich eine team-orientierte Zusammenarbeit. Nach erfolgreichem Build der Komponenten-Library und aktivem Login (npm adduser) auf npmjs.com überträgt der Terminalbefehl npm publish im package-Ordner das npm-Paket in die npm-registry.Um eine Komponenten-Library in einem Entwicklungsprojekt wiederzuverwenden, muss der Programmierer den Namen und die benötigte Versionsnummer des zugehörigen npm-Package kennen. Dazu greift der Builder beim Erzeugen des npm-Pakets auf den in der package.json-Datei stehenden Eintrag beim name- und version-Feld zurück. Grundsätzlich kennzeichnen Name und Versionsnummer eines npm-Package dieses eindeutig in einer npm-Registry.Alle verfügbaren Versionen in der öffentlich zugänglichen npm-registry eines npm-Pakets gibt der Befehl npm view <paketname> versions aus. Als Programmierer einer App installiert man eine Komponenten-Library wie jedes npm-Package über den Befehl npm install <paketname>@ <versionsnummer>.Installation der Komponenten-Library
Nach der Installation der Komponenten-Library stehen alle ihre Bestandteile für die Programmierung der App zur Verfügung. Dazu hat der npm install-Befehl in den node_modules-Ordner des App-Projekts das npm-Paket kopiert. Gleichzeitig hat npm install die Komponenten-Library in der package.json-Datei als Abhängigkeit in den "dependencies"-Bereich eingetragen. Während die Entwicklungsumgebung den Ordner mit dem npm-Paket im node_modules-Verzeichnis für die Codierung des Quellcodes verwendet, dient der Eintrag in der package.json-Datei dem Builder zur Erzeugung einer lauffähigen Version der App. Soll eine Library wieder aus einem Entwicklungsprojekt entfernt werden, kommt der Befehl npm remove <paketname> zum Einsatz. Dessen Ausführung entfernt beide Einträge, sowohl im node_modules-Ordner als auch in der package.json-Datei.Innerhalb eines Projektordners zeigt der Befehl npm list <paketname> die aktuell installierte Versionsnummer der Component-Library an. Damit prüft der npm list-Befehl, ob innerhalb des Entwicklungsprojekts die korrekte, das heißt für die App benötigte Version der Library installiert ist. Nach deren Installation erhält der Entwickler über eine import-Anweisung Zugriff auf die Library-Komponenten. Der Zugriff erfolgt über die Quellcode-Zeile import { <KompoName> } from '<npm-Paket>' im <script>-Bereich der Komponente. Anschließend kennt die Entwicklungsumgebung diese Svelte-Komponente. Der Programmierer greift in der zugehörigen Quellcode-Datei auf deren Leistungen mit der üblichen Svelte-Notation <KompoName … /> zu.Links zum Thema
<ul><li><b><a href="https://svelte.dev/" rel="noopener" target="_blank">Homepage von Svelte</a> <br/></b></li><li><b><a href="https://kit.svelte.dev/" rel="noopener" target="_blank">Homepage von SvelteKit</a> <br/></b></li><li><b><a href="https://github.com/sveltejs/realworld" rel="noopener" target="_blank">GitHub-Repository RealWorld-App realisiert mit SvelteKit</a> <br/></b></li><li><b><a href="https://sveltesociety.dev/" rel="noopener" target="_blank">Homepage der Svelte Society</a> <br/></b></li><li><b><a href="https://sveltesociety.dev/templates#svelte-kit" rel="noopener" target="_blank">Starter-Templates für SvelteKit</a> <br/></b></li><li><b><a href="https://github.com/uuidjs/uuid" rel="noopener" target="_blank">GitHub-Repository von uuid</a> <br/></b></li><li><b><a href="https://sveltesociety.dev/components#adapters" rel="noopener" target="_blank">Liste von der Svelte-Community bereitgestellten Adapter</a> <br/></b></li></ul>