SvelteKit er det siste av det jeg vil kalle neste generasjons applikasjonsrammeverk. Det stillaserer selvfølgelig en applikasjon for deg, med den filbaserte rutingen, distribusjonen og gjengivelsen på serversiden som Next har gjort for alltid. Men SvelteKit støtter også nestede oppsett, servermutasjoner som synkroniserer dataene på siden din, og noen andre finesser vi skal komme inn på.
Dette innlegget er ment å være en introduksjon på høyt nivå for å forhåpentligvis bygge litt spenning for alle som aldri har brukt SvelteKit. Det blir en avslappet tur. Hvis du liker det du ser, fullstendige dokumenter er her.
På noen måter er dette et utfordrende innlegg å skrive. SvelteKit er en søknadsrammer. Den finnes for å hjelpe deg med å bygge ... vel, applikasjoner. Det gjør det vanskelig å demo. Det er ikke mulig å bygge en hel applikasjon i et blogginnlegg. Så i stedet bruker vi fantasien litt. Vi bygger skjelettet til en applikasjon, har noen tomme UI-plassholdere og hardkodede statiske data. Målet er ikke å bygge en faktisk applikasjon, men i stedet å vise deg hvordan SvelteKits bevegelige deler fungerer slik at du kan bygge en egen applikasjon.
For det formål vil vi bygge den velprøvde og sanne To-Do-applikasjonen som et eksempel. Men ikke bekymre deg, dette vil handle mye, mye mer om å se hvordan SvelteKit fungerer enn å lage enda en To-Do-app.
Koden for alt i dette innlegget er tilgjengelig på GitHub. Dette prosjektet er også utplassert på Vercel for en live demo.
Opprette prosjektet ditt
Å spinne opp et nytt SvelteKit-prosjekt er enkelt nok. Løpe npm create your-app-name
i terminalen og svar på spørsmålet. Pass på å velge "Skeleton Project", men ellers gjør de valgene du vil for TypeScript, ESLint, etc.
Når prosjektet er opprettet, kjør npm i
og npm run dev
og en utviklerserver skal begynne å kjøre. Fyr opp localhost:5173
i nettleseren, så får du plassholdersiden for skjelett-appen.
Grunnleggende ruting
Legg merke til routes
mappe under src
. Det inneholder kode for alle våre ruter. Det er allerede en +page.svelte
fil der inne med innhold for roten /
rute. Uansett hvor i filhierarkiet du er, har den faktiske siden for den banen alltid navnet +page.svelte
. Med det i tankene, la oss lage sider for /list
, /details
, /admin/user-settings
og admin/paid-status
, og legg også til noen tekstplassholdere for hver side.
Filoppsettet ditt skal se omtrent slik ut:
Du skal kunne navigere rundt ved å endre URL-baner i nettleserens adresselinje.
oppsett
Vi vil ha navigasjonslenker i appen vår, men vi vil absolutt ikke kopiere markeringen for dem på hver side vi lager. Så la oss lage en +layout.svelte
fil i roten til vår routes
mappe, som SvelteKit vil behandle som en global mal for alle sider. La oss legge til litt innhold til den:
<nav> <ul> <li> <a href="/no/">Home</a> </li> <li> <a href="/no/list">To-Do list</a> </li> <li> <a href="/no/admin/paid-status">Account status</a> </li> <li> <a href="/no/admin/user-settings">User settings</a> </li> </ul>
</nav> <slot /> <style> nav { background-color: beige; } nav ul { display: flex; } li { list-style: none; margin: 15px; } a { text-decoration: none; color: black; }
</style>
Litt rudimentær navigasjon med noen grunnleggende stiler. Spesielt viktig er <slot />
stikkord. Dette er ikke sporet du bruker med webkomponenter og shadow DOM, men snarere en Svelte-funksjon som indikerer hvor vi skal plassere innholdet vårt. Når en side gjengis, vil sideinnholdet gli inn der sporet er.
Og nå har vi litt navigering! Vi vil ikke vinne noen designkonkurranser, men vi prøver ikke det.
Nestede oppsett
Hva om vi ønsket at alle administratorsidene våre skulle arve den normale layouten vi nettopp har bygget, men også dele noen ting som er felles for alle administratorsidene (men bare administratorsidene)? Ikke noe problem, vi legger til en til +layout.svelte
fil i roten vår admin
katalogen, som vil bli arvet av alt under den. La oss gjøre det og legge til dette innholdet:
<div>This is an admin page</div> <slot /> <style> div { padding: 15px; margin: 10px 0; background-color: red; color: white; }
</style>
Vi legger til et rødt banner som indikerer at dette er en admin-side og deretter, som før, en <slot />
angir hvor vi vil at sideinnholdet vårt skal gå.
Rotoppsettet vårt fra før gjengis. Innsiden av rotoppsettet er en <slot />
stikkord. Innholdet i det nestede oppsettet går inn i rotoppsettet <slot />
. Og til slutt definerer det nestede oppsettet sitt eget <slot />
, der sideinnholdet gjengis.
Hvis du navigerer til admin-sidene, bør du se det nye røde banneret:
Definerer våre data
OK, la oss gjengi noen faktiske data - eller i det minste se hvordan vi kan gjengi noen faktiske data. Det er hundre måter å opprette og koble til en database på. Dette innlegget handler imidlertid om SvelteKit, ikke administrasjon av DynamoDB, så vi "laster" noen statiske data i stedet. Men vi bruker alle de samme maskinene for å lese og oppdatere den som du vil bruke for ekte data. For en ekte nettapp, bytt ut funksjonene som returnerer statiske data med funksjoner som kobler til og spør til hvilken database du måtte bruke.
La oss lage en smuss-enkel modul i lib/data/todoData.ts
som returnerer noen statiske data sammen med kunstige forsinkelser for å simulere ekte spørringer. Du vil se dette lib
mappe importert andre steder via $lib
. Dette er en SvelteKit-funksjon for den aktuelle mappen, og du kan til og med legg til dine egne aliaser.
let todos = [ { id: 1, title: "Write SvelteKit intro blog post", assigned: "Adam", tags: [1] }, { id: 2, title: "Write SvelteKit advanced data loading blog post", assigned: "Adam", tags: [1] }, { id: 3, title: "Prepare RenderATL talk", assigned: "Adam", tags: [2] }, { id: 4, title: "Fix all SvelteKit bugs", assigned: "Rich", tags: [3] }, { id: 5, title: "Edit Adam's blog posts", assigned: "Geoff", tags: [4] },
]; let tags = [ { id: 1, name: "SvelteKit Content", color: "ded" }, { id: 2, name: "Conferences", color: "purple" }, { id: 3, name: "SvelteKit Development", color: "pink" }, { id: 4, name: "CSS-Tricks Admin", color: "blue" },
]; export const wait = async amount => new Promise(res => setTimeout(res, amount ?? 100)); export async function getTodos() { await wait(); return todos;
} export async function getTags() { await wait(); return tags.reduce((lookup, tag) => { lookup[tag.id] = tag; return lookup; }, {});
} export async function getTodo(id) { return todos.find(t => t.id == id);
}
En funksjon for å returnere et flatt utvalg av gjøremålene våre, et oppslag av taggene våre og en funksjon for å hente en enkelt gjøremål (vi bruker den siste på detaljsiden vår).
Laster inn dataene våre
Hvordan får vi disse dataene inn på Svelte-sidene våre? Det er flere måter, men for nå, la oss lage en +page.server.js
fil i vår list
mappe, og legg dette innholdet i den:
import { getTodos, getTags } from "$lib/data/todoData"; export function load() { const todos = getTodos(); const tags = getTags(); return { todos, tags, };
}
Vi har definert en load()
funksjon som henter inn dataene som trengs for siden. Legg merke til at vi er det ikke await
-ringer til vår getTodos
og getTags
asynkrone funksjoner. Å gjøre det vil skape en datainnlastingsfoss mens vi venter på at oppgaveelementene våre skal komme inn før vi laster inn taggene våre. I stedet returnerer vi råløftene fra load
, og SvelteKit gjør det nødvendige arbeidet for å await
Dem.
Så hvordan får vi tilgang til disse dataene fra sidekomponenten vår? SvelteKit gir en data
prop for vår komponent med data på den. Vi får tilgang til gjøremålene våre og tagger fra den ved å bruke en reaktivt oppdrag.
Vår listesidekomponent ser nå slik ut.
<script> export let data; $: ({ todo, tags } = data);
</script> <table cellspacing="10" cellpadding="10"> <thead> <tr> <th>Task</th> <th>Tags</th> <th>Assigned</th> </tr> </thead> <tbody> {#each todos as t} <tr> <td>{t.title}</td> <td>{t.tags.map((id) => tags[id].name).join(', ')}</td> <td>{t.assigned}</td> </tr> {/each} </tbody>
</table> <style> th { text-align: left; }
</style>
Og dette bør gjengi gjøremålene våre!
Layoutgrupper
Før vi går videre til detaljsiden og muterer data, la oss ta en titt på en veldig pen SvelteKit-funksjon: layoutgrupper. Vi har allerede sett nestede oppsett for alle admin-sider, men hva om vi ønsket å dele et oppsett mellom vilkårlige sider på samme nivå i filsystemet vårt? Spesielt, hva om vi ønsket å dele en layout mellom bare vår listeside og vår detaljside? Vi har allerede en global layout på det nivået. I stedet kan vi opprette en ny katalog, men med et navn som står i parentes, slik:
Vi har nå en layoutgruppe som dekker listene og detaljsidene våre. Jeg kalte den (todo-management)
men du kan navngi det hva du vil. For å være tydelig, vil dette navnet ikke påvirke nettadressene til sidene i layoutgruppen. URL-ene forblir de samme; layoutgrupper lar deg legge til delte layouter på sider uten at de alle omfatter hele en katalog i routes
.
We kunne Legg til en +layout.svelte
fil og noen dumt <div>
banner som sier "Hei, vi administrerer gjøremål". Men la oss gjøre noe mer interessant. Oppsett kan definere load()
funksjoner for å gi data for alle ruter under dem. La oss bruke denne funksjonaliteten til å laste inn taggene våre - siden vi kommer til å bruke taggene våre i vår details
side — i tillegg til list
siden vi allerede har.
I virkeligheten er det nesten helt sikkert ikke verdt det å tvinge en layoutgruppe til bare å gi en enkelt databit; det er bedre å duplisere disse dataene i load()
funksjon for hver side. Men for dette innlegget vil det gi unnskyldningen vi trenger for å se en ny SvelteKit-funksjon!
La oss først gå inn på vår list
sidens +page.server.js
fil og fjern taggene fra den.
import { getTodos, getTags } from "$lib/data/todoData"; export function load() { const todos = getTodos(); return { todos, };
}
Listesiden vår skal nå produsere en feil siden det ikke er noe tags
gjenstand. La oss fikse dette ved å legge til en +layout.server.js
fil i layoutgruppen vår, definer deretter en load()
funksjon som laster inn taggene våre.
import { getTags } from "$lib/data/todoData"; export function load() { const tags = getTags(); return { tags, };
}
Og akkurat som det gjengis Listesiden vår igjen!
Vi laster inn data fra flere steder
La oss sette et godt poeng på hva som skjer her:
- Vi definerte en
load()
funksjon for layoutgruppen vår, som vi legger inn+layout.server.js
. - Dette gir data for alle av sidene oppsettet tjener - som i dette tilfellet betyr listene og detaljsidene våre.
- Listesiden vår definerer også en
load()
funksjon som går i sin+page.server.js
filen. - SvelteKit gjør det grynte arbeidet med å ta resultatene fra disse datakildene, slå dem sammen og gjøre begge tilgjengelige i
data
.
Vår detaljside
Vi bruker detaljsiden vår til å redigere et gjøremål. La oss først legge til en kolonne i tabellen på vår listeside som kobler til detaljsiden med oppgaveelementets ID i søkestrengen.
<td><a href="/no/details?id={t.id}">Edit</a></td>
La oss nå bygge ut detaljsiden vår. Først legger vi til en laster for å ta tak i gjøremålet vi redigerer. Lage en +page.server.js
in /details
, med dette innholdet:
import { getTodo, updateTodo, wait } from "$lib/data/todoData"; export function load({ url }) { const id = url.searchParams.get("id"); console.log(id); const todo = getTodo(id); return { todo, };
}
Vår laster leveres med en url
egenskapen som vi kan trekke søkestrengverdier fra. Dette gjør det enkelt å slå opp oppgaveelementet vi redigerer. La oss gjengi det gjøremålet, sammen med funksjonalitet for å redigere det.
SvelteKit har fantastiske innebygde mutasjonsmuligheter, så lenge du bruker skjemaer. Husk skjemaer? Her er vår detaljside. Jeg har fjernet stilene for korthet.
<script> import { enhance } from "$app/forms"; export let data; $: ({ todo, tags } = data); $: currentTags = todo.tags.map(id => tags[id]);
</script> <form use:enhance method="post" action="?/editTodo"> <input name="id" type="hidden" value="{todo.id}" /> <input name="title" value="{todo.title}" /> <div> {#each currentTags as tag} <span style="{`color:" ${tag.color};`}>{tag.name}</span> {/each} </div> <button>Save</button>
</form>
Vi henter taggene som før fra layoutgruppens loader og gjøremålselementet fra sidens loader. Vi tar tak i det faktiske tag
objekter fra gjøremålslisten over tag-ID-er og deretter gjengi alt. Vi lager et skjema med en skjult inngang for ID og en reell inngang for tittelen. Vi viser taggene og gir deretter en knapp for å sende inn skjemaet.
Hvis du la merke til use:enhance
, som bare forteller SvelteKit å bruke progressiv forbedring og Ajax til å sende inn skjemaet vårt. Du vil sannsynligvis alltid bruke det.
Hvordan lagrer vi redigeringene våre?
Legg merke til action="?/editTodo"
attributt på selve skjemaet? Dette forteller oss hvor vi vil sende inn våre redigerte data. For vårt tilfelle ønsker vi å underkaste oss en editTodo
"handling."
La oss lage den ved å legge til følgende i +page.server.js
fil vi allerede har for detaljer (som for øyeblikket har en load()
funksjon, for å ta tak i gjøremålet vårt):
import { redirect } from "@sveltejs/kit"; // ... export const actions = { async editTodo({ request }) { const formData = await request.formData(); const id = formData.get("id"); const newTitle = formData.get("title"); await wait(250); updateTodo(id, newTitle); throw redirect(303, "/list"); },
};
Skjemahandlinger gir oss en request
objekt, som gir tilgang til vår formData
, som har en get
metode for våre ulike skjemafelt. Vi la til den skjulte inngangen for ID-verdien slik at vi kunne hente den her for å slå opp oppgaveelementet vi redigerer. Vi simulerer en forsinkelse, ringer en ny updateTodo()
metoden, og omdirigere brukeren tilbake til /list
siden. Den updateTodo()
metoden oppdaterer bare våre statiske data; i det virkelige liv vil du kjøre en slags oppdatering uansett hvilken databutikk du bruker.
export async function updateTodo(id, newTitle) { const todo = todos.find(t => t.id == id); Object.assign(todo, { title: newTitle });
}
La oss prøve det. Vi går først til listesiden:
La oss nå klikke på Rediger-knappen for et av gjøremålene for å få opp redigeringssiden /details
.
Vi kommer til å legge til en ny tittel:
Klikk nå på Lagre. Det burde få oss tilbake til vårt /list
side, med den nye gjøremålstittelen brukt.
Hvordan dukket den nye tittelen opp slik? Det var automatisk. Når vi omdirigerte til /list
side, kjørte SvelteKit automatisk alle våre lastere på nytt akkurat som det ville ha gjort uansett. Dette er det viktigste fremskrittet som neste generasjons applikasjonsrammeverk, som SvelteKit, Remixog Neste 13 gi. I stedet for å gi deg en praktisk måte å gjengi sider og deretter ønske deg lykke til med å hente de endepunktene du måtte ha for å oppdatere data, integrerer de datamutasjon sammen med datalasting, slik at de to kan jobbe sammen.
Et par ting du kanskje lurer på...
Denne mutasjonsoppdateringen virker ikke så imponerende. Lasterne vil kjøre på nytt hver gang du navigerer. Hva om vi ikke hadde lagt til en viderekobling i skjemahandlingen vår, men holdt oss på den gjeldende siden? SvelteKit ville utføre oppdateringen i formhandlingen, som før, men ville fortsatt kjør alle lasterne på nytt for gjeldende side, inkludert lasterne i sideoppsettet(e).
Kan vi ha mer målrettede måter å ugyldiggjøre dataene våre på? Taggene våre ble for eksempel ikke redigert, så i det virkelige liv vil vi ikke spørre dem på nytt. Ja, det jeg viste deg er bare standardskjemaoppførselen i SvelteKit. Du kan slå av standardoppførselen ved å gir tilbakeringing til use:enhance
. Da gir SvelteKit manual ugyldiggjøringsfunksjoner.
Å laste inn data på hver navigasjon er potensielt dyrt og unødvendig. Kan jeg cache disse dataene som jeg gjør med verktøy som react-query
? Ja, bare annerledes. SvelteKit lar deg angi (og deretter respektere) cache-kontrolloverskriftene som nettet allerede gir. Og jeg skal dekke cache-ugyldiggjøringsmekanismer i et oppfølgende innlegg.
Alt vi har gjort gjennom denne artikkelen bruker statiske data og endrer verdier i minnet. Hvis du trenger å tilbakestille alt og starte på nytt, stopp og start på nytt npm run dev
Nodeprosess.
Innpakning opp
Vi har knapt skrapet i overflaten til SvelteKit, men forhåpentligvis har du sett nok til å bli begeistret for det. Jeg kan ikke huske sist gang jeg syntes webutvikling var så gøy. Med ting som bunting, ruting, SSR og distribusjon alt håndtert rett ut av boksen, får jeg bruke mer tid på koding enn på å konfigurere.
Her er noen flere ressurser du kan bruke som neste trinn for å lære SvelteKit:
- SEO-drevet innhold og PR-distribusjon. Bli forsterket i dag.
- Platoblokkkjede. Web3 Metaverse Intelligence. Kunnskap forsterket. Tilgang her.
- kilde: https://css-tricks.com/getting-started-with-sveltekit/
- 1
- 10
- 100
- 11
- 7
- 9
- 98
- a
- I stand
- Om oss
- om det
- adgang
- Logg inn
- Handling
- handlinger
- Adam
- la til
- tillegg
- adresse
- admin
- avansert
- påvirke
- Alle
- tillate
- sammen
- allerede
- alltid
- beløp
- og
- En annen
- besvare
- noen
- app
- Søknad
- søknader
- anvendt
- rundt
- Array
- Artikkel
- kunstig
- tildelt
- Automatisk
- automatisk
- tilgjengelig
- avvente
- tilbake
- bakgrunn
- banner
- Bar
- grunnleggende
- før du
- BEST
- Bedre
- mellom
- Bit
- Svart
- Blogg
- Blogginnlegg
- Blå
- Eske
- bringe
- nett~~POS=TRUNC leseren~~POS=HEADCOMP
- bugs
- bygge
- bygget
- innebygd
- knapp
- Cache
- ring
- Samtaler
- evner
- saken
- Gjerne
- utfordrende
- endring
- fjerne
- kode
- Koding
- farge
- Kolonne
- Kom
- Felles
- Konkurranser
- komponent
- komponenter
- konferanser
- Koble
- Tilkobling
- Konsoll
- innhold
- Praktisk
- kunne
- Kurs
- dekker
- Dekker
- skape
- opprettet
- Opprette
- Gjeldende
- I dag
- dato
- Database
- Misligholde
- definerer
- forsinkelse
- forsinkelser
- distribusjon
- utforming
- detaljer
- dev
- Utvikling
- gJORDE
- Vise
- ikke
- gjør
- ikke
- hver enkelt
- andre steder
- nok
- Hele
- helhet
- feil
- etc
- Selv
- Hver
- alt
- eksempel
- opphisset
- Kjøreglede
- finnes
- dyrt
- eksportere
- gjennomførbart
- Trekk
- Noen få
- Felt
- filet
- Filer
- Endelig
- slutt
- Brann
- Først
- Fix
- flate
- etter
- for alltid
- skjema
- format
- skjemaer
- funnet
- rammer
- fra
- fullt
- moro
- funksjon
- funksjonalitet
- funksjoner
- få
- få
- Gi
- Giving
- Global
- Go
- mål
- Går
- skal
- grip
- Gruppe
- Gruppens
- skje
- Hard
- overskrifter
- hjelpe
- her.
- skjult
- hierarki
- høyt nivå
- holder
- forhåpentligvis
- Horisontal
- Hvordan
- HTML
- HTTPS
- JEG VIL
- fantasien
- importere
- betydning
- imponerende
- in
- Inkludert
- innledende
- inngang
- i stedet
- integrere
- interessant
- Introduksjon
- IT
- varer
- selv
- Javascript
- nøkkel
- Siste
- siste
- Layout
- læring
- Lar
- Nivå
- Li
- Life
- lett
- Sannsynlig
- lenker
- Liste
- leve
- laste
- loader
- lasting
- laster
- Lang
- Se
- UTSEENDE
- oppslag
- flaks
- maskiner
- gjøre
- GJØR AT
- Making
- administrerende
- håndbok
- Margin
- Saken
- midler
- Minne
- bare
- sammenslåing
- metode
- kunne
- tankene
- Moduler
- mer
- flytte
- flytting
- flere
- navn
- oppkalt
- nav
- Naviger
- Navigasjon
- nødvendig
- Trenger
- Ny
- neste
- node
- normal
- Antall
- objekt
- gjenstander
- ONE
- rekkefølge
- Annen
- ellers
- egen
- Spesielt
- banen
- Utfør
- plukke
- brikke
- stykker
- placeholder
- plato
- Platon Data Intelligence
- PlatonData
- Point
- Post
- innlegg
- potensielt
- Forbered
- Problem
- prosess
- produsere
- progressiv
- prosjekt
- lover
- eiendom
- beskyttet
- gi
- gir
- Trekker
- sette
- spørsmål
- Raw
- Lese
- ekte
- ekte liv
- Reality
- Rød
- omdirigere
- Uansett
- forbli
- husker
- fjerne
- gjengivelse
- gjengir
- anmode
- Ressurser
- Resultater
- retur
- retur
- avkastning
- tilbake
- Rich
- root
- Rute
- ruter
- Kjør
- rennende
- samme
- Spar
- se
- serverer
- sett
- Shadow
- Del
- delt
- bør
- Vis
- Enkelt
- ganske enkelt
- siden
- enkelt
- Skyv
- So
- noen
- noe
- Kilder
- bruke
- Begynn
- startet
- oppholdt seg
- Steps
- Stopp
- send
- Støtter
- overflaten
- system
- bord
- TAG
- Ta
- ta
- Snakk
- tandem
- målrettet
- forteller
- mal
- terminal
- De
- ting
- hele
- tid
- Tittel
- til
- sammen
- også
- verktøy
- tur
- behandle
- sant
- SVING
- Loggfila
- ui
- etter
- Oppdater
- oppdateringer
- URL
- us
- bruke
- Bruker
- verdi
- Verdier
- ulike
- av
- Se
- vente
- ønsket
- måter
- web
- nettkomponenter
- Webutvikling
- Hva
- hvilken
- hvit
- vil
- vinne
- uten
- herlig
- Arbeid
- virker
- verdt
- ville
- skrive
- Du
- Din
- zephyrnet