Coffee Break
10:00 - 10:30
Lunch Break
12:00 - 13:00
Coffee Break
14:30 - 15:00
Begin
09:00
End
17:00
Svelte is a tool for building web applications. Like other user interface frameworks, it allows you to build your app declaratively out of components that combine markup, styles and behaviours.
Logo
Register
Home
E-Mail
Submit
etc. pp...
Component
Component
Component
These components are compiled into small, efficient JavaScript modules that eliminate overhead traditionally associated with UI frameworks.
<h1>Simple Component</h1>
Component.svelte
<h1>Simple Component</h1>
<h1>Simple Component</h1>
<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;
<h1>Simple Component</h1>
import { [...] } 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
<h1>Simple Component</h1>
import Component from "./Component.js";
const app = new Component({
target: document.body,
});
export default app;
main.js
<script>
// STATE & BEHAVIOR
</script>
<!-- DECLARATIVE MARKUP -->
<h1>Hello enterJS!</h1>
<p>{"Put your JS expressions in curly braces."}</p>
<style>
/* PRESENTATION */
</style>
Component.svelte
<script>
let count = 1
</script>
<output>
{count} + {count} = {count + count}
</output>
LocalState.svelte
on:
and bind:
.<script>
let count = 1
</script>
<input bind:value={count} />
<button on:click={() => count-- }>Decrease</button>
<button on:click={() => count-- }>Increase</button>
<output> Count: {count} </output>
Counter.svelte
{#if}
& {:else}
for conditionals and {#each}
for loops.{#await}
.<script>
let condition = false
</script>
<p> <input type="checkbox" bind:checked={condition} /> </p>
{#if condition}
<p>The condition is true!</p>
{:else}
<p>The condition is false!</p>
{/if}
IfElse.svelte
<script>
let promise = fetchSomething()
</script>
{#await promise}
<p>Loading...</p>
{:then value}
<p>The promise resolved with value '{value}'</p>
{:catch error}
<p>The promise rejected with value '{error}'</p>
{/await}
Await.svelte
<script>
let someIterable = [1, 2, 3, 4, 5]
</script>
<ul>
{#each someIterable as item}
<li>{item}</li>
{:else value}
<li>No items found</li>
{/each}
</ul>
Each.svelte
{#each}
block in Svelte is changed, elements are removed or added only at the end of the block.{@const}
tag can help with that.<script>
let edges = [2, 3, 4];
</script>
<h1>Cube calculations</h1>
{#each edges as edge}
{@const square = edge * edge}
{@const surface = 6 * square}
{@const volume = square * edge}
<output>
Edge length: {edge}m,
Total Surface: {surface}m²,
Volume: {volume}m³
</output>
{/each}
Cubes.svelte
=
operator and its variants are used in Svelte to establish data binding between variables and UI elements.<script>
let counter = 0;
const inc = () => counter++;
const dec = () => counter--;
</script>
<output>{counter}</output>
<button on:click={dec}>Decrease</button>
<button on:click={inc}>Increase</button>
Counter.svelte
<script>
let counter = 0;
$: doubled = counter * 2;
$: quadrupled = doubled * 2;
const inc = () => counter++;
const dec = () => counter--;
</script>
<b>x1</b>: {counter}<br>
<b>x2</b>: <output>{counter} * 2 = {doubled}</output><br>
<b>x4</b>: <output>{doubled} * 2 = {quadrupled}</output><br>
<button on:click={dec}>Decrease</button>
<button on:click={inc}>Increase</button>
Counter.svelte
class:
directive allows binding classes based on expressions.style:
directive allows setting individual style properties to expressed values.<script>
import P from './P.svelte'
let isBlue = false
</script>
<input type="checkbox" bind:checked={isBlue} />
<h2 style:color={isBlue ? "blue" : ""}>
This is blue, when isBlue is true.</h2>
<h2 class:isBlue>
This is blue, when isBlue is true.</h2>
<p> This is always red. </p>
<P> This is never red. </P>
<style>
.isBlue { color: blue; }
p { color: red; }
</style>
CSS.svelte
<p><slot /></p>
P.svelte
Logo
Register
Home
E-Mail
Submit
E-Mail
Submit
Register
Home
Logo
Logo
Register
Home
E-Mail
Submit
Logo
Register
Home
Submit
E-Mail
Submit
Register
Home
Logo
Logo
Register
Home
E-Mail
Submit
E-Mail
<Logo>
<Header>
<App>
<NavItem>
<NavItem>
<NavBar>
<Label>
<Input>
<Form>
<Button>
Logo
Register
Home
E-Mail
Submit
E-Mail
Submit
Register
Home
Logo
Logo
Register
Home
E-Mail
Submit
<script>
import Header from './Header.svelte'
import NavBar from './NavBar.svelte'
import Form from './Form.svelte'
</script>
<div class="wrapper">
<Header />
<NavBar />
<Form />
</div>
App.svelte
If I nest components within each other, how am I supposed to provide data from one to the other?
- Some person, somewhere
Register
Home
<NavItem>
<NavItem>
Register
Home
<NavItem >
<NavItem >
label="Home"
label="Register"
Register
Home
<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>
E-Mail
Submit
Register
Home
Logo
E-Mail
Submit
Logo
Register
Home
E-Mail
Submit
<App>
<Form>
E-Mail
Submit
Logo
Register
Home
E-Mail
Submit
<App>
<Form>
How?
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
async function submitForm() {
await postForm();
dispatch("form:posted", { /* 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:form:posted={handleSubmit} />
App.svelte
<slot>
element.Dialog
Text that is shown in the dialog. Potentially expanded by further content.
Okay
<strong>Dialog</strong>
<p>Text that is shown in the dialog. Potentially expanded by further content.</p>
<button>Okay</button>
<dialog>
<header><slot name="header" /></header>
<slot />
<footer><slot name="footer" /></footer>
</dialog>
Dialog.svelte
<script>
import Dialog from './Dialog.svelte'
</script>
<Dialog>
<h1 slot="header">Dialog Header (header slot)</h1>
<p>Dialog content (default slot)</p>
<svelte:fragment slot="footer">
<button>Cancel</button>
<button>Okay</button>
</svelte:fragment>
</Dialog>
App.svelte
<dialog>
<header><slot name="header" /></header>
<slot />
<footer><slot name="footer" /></footer>
</dialog>
Dialog.svelte
<script>
import Dialog from './Dialog.svelte'
</script>
<Dialog>
<h1 slot="header">Dialog Header (header slot)</h1>
<p>Dialog content (default slot)</p>
<svelte:fragment slot="footer">
<button>Cancel</button>
<button>Okay</button>
</svelte:fragment>
</Dialog>
App.svelte
<dialog>
<header><slot name="header" /></header>
<slot />
<footer><slot name="footer" /></footer>
</dialog>
Dialog.svelte
<script>
import Dialog from './Dialog.svelte'
</script>
<Dialog>
<h1 slot="header">Dialog Header (header slot)</h1>
<p>Dialog content (default slot)</p>
<svelte:fragment slot="footer">
<button>Cancel</button>
<button>Okay</button>
</svelte:fragment>
</Dialog>
App.svelte
<dialog>
<header><slot name="header" /></header>
<slot />
<footer><slot name="footer" /></footer>
</dialog>
Dialog.svelte
<script>
import Dialog from './Dialog.svelte'
</script>
<Dialog>
<h1 slot="header">Dialog Header (header slot)</h1>
<p>Dialog content (default slot)</p>
<svelte:fragment slot="footer">
<button>Cancel</button>
<button>Okay</button>
</svelte:fragment>
</Dialog>
App.svelte
SvelteKit is a framework for rapidly developing robust, performant web applications using Svelte. If you're coming from React, SvelteKit is similar to Next. If you're coming from Vue, SvelteKit is similar to Nuxt.
src/routes/
points to the root route.src/routes/login
points to a /login route.src/routes/posts/[id]
points to a post with the id passed in place of [id]
.The pages markup, styles and behavior. It may receive a data
or a form
prop.
The actual path to a specific route, rooted at the routes
folder in a SvelteKit code base.
Loads data on the client and on the server. Returns data available within the data
prop.
Loads data and processes forms on the server. Returns data available within data
and form
.
<script>
// data loaded in
// load functions
export let data
// data returned from
// form actions
export let form
</script>
<h1>Route Headline</h1>
<!-- any additional markup -->
+page.svelte
export function load () {
// any data loading logic
// that can run on client
// and server
return {
// any loaded data
}
}
+page.js
export function load () {
// any data loading logic
// that is server-only
return {
// any loaded data
}
}
export const actions = {
default() {
// default form action
},
namedAction() {
// named form action
}
}
+page.server.js
<script>
// data loaded in
// load functions
export let data
// data returned from
// form actions
export let form
</script>
<h1>Route Headline</h1>
<!-- any additional markup -->
+page.svelte
export function load () {
// any data loading logic
// that can run on client
// and server
return {
// any loaded data
}
}
+page.js
export function load () {
// any data loading logic
// that is server-only
return {
// any loaded data
}
}
export const actions = {
default() {
// default form action
},
namedAction() {
// named form action
}
}
+page.server.js
<script>
// data loaded in
// load functions
export let data
// data returned from
// form actions
export let form
</script>
<h1>Route Headline</h1>
<!-- any additional markup -->
+page.svelte
export function load () {
// any data loading logic
// that can run on client
// and server
return {
// any loaded data
}
}
+page.js
export function load () {
// any data loading logic
// that is server-only
return {
// any loaded data
}
}
export const actions = {
default() {
// default form action
},
namedAction() {
// named form action
}
}
+page.server.js
<script>
// data loaded in
// load functions
export let data
// data returned from
// form actions
export let form
</script>
<h1>Route Headline</h1>
<!-- any additional markup -->
+page.svelte
export function load () {
// any data loading logic
// that can run on client
// and server
return {
// any loaded data
}
}
+page.js
export function load () {
// any data loading logic
// that is server-only
return {
// any loaded data
}
}
export const actions = {
default() {
// default form action
},
namedAction() {
// named form action
}
}
+page.server.js
<script>
// data loaded in
// load functions
export let data
// data returned from
// form actions
export let form
</script>
<h1>Route Headline</h1>
<!-- any additional markup -->
+page.svelte
export function load () {
// any data loading logic
// that can run on client
// and server
return {
// any loaded data
}
}
+page.js
export function load () {
// any data loading logic
// that is server-only
return {
// any loaded data
}
}
export const actions = {
default() {
// default form action
},
namedAction() {
// named form action
}
}
+page.server.js
src/routes/+layout.svelte
applies to
src/routes/+page.svelte
, as well assrc/routes/login/+page.svelte
, etc.src/routes/+layout.svelte
wraps src/routes/login/+layout.svelte
Your+layout.svelte
files can also load data, via+layout.js
or+layout.server.js
.
<script>
export let data
</script>
<div class="wrapper">
<header>Headline</header>
<main>
<slot />
</main>
<footer>Footer</footer>
</div>
+layout.svelte
+page.js
) and server load functions (located in +page.server.js
).+layout.js
and +layout.server.js
, respectively).export function load () {
return {
someFlag: true
}
}
routes/+layout.server.js
export function load (event) {
const { parent } = event
const data = await parent();
return {
anotherFlag: !data.someFlag
}
}
routes/posts/+layout.server.js
export function load (event) {
const { parent } = event
const data = await parent();
const {
someFlag,
anotherFlag
} = data;
return {
// data based on someFlag
// and anotherFlag
}
}
routes/posts/+page.server.js
export function load () {
return {
someFlag: true
}
}
routes/+layout.server.js
export function load (event) {
const { parent } = event
const data = await parent();
return {
anotherFlag: !data.someFlag
}
}
routes/posts/+layout.server.js
export function load (event) {
const { parent } = event
const data = await parent();
const {
someFlag,
anotherFlag
} = data;
return {
// data based on someFlag
// and anotherFlag
}
}
routes/posts/+page.server.js
export function load () {
return {
someFlag: true
}
}
routes/+layout.server.js
export function load (event) {
const { parent } = event
const data = await parent();
return {
anotherFlag: !data.someFlag
}
}
routes/posts/+layout.server.js
export function load (event) {
const { parent } = event
const data = await parent();
const {
someFlag,
anotherFlag
} = data;
return {
// data based on someFlag
// and anotherFlag
}
}
routes/posts/+page.server.js
export function load () {
return {
someFlag: true
}
}
routes/+layout.server.js
export function load (event) {
const { parent } = event
const data = await parent();
return {
anotherFlag: !data.someFlag
}
}
routes/posts/+layout.server.js
export function load (event) {
const { parent } = event
const data = await parent();
const {
someFlag,
anotherFlag
} = data;
return {
// data based on someFlag
// and anotherFlag
}
}
routes/posts/+page.server.js
export function load () {
return {
someFlag: true
}
}
routes/+layout.server.js
export function load (event) {
const { parent } = event
const data = await parent();
return {
anotherFlag: !data.someFlag
}
}
routes/posts/+layout.server.js
export function load (event) {
const { parent } = event
const data = await parent();
const {
someFlag,
anotherFlag
} = data;
return {
// data based on someFlag
// and anotherFlag
}
}
routes/posts/+page.server.js
export function load ({ params }) {
const post = await getPost(params.id)
return {
post
}
}
routes/posts/[id]/+page.server.js
+page.server.ts
file alongside the load function.<form>
element with the POST
method.use:enhance
Svelte action.form
prop.<script>
import { enhance } from '$app/forms';
export let form;
</script>
<form method="POST" use:enhance>
{#if !form.success}
An error occurred!
{/if}
<input type="email" name="email">
<input type="password" name="password">
<button>Submit</button>
</form>
+page.svelte
import { fail } from '@sveltejs/kit';
export const actions = {
default({ request }) {
const formData = await request.formData();
const success = validateCredentials(
formData.get("email"),
formData.get("password")
)
if(!success) {
return fail(400, { success: false });
}
return { success: true };
}
}
+page.server.js
<script>
import { enhance } from '$app/forms';
export let form;
</script>
<form method="POST" use:enhance>
{#if !form.success}
An error occurred!
{/if}
<input type="email" name="email">
<input type="password" name="password">
<button>Submit</button>
</form>
+page.svelte
import { fail } from '@sveltejs/kit';
export const actions = {
default({ request }) {
const formData = await request.formData();
const success = validateCredentials(
formData.get("email"),
formData.get("password")
)
if(!success) {
return fail(400, { success: false });
}
return { success: true };
}
}
+page.server.js
<script>
import { enhance } from '$app/forms';
export let form;
</script>
<form method="POST" use:enhance>
{#if !form.success}
An error occurred!
{/if}
<input type="email" name="email">
<input type="password" name="password">
<button>Submit</button>
</form>
+page.svelte
import { fail } from '@sveltejs/kit';
export const actions = {
default({ request }) {
const formData = await request.formData();
const success = validateCredentials(
formData.get("email"),
formData.get("password")
)
if(!success) {
return fail(400, { success: false });
}
return { success: true };
}
}
+page.server.js
<script>
import { enhance } from '$app/forms';
export let form;
</script>
<form method="POST" use:enhance>
{#if !form.success}
An error occurred!
{/if}
<input type="email" name="email">
<input type="password" name="password">
<button>Submit</button>
</form>
+page.svelte
import { fail } from '@sveltejs/kit';
export const actions = {
default({ request }) {
const formData = await request.formData();
const success = validateCredentials(
formData.get("email"),
formData.get("password")
)
if(!success) {
return fail(400, { success: false });
}
return { success: true };
}
}
+page.server.js
error()
helper provided by SvelteKit.+error.svelte
file for the affected route hierarchy.handleError
hook.export function throwError() {
throw new Error();
}
some-module.js
import { error } from '@sveltejs/kit';
import { throwError } from './someModule.js'
export function load() {
if(!userIsAuthorized()) {
// expected error
error(401, {
message: "The user is not authorized."
});
}
// unexpected error
throwError()
return {
// ...data
}
}
+page.server.js
export function handleError({error}) {
// do error handling stuff
return {
message: "Error message",
//... other data
}
}
hooks.client.js
import { redirect } from '@sveltejs/kit';
export function handle({event, resolve}) {
if(event.url.pathname.startsWith("/api")
&& !userIsAuthorized()) {
redirect(302, "/login")
}
return resolve(event)
}
hooks.server.js
export function handleError({error}) {
// do error handling stuff
return {
message: "Error message",
//... other data
}
}
hooks.client.js
import { redirect } from '@sveltejs/kit';
export function handle({event, resolve}) {
if(event.url.pathname.startsWith("/api")
&& !userIsAuthorized()) {
redirect(302, "/login")
}
return resolve(event)
}
hooks.server.js
export function handleError({error}) {
// do error handling stuff
return {
message: "Error message",
//... other data
}
}
hooks.client.js
import { redirect } from '@sveltejs/kit';
export function handle({event, resolve}) {
if(event.url.pathname.startsWith("/api")
&& !userIsAuthorized()) {
redirect(302, "/login")
}
return resolve(event)
}
hooks.server.js
export function handleError({error}) {
// do error handling stuff
return {
message: "Error message",
//... other data
}
}
hooks.client.js
import { redirect } from '@sveltejs/kit';
export function handle({event, resolve}) {
if(event.url.pathname.startsWith("/api")
&& !userIsAuthorized()) {
redirect(302, "/login")
}
return resolve(event)
}
hooks.server.js
Schema.parse()
method, the result is either an object matching the schema or an error is thrown.Schema.safeParse()
method, the result is always an object with a success property and the parsed data or the error.import { z } from 'zod';
export const User = z.object({
name: z.string(),
age: z.number().optional(),
dateOfBirth: z.coerce.date()
})
// passes
let user = User.parse({name: "Karl", dateOfBirth: new Date()})
// throws
let user = User.parse({name: 3537, dateOfBirth: new Date() })
// throws
let user = User.parse({name: "Marlene", dateOfBirth: "not-a-date" })
User.js
import { zfd } from 'zod-form-data';
const Credentials = zfd.formData({
email: zfd.text(),
password: zfd.text()
});
export const actions = {
async login({request}) {
const credentials = Credentials.parse(
await request.formData()
);
const user = await loginWithCredentials(credentials);
return {
user
}
}
}
+page.server.js
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({
type: 'varchar',
length: 254
})
email: string;
@Column({
type: 'varchar',
length: 100,
})
password: string;
}
User.ts
const userRepository = datasource.getRepository(User);
function async addUser(email: string, password: string) {
const user = new User();
user.email = email;
user.password = encrypt(password);
await userRepository.save(user);
}
function async getUser(id: number) {
const user = userRepository.findOne({
where: {
id: id
}
})
}
function async deleteUser(id: number) {
await userRepository.delete(id);
}
userManagement.ts
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({
type: 'varchar',
length: 254
})
email: string;
@Column({
type: 'varchar',
length: 100,
})
password: string;
}
User.ts
const userRepository = datasource.getRepository(User);
function async addUser(email: string, password: string) {
const user = new User();
user.email = email;
user.password = encrypt(password);
await userRepository.save(user);
}
function async getUser(id: number) {
const user = userRepository.findOne({
where: {
id: id
}
})
}
function async deleteUser(id: number) {
await userRepository.delete(id);
}
userManagement.ts
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({
type: 'varchar',
length: 254
})
email: string;
@Column({
type: 'varchar',
length: 100,
})
password: string;
}
User.ts
const userRepository = datasource.getRepository(User);
function async addUser(email: string, password: string) {
const user = new User();
user.email = email;
user.password = encrypt(password);
await userRepository.save(user);
}
function async getUser(id: number) {
const user = userRepository.findOne({
where: {
id: id
}
})
}
function async deleteUser(id: number) {
await userRepository.delete(id);
}
userManagement.ts
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({
type: 'varchar',
length: 254
})
email: string;
@Column({
type: 'varchar',
length: 100,
})
password: string;
}
User.ts
const userRepository = datasource.getRepository(User);
function async addUser(email: string, password: string) {
const user = new User();
user.email = email;
user.password = encrypt(password);
await userRepository.save(user);
}
function async getUser(id: number) {
const user = userRepository.findOne({
where: {
id: id
}
})
}
function async deleteUser(id: number) {
await userRepository.delete(id);
}
userManagement.ts
LinkedIn:
Xing:
X: