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: und bind:.

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

  1. Füge eine Möglichkeit zum Löschen von Schätzungen ein
     
  2. 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

  1. Extrahiere die Bearbeitung von Schätzungen in eine Komponente
     
  2. 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 und derived.

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