Dan Matthews

Why you should consider Svelte for your next Laravel project.

Svelte is still thought of by some as the new kid on the block in the javascript world, but it's got some really endearing features, is stable and mature, and feels light and nimble to use.

I thought it would be criminal of me not to take you on a little tour of some of my favourite parts.

Most of the things i'm going to talk about are available if you're using Svelte on it's own, through InertiaJS or in SvelteKit, which is sort of like Next.js for Svelte.

It's fast! (and small)

Svelte isn't like React or Vue - it's a compiled framework, while React is an interpreted framework. This means that Svelte converts your code into optimized vanilla JavaScript at build time, rather than relying on the browser to interpret and execute it at runtime. This can make Svelte apps faster and more efficient, particularly on lower-end devices.

Also, it's small, this article outlines some of the differences in bundle size:

Svelte’s .gzip version has a size of 1.6 kilobytes. React.gzip, when combined with ReactDOM, has a total size of 42.2 kilobytes. The smaller bundle size of Svelte ensures faster loading speeds, better responsiveness, and lower bandwidth costs.

It's syntax is friendlier (proper if/else statements!)

If you're a JSX convert that's absolutely fine, but for me, i like writing HTML! And you know what I love the MOST about Svelte? The fact it has proper if/else blocks unlike other frameworks - a nice benefit of it being a compiled framework.

For example, in React you might see something like:

<div>
  {name && (<p>{name}</p>)}
  {!name && (<p>Name Unknown</p>)}
</div>

That's hard to read and... it just looks ugly. Here's Vue (which is actually way nicer & cleaner anyway):

<div v-if="name">{{ name }}</div>
<div v-else>No Name</div>

But here's Svelte's version:

{#if name}
My name is {name}
{:else}
This user has no name
{/if}

Easy to read, parse, and clearly defined - they're conditionals like you would just use in normal JS or PHP.

Your 'state' is just variables 🤷‍♂️

You define your 'state' by declaring variables and...using them.

<script>

const shouldShowWelcome = false;

const name = "Dave";

const showWelcome = () => {
	shouldShowWelcome = true;
}

</script>

{#if shouldShowWelcome}
	<!-- Hi there Dave, how are you today? -->
	<p>Hi there {name}, how are you today?</p>
{/if}

<button on:click={showWelcome}>Show Welcome</button>

'Props' are just variables too

You access props in Svelte by simply declaring them as exported member variables!

With a component like this:

<TitleComponent title={'Hello There!'} />

You can access (and set a default), simply by writing your component like this:

<script>
	export let title = undefined;
</script>

{#if title}
	<h1>{title}</h1>
{/if}

Or set a default and get rid of the {#if}:

<script>
	export let title = "Welcome to my blog";
</script>

<h1>{title}</h1>

Ooh look, there's that nice {#if} block again too 😉

Watch any variable or expression easily with Reactive Declarations

The $: statement in Svelte takes some getting used to - but it is IMMENSELY powerful. You use it to run expressions or functions that need to be re-ran when something changes.

For example:

<script>
	
	// These are passed as props.
	export let firstName = '';
	export let lastName = '';

	// Declare the var that will be filled in by the $: statement.
	let fullName;

	// Build a full name from the two parts.
	$: fullName = firstName + ' ' + lastName;
</script>

Hi there {fullName}!

This expression will now automatically re-run if firstName or lastName change!

There are some more superb examples in the offical tutorial.

It comes with transitions built in

For simple transitions like fades are included, and there are tonnes of ways to customise transitions including a JS options API and the ability to use CSS too.

<script>
	import { fade } from 'svelte/transition';
	let visible = true;
</script>

<p transition:fade>This block fades in and out!</p>

See the transitions section of the tutorial for a bigger overview.

Deal with promises in your templates with #await blocks:

Loading something in using a fetch() request or AJAX call using something like axios? let the template deal with it's state easily:

<script>
  async function getData() {
    const res await fetch(`/my-api/endpoint`);
    const json = await res.json();
    if (res.ok) {
        return json;
    } else {
      throw new Error(json);
    }
  }
  let myDataCall = getData();
</script>

{#await myDataCall}
	<p>...waiting</p>
{:then json}
	Hi there {json.name}, how are you?
{:catch error}
	<p style="color: red">{error.message}</p>
{/await}

And A few other quick things:

Conditional classes are easy:

<div class="first second" class:third={booleanCondition} class:fourth={!booleanCondition}>

The lifecycle hooks are well named and easy to use:

<script>
  import {onMount, beforeUpdate, afterUpdate, onDestroy} from 'svelte';

  onMount(() => {})

  beforeUpdate(() => {});

  afterUpdate(() => {});

  onDestroy(() => {});
</script>

Emitting custom events is super easy:

<script>
  import {createEventDispatcher} from 'svelte';
  const emit = createEventDispatcher();
  emit('myEvent', {some:'Data',goes:'here'});
</script>

and listening to them is easy too:

<MyComponent on:myEvent={(event) => { let data = event.detail }}>

Binding an input to a variable is super easy:

<script>
  let name = undefined;
</script>

<input type="text" bind:value={name}>

So is binding regular events:

<a on:click|preventDefault={() => { alert("clicked") }}>Click me!</a>

Fragments are super useful for when you don't want to add any additional markup for a slot:

<Header>
  <svelte:fragment slot="title">
    Your Page Title Here
  </svelte:fragment>
</Header>

You can also render HTML tag names dynamically using <svelte:element>:

<script>
  // If a URL is provided, we want this to be an anchor tag.
  // But if the URL is not provided, use a HTML button tag instead.
  export let url = undefined;
  export let text = "Click Me";
</script>

<svelte:element this={url === undefined ? 'button' : 'a'} href={url}>{text}</svelte:element>