Web-Apps mit Svelte
Ein praktischer Einstieg
Der Trainer
- Nils Röhrig
- Software Engineer @ REWE digital
- Frontend-Fokus
- Svelte-Nutzer seit 2019
- Speaker auf Konferenzen und Meetups
Agenda
2. Kommunikation
- Verschachtelung
- Props
- Event Dispatching
- Event Forwarding
- Events oder Callbacks
1. Grundlagen
- Framework
- Lokaler State
- Direktiven
- Kontrollstrukturen
- CSS Support
- Reaktivität
3. Zustand
- Svelte Stores
- Custom Stores
- Svelte Kontext
- Stores im Kontext
4. Goodies
- Komponenten-Slots
- Arbeit mit Promises
- DOM-Referenzen
- Svelte Actions
- SVG-Support
- Transitionen
Kaffepause
10:30 - 11:00
Mittagspause
12:30 - 13:30
Kaffepause
15:00 - 15:30
Genereller Ablauf
Genereller Ablauf
Vorstellung der Konzepte des Kapitels mit Beispielen
Live Coding der Workshop-App durch Trainer
Übung der Inhalte durch Teilnehmer:innen
Lösungsvorschlag des Trainers
1. Grundlagen
Svelte ist ein Komponenten-Framework
Svelte ist ein Komponenten-Framework
Logo
Register
Home
E-Mail
Submit
Svelte ist ein Komponenten-Framework
Logo
Register
Home
E-Mail
Submit
Komponente
Svelte ist ein Komponenten-Framework
Logo
Register
Home
E-Mail
Submit
Komponente
Komponente
Svelte ist ein Komponenten-Framework
Logo
Register
Home
E-Mail
Submit
Komponente
Komponente
Komponente
Svelte ist ein Komponenten-Framework
Logo
Register
Home
E-Mail
Submit
Komponente
Komponente
Komponente
etc. pp...
Svelte ist ein Compiler
Svelte ist ein Compiler
<h1>Simple Component</h1>
Component.svelte
Svelte ist ein Compiler
<h1>Simple Component</h1>
Svelte ist ein Compiler
<h1>Simple Component</h1>
Svelte ist ein Compiler
<h1>Simple Component</h1>
import { SvelteComponent, detach, element, init,
insert, noop, safe_not_equal } from "svelte/internal";
function create_fragment(ctx) {
let h1;
return {
c() {
h1 = element("h1");
h1.textContent = "Simple Component";
},
m(target, anchor) {
insert(target, h1, anchor);
},
p: noop,
i: noop,
o: noop,
d(detaching) {
if (detaching) detach(h1);
},
};
}
class SimpleComponent extends SvelteComponent {
constructor(options) {
super();
init(this, options, null, create_fragment, safe_not_equal, {});
}
}
export default SimpleComponent;
Svelte ist ein Compiler
<h1>Simple Component</h1>
/* Component.svelte generated by Svelte v3.57.0 */
import { SvelteComponent, detach, element, init, insert, noop,
safe_not_equal } from "svelte/internal";
function create_fragment(ctx) {
let h1;
return {
c() {
h1 = element("h1");
h1.textContent = "Simple Component";
},
m(target, anchor) {
insert(target, h1, anchor);
},
p: noop,
i: noop,
o: noop,
d(detaching) {
if (detaching) detach(h1);
},
};
}
class Component extends SvelteComponent {
constructor(options) {
super();
init(this, options, null, create_fragment, safe_not_equal, {});
}
}
export default Component;
Component.js
Svelte ist ein Compiler
<h1>Simple Component</h1>
import Component from "./Component.js";
const app = new App({
target: document.body,
});
export default app;
main.js
Dateistruktur
Dateistruktur
<script>
// STATE & BEHAVIOR
</script>
<!-- DECLARATIVE MARKUP -->
<h1>Hello JSDays!</h1>
<p>{"Put your JS expressions in curly braces."}</p>
<style>
/* PRESENTATION */
</style>
Component.svelte
Lokaler State
Lokaler State
- Der lokale Komponenten-State in Svelte besteht aus lokalen Variablen.
- Er beschreibt den Zustand der Komponente und ist nicht mit anderen Komponenten geteilt.
- Der lokale State ist reaktiv im Svelte-Sinne, d.h. bei Änderungen werden nur die betroffenen Teile der Komponente aktualisiert.
Lokaler State
Direktiven
Direktiven
- Svelte-Direktiven sind als Attribute in Svelte-Elementen verwendbar.
- Sie können das Verhalten von Elementen steuern, z.B. durch das Binden von Daten oder das Behandeln von Ereignissen.
- Svelte bietet verschiedene Direktiven an, die das Verhalten von Elementen steuern können, wie z.B.
on:
undbind:
.
Direktiven
Kontrollstrukturen
Kontrollstrukturen
- Kontrollstrukturen sind ein integraler Bestandteil des Svelte-Markups.
- Sie regeln den Programmfluss und sind aus anderen Programmiersprachen bekannt.
- Svelte bietet eine Block-Syntax für Kontrollstrukturen, die verschiedene Ausdrücke wie
if
,else
,each
, und andere unterstützt.
Kontrollstrukturen
Veränderung des Wertes eines {#each}
-Blocks
- Wenn der Wert eines
{#each}
-Blocks in Svelte geändert wird, werden nur am Ende des Blocks Elemente entfernt oder hinzugefügt.
- Geänderte Elemente werden an derselben Stelle im DOM aktualisiert.
- Verwendung von eindeutigen IDs kann unerwünschte Effekte vermeiden, wenn gerenderte Elemente nicht direkt oder reaktiv von der Änderung des Werts abhängig sind.
Keyed Each Block
Lokale Konstanten
Reaktivität
Reaktivität
- Svelte integriert Reaktivität als Kernelement.
- Der
=
-Operator und seine Varianten werden in Svelte verwendet, um Datenbindung zwischen Variablen und UI-Elementen herzustellen.
- Svelte verfolgt Abhängigkeiten zwischen Variablen und aktualisiert nur die Teile des DOM, die davon betroffen sind.
- Durch Build-Time-Tracking der Zuweisungen wird der Code optimiert.
- Svelte bietet Sprachunterstützung wie Reactive Statements.
Reaktivität
CSS Support
CSS Support
- CSS ist Teil des Single-File-Component-Ansatzes in Svelte.
- Styles sind automatisch scopiert, um Konflikte zu vermeiden.
- Direktiven ermöglichen das Binding von Klassen.
- Es gibt auch Direktiven zum gezielten Setzen einzelner CSS-Properties.
CSS Support
Live Coding
Übung
Übung
- Füge eine Möglichkeit zum Löschen von Schätzungen ein
- Füge eine Möglichkeit zum Bearbeiten von Schätzungen ein
Aufgaben
Hinweise
- Beschränke dich auf Techniken aus Kapitel 1
- crypto.randomUUID() erzeugt eine zufällige UUID
git checkout tags/chapter_1_exercise -b <BRANCH_NAME>
npm ci
npm run dev
Vorbereitung
nilsroehrig/svelte-workshop-revisited
Repository
Lösungsvorschlag
2. Kommunikation
2. Kommunikation
- Verschachtelung
- Props
- Event Dispatching
- Event Forwarding
- Events oder Callbacks
Verschachtelung von Komponenten
Verschachtelung von Komponenten
E-Mail
Submit
Register
Home
Logo
Verschachtelung von Komponenten
E-Mail
Submit
Register
Home
Logo
Logo
Register
Home
E-Mail
Submit
Logo
Register
Home
E-Mail
Submit
Logo
Register
Home
E-Mail
Submit
E-Mail
Submit
Register
Home
Logo
Logo
Register
Home
E-Mail
Submit
Logo
Register
Home
E-Mail
Submit
E-Mail
Submit
Register
Home
Logo
<Logo>
<Header>
<App>
<NavItem>
<NavItem>
<NavBar>
<Label>
<Input>
<Form>
<Button>
Verschachtelung von Komponenten
Props
Props
Register
Home
Props
<NavItem>
<NavItem>
Register
Home
Props
<NavItem >
<NavItem >
label="Home"
label="Register"
Register
Home
Props
<script>
const str = "a string";
const num = 12345;
const bool = true;
const obj = {key: "value"};
const arr = [1, 2, 3, 4, 5];
function callback() {
console.log("callback");
}
</script>
<AnyComponent
stringProp={str}
numberProp={num}
booleanProp={bool}
objectProp={obj}
arrayProp={arr}
{callback}
/>
Props
<script>
const str = "a string";
const num = 12345;
const bool = true;
const obj = {key: "value"};
const arr = [1, 2, 3, 4, 5];
function callback() {
console.log("callback");
}
</script>
<AnyComponent
stringProp={str}
numberProp={num}
booleanProp={bool}
objectProp={obj}
arrayProp={arr}
{callback}
/>
<script>
export let stringProp = "";
export let numberProp = 0;
export let booleanProp = true;
export let objectProp = {key: "value"};
export let arrayProp = [1, 2, 3];
export let callback = () => undefined;
</script>
<p>{stringProp}</p>
<p>{numberProp}</p>
<p>{booleanProp}</p>
{#each Object.entries(objectProp) as [key, value]}
<p>{key}: {value}</p>
{/each}
{#each arrayProp as value}
<p>{value}</p>
{/each}
<button on:click={callback}>Call back</button>
Props
$$props
& $$restProps
Event-Dispatching
Event-Dispatching
E-Mail
Submit
Register
Home
Logo
Event-Dispatching
E-Mail
Submit
Logo
Register
Home
E-Mail
Submit
<App>
<Form>
Event-Dispatching
E-Mail
Submit
Logo
Register
Home
E-Mail
Submit
<App>
<Form>
Wie?
Event-Dispatching
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
async function submitForm() {
await postForm();
dispatch("submit", { /* any information to share */ });
}
</script>
<form on:submit={submitForm}>
<!-- form content -->
</form>
Form.svelte
Event-Dispatching
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
async function submitForm() {
await postForm();
dispatch("submit", { /* any information to share */ }
}
</script>
<form on:submit={submitForm}>
<!-- form content -->
</form>
Form.svelte
<script>
import Form from './Form.svelte';
function handleSubmit(event) {
/* here the shared information can be found,
* as Svelte events are just instances of
* CustomEvent */
const { detail } = event;
console.log({detail});
}
</script>
<Form on:submit={handleSubmit} />
App.svelte
Event-Dispatching
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
async function submitForm() {
await postForm();
dispatch("submit", { /* any information to share */ }
}
</script>
<form on:submit={submitForm}>
<!-- form content -->
</form>
Form.svelte
<script>
import Form from './Form.svelte';
function handleSubmit(event) {
/* here the shared information can be found,
* as Svelte events are just instances of
* CustomEvent */
const { detail } = event;
console.log({detail});
}
</script>
<Form on:submit={handleSubmit} />
App.svelte
Event-Dispatching
Event-Forwarding
Event-Forwarding
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
async function submitForm() {
await postForm();
dispatch("submit", { /* any information to share */ }
}
</script>
<form on:submit={submitForm}>
<!-- form content -->
</form>
Form.svelte
<script>
import Form from './Form.svelte';
function handleSubmit(event) {
/* here the shared information can be found,
* as Svelte events are just instances of
* CustomEvent */
const { detail } = event;
console.log({detail});
}
</script>
<Form on:submit={handleSubmit} />
App.svelte
Event-Forwarding
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
async function submitForm() {
await postForm();
dispatch("submit", { /* any information to share */ }
}
</script>
<form on:submit={submitForm}>
<!-- form content -->
</form>
Form.svelte
<script>
import Form from './Form.svelte';
function handleSubmit(event) {
/* here the shared information can be found,
* as Svelte events are just instances of
* CustomEvent */
const { detail } = event;
console.log({detail});
}
</script>
<Form on:submit={handleSubmit} />
App.svelte
Event-Forwarding
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
async function submitForm() {
await postForm();
dispatch("submit", { /* any information to share */ }
}
</script>
<form on:submit={submitForm}>
<!-- form content -->
</form>
Form.svelte
<script>
import Form from './Form.svelte';
function handleSubmit(event) {
/* here the shared information can be found,
* as Svelte events are just instances of
* CustomEvent */
const { detail } = event;
console.log({detail});
}
</script>
<Form on:submit={handleSubmit} />
App.svelte
Event-Forwarding
<form on:submit>
<!-- form content -->
</form>
Form.svelte
<script>
import Form from './Form.svelte';
async function handleSubmit(event) {
const data = FormData(event.target);
await postData(data);
}
</script>
<Form on:submit={handleSubmit} />
App.svelte
Event-Forwarding
Events vs. Callbacks
Events vs. Callbacks
<script>
import AnotherComponent from './AnotherComponent.svelte';
function callback() {
console.log("I am a callback. Arguments: ", ...arguments);
}
</script>
<AnotherComponent {callback} />
<script>
export let callback;
</script>
<button on:click={callback}>
Click me!
</button>
Component.svelte
AnotherComponent.svelte
Events vs. Callbacks
<script>
import Button from './Button.svelte';
function handleButtonElementClick() {
console.log("Button element clicked.");
}
function handleButtonComponentClick() {
console.log("Button component clicked.");
}
</script>
<button on:click={handleButtonElementClick}>Button element</button>
<Button onClick={handleButtonComponentClick}>Button Component</Button>
Events vs. Callbacks
Live Coding
Übung
Übung
git checkout tags/chapter_2_exercise -b <BRANCH_NAME>
npm ci
npm run dev
Vorbereitung
nilsroehrig/svelte-workshop-revisited
Repository
- Extrahiere die Bearbeitung von Schätzungen in eine Komponente
- Finde Möglichkeiten für Synergieeffekte durch Extraktion und wende sie an
Aufgaben
Hinweise
- Beschränke dich auf Techniken aus Kapitel 1 und 2
- Einzelne Bestandteile von Seiten (z.B. Formulare), kannst du gerne extrahieren
Lösungsvorschlag
3. State Management
3. State Management
- Svelte Stores
- Custom Stores
- Svelte Context
- Stores im Kontext
Svelte Stores
Svelte Stores
- Stores sind JavaScript-Objekte, die Werte kapseln und über eine
.subscribe
-Methode abonniert werden können.
- Abonnenten werden über Aktualisierungen benachrichtigt.
- Svelte bietet Sprachunterstützung für die Verwendung von Stores.
- Es gibt verschiedene Arten von mitgeliferten Stores, namentlich
readable
,writable
undderived
.
Svelte Stores
Svelte Store Contract
- Ein Store muss eine
.subscribe
-Methode enthalten, die als Argument eine Subscription-Funktion akzeptiert, um ein Abo zu erstellen.
- Die Subscription-Funktion muss sofort und synchron mit dem aktuellen Wert des Stores aufgerufen werden, wenn
.subscribe
aufgerufen wird.
- Alle aktiven Subscription-Funktionen des Stores müssen später synchron aufgerufen werden, wenn sich der Wert des Stores ändert.
-
.subscribe
muss eine Unsubscribe-Funktion zurückgeben. Deren Aufruf muss das Abo beenden und die entsprechende Subscription-Funktion darf nicht erneut vom Store aufgerufen werden.
- Ein Store kann optional eine
.set
-Methode enthalten, welche als Argument einen neuen Wert akzeptiert und den Store damit aktualisiert. Ein solcher Store wird als Writable Store bezeichnet.
Custom Stores
Custom Stores
Svelte Kontext
Svelte Kontext
Stores im Kontext
Stores im Kontext
Live Coding
Übung
Übung
git checkout tags/chapter_3_exercise -b <BRANCH_NAME>
npm ci
npm run dev
Vorbereitung
nilsroehrig/svelte-workshop-revisited
Repository
1. Finde einen Weg, die Werte aus der Estimation-Liste in einem Custom Store zu spreichern und über diesen Store zu aktualisieren.
Aufgaben
Hinweise
- Beschränke dich auf bisher gelernte Techniken
- Stores sind Observables und können abonniert werden
git checkout 9129682
Lösungsvorschlag
4. Fortgeschrittene Features
4. Fortgeschrittene Features
- Komponenten-Slots
- Arbeit mit Promises
- DOM-Referenzen
- Svelte Actions
- SVG-Support
- Transitionen
Komponenten-Slots
Komponenten-Slots
Dialog
Text der im Dialog angezeigt wird. Potenziell ergänzt um weiteren Content.
Okay
Komponenten-Slots
<strong>Dialog</strong>
<p>Text der im Dialog angezeigt wird. Potenziell ergänzt um weiteren Content.</p>
<button>Okay</button>
Komponenten-Slots
Arbeit mit Promises
Arbeit mit Promises
Komponente Rendern
Daten Abrufen
Anzeige Aktualisieren
Arbeit mit Promises
Komponente Rendern
Daten Abrufen
Anzeige Aktualisieren
Arbeit mit Promises
Transitionen
Transitionen
Transitionen
Refs & Actions
Refs & Actions
SVG Support
SVG Support
Live Coding
Übung
Übung
git checkout tags/chapter_4_exercise -b <BRANCH_NAME>
npm ci
npm run dev
Vorbereitung
nilsroehrig/svelte-workshop-revisited
Repository
1. Vervollständige die Bearbeitung von Schätzungen, sodass Stories bearbeitet und geschätzt werden können.
Aufgaben
Hinweise
- Beschränke dich auf bisher gelernte Techniken
Web-Apps mit Svelte (JSDays Munich 2023)
By Nils Röhrig
Web-Apps mit Svelte (JSDays Munich 2023)
- 1,512