A hitchhiker's guide to svelte.js

Farzad Yousefzadeh

HelsinkiJS Dec 2019

Farzad YousefZadeh

Formerly:

Aerospace engineer 🚀  astrophysicist 🌌

farzadyz.com

Svelte is a compiler

*.svelte

Almost no Runtime

Bare minimum a11y

DEAD code elimination

{
  c() {
    h1 = element("h1");
    t0 = text("Hello ");
    t1 = text(name);
    t4 = space();
    img = element("img");
  },
  m(target, anchor) {
    insert(target, h1, anchor);
    append(h1, t0);
    append(h1, t1);
    insert(target, t4, anchor);
    insert(target, img, anchor);
  }
};

Compiler output is readable!

Svelte is also a FRAmework

View: HTML template

logic: Javasript

Style: scoped + global css

App.svelte

// only 1 script
<script>
	
</script>

// only 1 style
<style>
	
	
</style>

// the rest is view
<p>Text</p>
<Test />

Every *.svelte file is a component

Module system

elements starting with lowercases

// App.svelte

<script>
  import Button from './Button.svelte'
</script>

<h1>Some title</h1>
<Button>Click me</Button>

Components starting with uppercases

component is default export of file

HTML template

<h1>HTML Tags</h1>

<a href="/pages/{nextPage}">Next</a>

<a href={nextPageURL}>Next</a>

<CustomComponent {...props} />

<p>Page is {currentPage}</p>

{#if expression}...{/if}
{#if expression}...{:else if expression}...{/if}
{#if expression}...{:else}...{/if}

{#each expression as name}...{:else}...{/each}

Suspending view

{#await promise}

  <!-- promise is pending -->
  <p>waiting for the promise to resolve...</p>
  
{:then value}

  <!-- promise was fulfilled -->
  <p>The value is {value}</p>
  
{:catch error}

  <!-- promise was rejected -->
  <p>Something went wrong: {error.message}</p>
  
{/await}

scoped & global styles


p {
  color: tomato; // p.svelte-1fj21zt{ color:tomato }
}

:global(.text) {
  color: teal; // .text{ color:teal }
}

:global(div > strong) {
  color: blue; // div > strong{ color:blue }
}

:global(body) {
  margin: 0; // body{ margin:0 }
}

div :global(strong) {
  color: goldenrod; // div.svelte-1fj21zt strong{ color:goldenrod }
}

props and state

<script>
  // props
  export searchQuery = ""
  export initialPageItems = []
  
  // state
  let fetchState = "pending"
  let allItems = [].concat(initialPageItems);
  
  // Normal variable
  const PER_PAGE = 10
</script>

lifecycle methods

<script>
  import {onMount, onDestroy, beforeUpdate, afterUpdate} from "svelte"
  
  onMount(() => {
    // code
    
    return () => {
      // cleanup
    }
  })
  
  onDestroy(() => {
    // cleanup
  })
</script>

svelte is reactive

Reactivity with assignment

reactive statements

parent-child communication

parent-child communication

parent-child communication

Distributed stores (writable stores)

import {writable} from "svelte/store"

export const userStore = writable({username: '', repos: []})

/*
  const unsub = userStore.subscribe(value => {
    // do something with updated value
  })
    
  userStore.update(currentState => newState)
    
  userStore.set(newState)
*/

Auto-subscribe (writable stores)

<script>
  import {timerStore} from './timerStore.js'
  
  let timer
  let id
  
  id = timerStore.subscribe(newTime => {
    timer = newTime
  })
  
  onDestory(() => {
    clearInterval(id)
  })
</script>

<p>Timer: {timer}</p>
<script>
  import {timerStore} from './timerStore.js'
</script>

<p>Timer: {$timerStore.value}</p>

Distributed stores (readable stores)

import {readable} from "svelte/store"

export const userStore = readable(defaultValue, (setState) => {
  setState(...)
  
  return () => {
   // unsubscribe
  }
})

Derived stores

import {readable} from "svelte/store"

export const userStore = readable(defaultValue, (setState) => {
  setState(...)
  
  return () => {
   // unsubscribe
  }
})

const start = new Date();

export const elapsed = derived(
  time,
  $time => Math.round(($time - start) / 1000)
);

Special elements

// recurive components
<svelte.self />

// bind to window events
// attach event handlers
<svelte.window />

// Same as Helmet in React
<svelte.head />

// attach to body events
// bind to body values
<svelte.body />

Dynamic children

// Button.svelte

<button>

  <slot></slot>
  
  <slot>
    <strong>Fallback of no children</strong>
  </slot>
  
</button>

compound components

// Button.svelte

<button>

  <slot name="icon"></slot>
  <slot name="text"></slot>
  
</button>


// App.svelte

<Button>
  <slot name="icon">
    <svg />
  </slot>
  
  <slot name="text">
    <em>Italic button text</em>
  </slot>
</Button>

Sum up

Next steps