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:
_10<div>_10 {name && (<p>{name}</p>)}_10 {!name && (<p>Name Unknown</p>)}_10</div>
That's hard to read and... it just looks ugly. Here's Vue (which is actually way nicer & cleaner anyway):
_10<div v-if="name">{{ name }}</div>_10<div v-else>No Name</div>
But here's Svelte's version:
_10{#if name}_10My name is {name}_10{:else}_10This user has no name_10{/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.
_18<script>_18_18const shouldShowWelcome = false;_18_18const name = "Dave";_18_18const showWelcome = () => {_18 shouldShowWelcome = true;_18}_18_18</script>_18_18{#if shouldShowWelcome}_18 <!-- Hi there Dave, how are you today? -->_18 <p>Hi there {name}, how are you today?</p>_18{/if}_18_18<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:
_10<TitleComponent title={'Hello There!'} />
You can access (and set a default), simply by writing your component like this:
Or set a default and get rid of the {#if}
:
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:
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.
_10<script>_10 import { fade } from 'svelte/transition';_10 let visible = true;_10</script>_10_10<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:
_20<script>_20 async function getData() {_20 const res await fetch(`/my-api/endpoint`);_20 const json = await res.json();_20 if (res.ok) {_20 return json;_20 } else {_20 throw new Error(json);_20 }_20 }_20 let myDataCall = getData();_20</script>_20_20{#await myDataCall}_20 <p>...waiting</p>_20{:then json}_20 Hi there {json.name}, how are you?_20{:catch error}_20 <p style="color: red">{error.message}</p>_20{/await}
And A few other quick things:
Conditional classes are easy:
_10<div class="first second" class:third={booleanCondition} class:fourth={!booleanCondition}>
The lifecycle hooks are well named and easy to use:
_11<script>_11 import {onMount, beforeUpdate, afterUpdate, onDestroy} from 'svelte';_11_11 onMount(() => {})_11_11 beforeUpdate(() => {});_11_11 afterUpdate(() => {});_11_11 onDestroy(() => {});_11</script>
Emitting custom events is super easy:
_10<script>_10 import {createEventDispatcher} from 'svelte';_10 const emit = createEventDispatcher();_10 emit('myEvent', {some:'Data',goes:'here'});_10</script>
and listening to them is easy too:
_10<MyComponent on:myEvent={(event) => { let data = event.detail }}>
Binding an input to a variable is super easy:
_10<script>_10 let name = undefined;_10</script>_10_10<input type="text" bind:value={name}>
So is binding regular events:
_10<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:
_10<Header>_10 <svelte:fragment slot="title">_10 Your Page Title Here_10 </svelte:fragment>_10</Header>
You can also render HTML tag names dynamically using <svelte:element>
: