Svelte - ett lättviktigt och snabbt ramverk för att bygga gränssnitt på webben
Bakgrund
Då var vi här igen. Svelte. Är detta ännu ett Javascript-ramverk i mängden? Många av er har antagligen hört talas om Svelte vid det här laget. Ramverket har ändå hunnit få några år på nacken. Första versionen av Svelte släpptes faktiskt redan 2016. Sveltes skapare heter Rich Harris och han ligger bland annat även bakom JS-bundlern Rollup. I det här inlägget tänkte jag avhandla vad Svelte är, hur det skiljer sig från andra, liknande ramverk (framförallt React) och vad mina erfarenheter och intryck av Svelte är.
Men vi kan börja med lite bakgrund. Vem är jag och hur kom jag in på Svelte från första början? Under mina hittills snart fyra år som konsult så har jag mest suttit med backendutveckling, men jag har alltid haft ett litet inneboende frontend-intresse. Jag ville således få utlopp för det här intresset och samtidigt få kompetensutveckla mig lite i frontend. I samma veva så hade jag en idé för ett hobbyprojekt som jag velat göra länge men aldrig riktigt haft tid eller fått tummen ur att genomföra det (som med alla hobbyprojekt någonsin). Vid denna tiden, i slutet av 2019, hade Svelte börjat få lite momentum och det pratades en del om ramverket, men väldigt få hade faktiskt testat det. Detta blev en bra match på alla sätt. Jag fick in i min kompetensplan att jag skulle utforska Svelte genom att bygga en frontend för detta hobbyprojekt med hjälp av ramverket. Och på den vägen är det. Så min erfarenhetsnivå av frontend och frontendramverk i allmänhet är inte jättehög, vilket såklart kan ha en inverkan på min bild av Svelte. Detta kan vara värt att ha i åtanke.
Vad är Svelte?
Enligt deras egen slogan så är Svelte ett ramverk för att bygga “Cybernetically enhanced web apps”. Detta är en rätt saftig slogan som sätter ribban högt och utlovar stordåd. Vidare så marknadsför Svelte sig självt genom tre huvudsakliga egenskaper som man får när man använder ramverket:
- Mindre kod
- Ingen virtuell DOM
- Verkligt reaktivt
Vi dyker ner lite mer i detalj i var och en av dessa tre för att försöka utveckla vad som faktiskt menas med dem.
Mindre kod
Denna egenskap illustreras nog bäst med ett exempel. Låt säga att vi skall bygga en väldigt enkel miniräknare som adderar två tal. Så här skulle det kunna se ut i Svelte:
Ett liknande exempel skulle kunna se ut ungefär så här i React:
I dessa exempel kan vi se ett par grejer. Svelte använder sig av tvåvägsbindningar för sina variabler, något som React inte gör. Detta leder till att man i React själv behöver ta hand om förändringarna som sker i input-fälten. En annan sak som man kan lägga märke till är att state-uppdateringen skiljer sig något. I Svelte uppdaterar man en state-variabel genom enkel tilldelning, istället för att till exempel använda useState-hooken som man gör i React. I Svelte behöver du heller inte exportera din komponent. Det sköter ramverket åt dig. Detta är några exempel på hur Svelte försöker göra sig av med så mycket boilerplate-kod som möjligt, och det är något som skaparen Rich Harris trycker hårt på i sin marknadsföring av ramverket.
Ingen virtuell DOM
Den virtuella DOM:en har fått mycket lovord de senaste åren och är ett av de tydligaste karaktärsdragen hos React. Många har säkert koll på vad en virtuell DOM är, men kortfattat kan man säga att det är en minnesrepresentation av hur DOM:en ska se ut. Denna representation synkas sedan med den verkliga DOM:en på ett smart sätt. Detta görs för att försöka undvika onödiga och kostsamma uppdateringar av den verkliga DOM:en. Rich Harris tyckte dock att detta medförde onödig overhead och att fördelarna av använda sig av en virtuell DOM inte väger upp för nackdelarna. Så Svelte har valt att helt gå ifrån detta koncept, men man kan ändå säga att renderingsmotorn fungerar snarlikt. Svelte uppdaterar DOM:en vid förändringar som föranleds av en variabeltilldelning (alltså en state-uppdatering).
Verkligt reaktivt
Som jag redan varit inne på tidigare så sköts state-uppdateringar i Svelte genom vanlig variabeltilldelning. Det finns alltså inget API eller liknande för att hantera state i en komponent, utan det är mer eller mindre inbyggt i språket. Och DOM:en renderas om som ett resultat av dessa variabeltilldelningar. Jag tror att det är lite detta Rich Harris menar när han säger att Svelte är “verkligt reaktivt”. Något annat som skvallrar om Sveltes reaktivitet är att ramverket har infört så kallade reaktiva uttryck. Dessa deklareras med ett $-tecken framför uttrycket:
Vad innebär då denna lite märkliga syntax? Varje gång värdet på variabeln count ändras så kommer det att göras en ny tilldelning av variabeln doubled med hänsyn till det nya värdet på count. Denna tilldelning leder i sin tur till en omrendering av DOM:en som vi var inne på tidigare. Detta tycker jag personligen är väldigt användbart. Man skulle kunna säga att dessa reaktiva uttryck är Sveltes lite simplare variant av Reacts useEffect.
Svelte är en kompilator
Vi har redan varit inne på en del skillnader mellan Svelte och React, men har väl kanske missat den allra största. Till skillnad från React så har Svelte ingen runtime. Snarare än att kalla Svelte för ett ramverk så skulle man kunna säga att Svelte fungerar mer som en kompilator eftersom all magi sker vid byggsteget. Vid byggsteget kompilerar Svelte helt enkelt ner och packar ihop all kod till HTML, CSS och Javascript. Detta medför en betydligt mindre bundle size för Svelte i jämförelse med React. Sveltes gzippade bundle size väger in på ungefär 1.6 KB, vilket kan jämföras med Reacts 42.2 KB. Många utvecklare och användare har hänvisat till Sveltes goda prestanda, och en stor anledning till detta ligger förmodligen i avsaknaden av virtuell DOM och runtime.
Svelte-filen
När man utvecklar Svelte-komponenter så skriver man dem i filer med en .svelte-ändelse. Som kanske avslöjats av tidigare exempel så fungerar denna fil i mångt och mycket som en vanlig HTML-fil, men med lite extra krydda och funktionalitet adderad från Svelte såklart. Man använder en script
-tagg för att skriva javascript, en style
-tagg för att skriva CSS, och allt som skrivs utanför dessa två taggar är HTML kryddat med lite Svelte-syntax. Det kan se ut ungefär så här:
I detta exemplet får vi även en försmak på hur man skriver if-satser och for-loopar i Svelte. Vi kikar lite närmare på dessa centrala koncept och jämför lite med dess motsvarigheter i React.
If-satser och for-loopar
I svelte finns det inbyggda if-satser i templating-motorn som väldigt mycket liknar “traditionella” if-satser:
Man kan även lägga till godtyckligt antal else-if statements i ovan exempel. I React skulle ett liknande exempel kunna skrivas så här:
Eller så här:
Svelte har också en inbyggd for-each loop för att rendera element baserat på en array. Den ser ut så här:
Jag uppskattar att den finns en inbyggd for-loop i Svelte, men jag blir alltid lite förvirrad av ordningen på argumenten. Personligen hade jag kanske hellre föredragit “each cat in cats” eller “for each cat in cats”, men det är ju en liten petitess i sammanhanget.
Ett liknande exempel i React hade kunnat se ut så här:
Här utnyttjar man javascripts map-funktion för att uppnå samma sak. Vad gäller for-loopar föredrar jag nog Sveltes approach med en inbyggd for-loop. För mig som inte är någon javascript-guru så blir det betydligt enklare att läsa och förstå.
Styling
Styling i Svelte sköts genom att använda style
-taggen inne i en komponent och det som skrivs innanför den här taggen är i princip helt vanlig CSS:
Så det blir lite som att ha inbyggda styled components. Den CSS som skrivs här får automatiskt ett komponent-scope och påverkar alltså inte andra element utanför komponenten.
Svelte har även mycket inbyggt vad det gäller övergångar och animationer. Ett exempel på en inbyggd övergång ser ut så här:
State-hantering
Vi har redan varit inne lite på hur man hanterar state inne i komponenter i Svelte. Men hur delar man state mellan komponenter? Delning av state i Svelte kan lösas på en rad olika sätt. Till exempel kan man använda Sveltes inbyggda Context-API eller en kombination av olika så kallade Svelte Stores. En stor skillnad mellan dessa är att Context-API:et bara kan användas för att dela state från en komponent till andra komponenter i nedåtgående riktning i arvskedjan, medan stores kan dela state mellan alla delar av en applikation.
En Svelte store är ett objekt som man som konsument kan prenumerera på ändringar på. Det finns några olika typer av stores. En av dessa är en så kallad writable store. Den kan användas så här:
För att slippa undan boilerplaten som krävs för att göra subscribe och unsubscribe kan man likt ett reaktivt uttryckt sätta ett $-tecken framför store-variabeln som man vill läsa och på så sätt slipper man göra subscribe och unsubscribe.
De två exemplen här är ekvivalenta. Förutom writeable stores, som innebär att man både kan läsa från och skriva till storen utifrån, finns även readable, derived och custom stores. En readable store är som namnet avslöjar en store där värdet inte kan ändras utifrån, utan bara läsas. Det är bara storen själv som kan uppdatera värdet:
En derived store utvinner sitt värde från en eller flera andra stores:
Svelte och Typescript
När jag började använda Svelte 2019 fanns det inget inbyggt stöd för Typescript, utan man fick mixtra med massa olika verktyg för att få det att lira. Detta var jag inte alls sugen på att göra när jag satte upp mitt projekt och har således inte använt Svelte i kombination med Typescript i någon större utsträckning. Inbyggt stöd för Typescript var den överlägset mest efterfrågade uppdateringen till Svelte och till slut kunde teamet inte stå emot längre och officiellt inbyggt stöd för Typescript infördes sommaren 2020, till de allra flestas stora glädje. Att döma av det jag sett av Typescript i Svelte-projekt i kombination med det jag läst om andras upplevelser så verkar det som om Typescript och Svelte är en vinnande kombination.
Ekosystem
Ekosystemet runt Svelte är nog det som har utvecklats mest de senaste åren. När jag började använda Svelte var Sapper ramverket som gällde när man ville bygga applikationer med Svelte. Det verkar dock i mångt och mycket vara ersatt av SvelteKit. Med SvelteKit får du tillgång till sånt som inte finns native i Svelte, som till exempel routing, server-side rendering och möjligheten att skriva backend-API:er. Man skulle kunna dra parallellen att SvelteKit är för Svelte vad NextJS är för React. SvelteKit är skapat och underhållet av samma team som underhåller Svelte. I övrigt så är Sveltes ekosystem mycket mindre än vad Reacts är. Det kan dels förklaras av att Svelte inte funnits lika länge och inte används i lika stor utsträckning som React, men också av att många av de funktioner som man ofta använder sig av bibliotek för i React redan finns inbyggda i Svelte, som exempelvis state-delning och animationer.
Sveltes community
Om vi ska kika lite på hur communityn ser ut kring Svelte så är det ju alltid kul att börja med att titta på hur många stjärnor repot har på Github. Svelte har i skrivande stund närmare 59k, att jämföra med React som har 189k och Vue som har 197k. Sveltes community är fortfarande väldigt mycket i sin linda om man jämför med de andra stora ramverken och det finns av förklarliga skäl inte lika många utvecklare som kan Svelte som något av de andra ramverken. Svelte är heller inte uppbackat av något stort företag, såsom React har Facebook eller Angular har Google. Det är “bara” Sveltes core team som underhåller och utvecklar Svelte. Detta kan såklart potentiellt bli ett problem i framtiden om nu detta core team av någon anledning får för sig att de inte vill utveckla Svelte längre. Enligt Stack Overflows stora enkätundersökning 2021 så rankades Svelte som det mest älskade webb-ramverket. Dock när det kommer till användningsgrad bland de svarande så hamnar Svelte väldigt lågt. Endast 2.75% av de närmare 70000 deltagarna svarar att de använt Svelte i något projekt, att jämföra med de dryga 40% som svarar att de använt React i något projekt. Svelte har alltså relativt låg användningsgrad, men de som använt Svelte verkar verkligen gilla det. Om man skall sammanfatta det som folk verkar uppskatta med Svelte så är det dess höga prestanda och goda utvecklarupplevelse.
Några avslutande ord
Allt som allt så tycker jag att Svelte är en teknik som är värd att utforska och lära sig mer om. Från mitt perspektiv har utvecklarupplevelsen varit kanon och det har antagligen hänt ganska mycket sen jag höll på med Svelte som mest för ett par sedan. Många som använt Svelte verkar gilla det, mig själv inkluderad. Hur väl Svelte för sig i storskaliga enterprise-applikationer kan jag inte svära vid, men jag tror att det beror mycket på hur ekosystemet och communityt runt Svelte utvecklas snarare än själva ramverket i sig. För att lära sig Svelte så rekommenderar jag verkligen den tutorial som finns på deras hemsida. Där får man på ett interaktivt och pedagogiskt sätt gå igenom alla delar av Svelte. Det var i princip uteslutande med hjälp av den som jag lärde mig att använda Svelte. Tack för mig!