Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Anzeige
Lesedauer 35 Min.

SvelteKit – Framework und Tools

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:
import { sveltekit } from '@sveltejs/kit/vite';
import type { UserConfig } from 'vite';
const config: UserConfig = {
    plugins: [sveltekit()],
    server: {
        port: 5000,
        strictPort: false,
    },
    preview: {
        port: 4000,
        strictPort: false,
    },
};
export default 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:
<script>
    import { page } from '$app/stores';
script>
<h1>{$page.status}: {$page.error.message}h>
 
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:

// +page.server.js
export async function load ({ fetch }) {
    const response = await fetch ('https://jsonplaceholder.typicode.com/users');
    // Rueckgabewerte von response in Console fuer Tests ausgeben
    // console.log(response.status); // 200
    // console.log(response.statusText); // OK
    if (response.status === 200) {
        const users = await response.json();
    return {
             // 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):

<script>
    export let data;
    // Zum Testen die erhaltenen Daten in der Console ausgeben
    // console.log(data)
script>
<h1>Welcome to SvelteKith1>
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.deva> to read the documentationp>
<h3>Liste der Benutzerh3>

<ul>
    {#each data.users as user}
        <li>
           <strong>Name: strong>{user.name}<br> 
           <strong>E-Mail: strong>{user.email}<br>
           <strong>Website: strong>{user.website}
        li>
    {/each}
ul>

 
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:

<script>
    import Footer from "$lib/Footer.svelte";
script>

<nav>
  <ul>
    <li><a href="/">Home  a>li>
    <li><a href="/about/">Über  a>li>
  ul>
nav>
<main>
  
  <slot />
main>

<nav>
  <ul>
    <li><a href="/impressum">Impressum  a>li>
    <li><a href="/kontakt/">Kontakt  a>li>
  ul>
nav>
<style lang="scss">
    nav ul { 
            list-style: none;
            padding: 3px 5px;
            background: rgb(202, 198, 198);
        }
    nav a {
            color: rgb(6, 6, 6);
            text-decoration: none;
        }
    nav a:hover {
                text-decoration: underline;
            }
    nav li {
            display: inline;
        }
style>


 
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:

<script>
// +page.svelte
    /** @type {import('./$types').ActionData} */
    import { enhance, applyAction } from '$app/forms';
    import InteressentenTabelle from "$lib/components/InteressentenTabelle.svelte";
    export let form;
    export let data;
script>
<h1>Beispiel Formular-Managementh1>
<div>
    <form  method="POST" 
        use:enhance={({ form }) => {
            // 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();
        };
      }}
    >
        <label for="name">
            <span>Namespan>
        label>
        <input type="text" name="name" placeholder="Name eingaben" required />
        
        <label for="email">
            <span>E-Mailspan>
        label>
        <input type="email" name="email" placeholder="adresse@beispiel.com" required />
        <button>Hinzufügenbutton>
  form>
  
  <InteressentenTabelle interessenten={data?.interessenten}/>
div>

 
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:

// +page.server.js
/** @type {import('./$types').Actions} */
let interessenten = []
// Definition der Form-Action default
export const actions = {
    default: async ({ request }) => {
        const formData = await request.formData()
        const name = formData.get('name')
        const email = formData.get('email')
        const interessent = {
              name,
              email
        }
        // Aufbau eines Interessenten-Arrays
        interessenten.push(interessent)
        // Testen ueber die JavaScript-Console
        // console.log('default:', interessenten)
        return {
              success: true,
        }
    }
}
// Bereitstellen/Lesen von Daten ueber den Server fuer den Client
export const load = () => {
    console.log('load:', interessenten);
    console.log('length: ', interessenten.length);
        return {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):

<script>
    // InteressentenTabelle.svelte
    export let interessenten = [];
script>
<h1>Tabelle der Interessentenh1>
<style>
    table, th, td {
    padding: 10px;
    border: 1px solid black; 
    border-collapse: collapse;
    }
style>    
<table align="left">
    <tbody>
        <tr>
            <th align="left">Nameth>
            <th align="left">E-Mailth>
        tr>
        
        {#each interessenten as interessent}
            <tr>
                <td>{interessent.name}td>
                <td>{interessent.email}td>
            tr>
        {/each}
    tbody>
table>

 
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:

// hooks.server.js
// Zufaellig generierte UUIDs (Version 4)
import { v4 as uuidv4 } from 'uuid';
/** @type {import("@sveltejs/kit").Handle} */
export async function handle({ event, resolve }) {
    console.log('Ausführung von hooks.server.js');
    // Lesen der Cookie "session"
    event.locals.user = event.cookies.get('session');
    // Ausgabe in der JavaScript-Console
    console.log("session: ", event.locals.user);
    // Keine session-Cookie vorhanden?
    if (!event.locals.user) {
        // Neue session-Cokkie anlegen
        event.cookies.set('session', uuidv4(), { secure: false, httpOnly: false });
    }
    let response = await resolve(event);
    return 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
/** @type {import('./$types').PageServerLoad} */
export async function load({ cookies }) {
    // Die Cookie mit dem Namen "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:


                
Anzeige
Anzeige
Anzeige
Anzeige