SvelteKit è l'ultimo di quelli che definirei framework applicativi di nuova generazione. Ovviamente crea un'applicazione per te, con il routing basato su file, la distribuzione e il rendering lato server che Next ha fatto per sempre. Ma SvelteKit supporta anche layout nidificati, mutazioni del server che sincronizzano i dati sulla tua pagina e alcune altre sottigliezze in cui entreremo.
Questo post vuole essere un'introduzione di alto livello per creare, si spera, un po' di entusiasmo per chiunque non abbia mai usato SvelteKit. Sarà un tour rilassato. Se ti piace quello che vedi, il i documenti completi sono qui.
In un certo senso questo è un post impegnativo da scrivere. SvelteKit è un framework applicativo. Esiste per aiutarti a creare... beh, applicazioni. Ciò rende difficile la demo. Non è possibile creare un'intera applicazione in un post di blog. Quindi, invece, useremo un po' la nostra immaginazione. Costruiremo lo scheletro di un'applicazione, avremo alcuni segnaposto dell'interfaccia utente vuoti e dati statici hardcoded. L'obiettivo non è creare un'applicazione reale, ma mostrarti come funzionano i pezzi mobili di SvelteKit in modo che tu possa creare un'applicazione personalizzata.
A tal fine, creeremo la collaudata e vera applicazione To-Do come esempio. Ma non preoccuparti, si tratterà molto, molto di più di vedere come funziona SvelteKit che di creare un'altra app To-Do.
Il codice per tutto in questo post è disponibile su GitHub. Questo progetto è anche schierato su Vercel per una dimostrazione dal vivo.
Creare il tuo progetto
Avviare un nuovo progetto SvelteKit è abbastanza semplice. Correre npm create your-app-name
nel terminale e rispondi alle domande. Assicurati di scegliere "Skeleton Project" ma altrimenti fai le selezioni che desideri per TypeScript, ESLint, ecc.
Una volta creato il progetto, eseguilo npm i
ed npm run dev
e un server di sviluppo dovrebbe iniziare a funzionare. Accendi localhost:5173
nel browser e otterrai la pagina segnaposto per l'app scheletro.
Instradamento di base
Si noti la routes
cartella sotto src
. Questo contiene il codice per tutti i nostri percorsi. C'è già un +page.svelte
file lì dentro con il contenuto per la radice /
itinerario. Non importa dove ti trovi nella gerarchia dei file, la pagina effettiva per quel percorso ha sempre il nome +page.svelte
. Con questo in mente, creiamo pagine per /list
, /details
, /admin/user-settings
ed admin/paid-status
e aggiungi anche alcuni segnaposto di testo per ogni pagina.
Il layout del tuo file dovrebbe essere simile a questo:
Dovresti essere in grado di navigare modificando i percorsi URL nella barra degli indirizzi del browser.
layout
Vorremo collegamenti di navigazione nella nostra app, ma certamente non vogliamo copiare il markup per loro su ogni pagina che creiamo. Quindi, creiamo un file +layout.svelte
file nella radice del nostro routes
cartella, che SvelteKit tratterà come modello globale per tutte le pagine. Andiamo e aggiungiamo alcuni contenuti ad esso:
<nav> <ul> <li> <a href="/it/">Home</a> </li> <li> <a href="/it/list">To-Do list</a> </li> <li> <a href="/it/admin/paid-status">Account status</a> </li> <li> <a href="/it/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>
Una navigazione rudimentale con alcuni stili di base. Di particolare importanza è il <slot />
etichetta. Questo è non lo slot che usi con i componenti web e lo shadow DOM, ma piuttosto una caratteristica Svelte che indica dove mettere i nostri contenuti. Quando viene eseguito il rendering di una pagina, il contenuto della pagina scorrerà nel punto in cui si trova lo slot.
E ora abbiamo un po' di navigazione! Non vinceremo nessun concorso di design, ma non ci stiamo provando.
Layout nidificati
E se volessimo che tutte le nostre pagine di amministrazione ereditassero il layout normale che abbiamo appena creato, ma condividessero anche alcune cose comuni a tutte le pagine di amministrazione (ma solo alle pagine di amministrazione)? Nessun problema, ne aggiungiamo un altro +layout.svelte
file nella nostra root admin
directory, che verrà ereditata da tutto ciò che si trova al di sotto di essa. Facciamolo e aggiungiamo questo contenuto:
<div>This is an admin page</div> <slot /> <style> div { padding: 15px; margin: 10px 0; background-color: red; color: white; }
</style>
Aggiungiamo un banner rosso che indica che questa è una pagina di amministrazione e poi, come prima, a <slot />
che denota dove vogliamo che vada il contenuto della nostra pagina.
Il nostro layout di root da prima del rendering. All'interno del layout radice c'è a <slot />
etichetta. Il contenuto del layout annidato va nel layout principale <slot />
. E infine, il layout nidificato definisce il proprio <slot />
, in cui viene eseguito il rendering del contenuto della pagina.
Se accedi alle pagine di amministrazione, dovresti vedere il nuovo banner rosso:
Definire i nostri dati
OK, eseguiamo il rendering di alcuni dati reali o, almeno, vediamo come possiamo rendere alcuni dati reali. Esistono centinaia di modi per creare e connettersi a un database. Questo post riguarda però SvelteKit, non gestisce DynamoDB, quindi "caricheremo" alcuni dati statici. Ma useremo tutti gli stessi macchinari per leggerlo e aggiornarlo che useresti per i dati reali. Per una vera app Web, scambia le funzioni che restituiscono dati statici con funzioni che si connettono e interrogano qualsiasi database tu usi.
Creiamo un modulo semplicissimo in lib/data/todoData.ts
che restituisce alcuni dati statici insieme a ritardi artificiali per simulare query reali. Vedrai questo lib
cartella importata altrove tramite $lib
. Questa è una funzionalità di SvelteKit per quella particolare cartella e puoi persino aggiungi i tuoi alias.
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);
}
Una funzione per restituire un array piatto delle nostre cose da fare, una ricerca dei nostri tag e una funzione per recuperare una singola cosa da fare (la useremo quest'ultima nella nostra pagina Dettagli).
Caricamento dei nostri dati
Come otteniamo questi dati nelle nostre pagine Svelte? Ci sono diversi modi, ma per ora, creiamo un file +page.server.js
file nel nostro list
cartella e inserire questo contenuto in essa:
import { getTodos, getTags } from "$lib/data/todoData"; export function load() { const todos = getTodos(); const tags = getTags(); return { todos, tags, };
}
Abbiamo definito un file load()
funzione che estrae i dati necessari per la pagina. Nota che lo siamo non await
-ing chiamate al nostro getTodos
ed getTags
funzioni asincrone. In questo modo si creerebbe una cascata di caricamento dei dati mentre aspettiamo che arrivino i nostri elementi da fare prima di caricare i nostri tag. Invece, restituiamo le promesse grezze da load
e SvelteKit fa il lavoro necessario per await
Loro.
Quindi, come accediamo a questi dati dal nostro componente della pagina? SvelteKit fornisce a data
prop per il nostro componente con i dati su di esso. Accederemo alle nostre cose da fare e ai tag da esso usando a assegnazione reattiva.
Il nostro componente della pagina Elenco ora ha questo aspetto.
<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>
E questo dovrebbe rendere i nostri oggetti da fare!
Gruppi di layout
Prima di passare alla pagina Dettagli e modificare i dati, diamo un'occhiata a una funzionalità SvelteKit davvero interessante: gruppi di impaginazione. Abbiamo già visto layout nidificati per tutte le pagine di amministrazione, ma se volessimo condividere un layout tra pagine arbitrarie allo stesso livello del nostro file system? In particolare, se volessimo condividere un layout solo tra la nostra pagina Elenco e la nostra pagina Dettagli? Abbiamo già un layout globale a quel livello. Invece, possiamo creare una nuova directory, ma con un nome tra parentesi, come questo:
Ora abbiamo un gruppo di layout che copre le nostre pagine Elenco e Dettagli. L'ho chiamato (todo-management)
ma puoi nominarlo come preferisci. Per essere chiari, questo nome lo farà non influenzano gli URL delle pagine all'interno del gruppo di layout. Gli URL rimarranno gli stessi; i gruppi di layout consentono di aggiungere layout condivisi alle pagine senza che tutti comprendano l'intera directory in routes
.
We potuto aggiungere un +layout.svelte
file e alcuni stupidi <div>
banner che dice: "Ehi, stiamo gestendo le cose da fare". Ma facciamo qualcosa di più interessante. I layout possono definire load()
funzioni al fine di fornire dati per tutti i percorsi sottostanti. Usiamo questa funzionalità per caricare i nostri tag, poiché utilizzeremo i nostri tag nel nostro details
pagina - oltre a list
pagina che abbiamo già.
In realtà, quasi certamente non vale la pena forzare un gruppo di layout solo a fornire un singolo dato; è meglio duplicare quei dati nel file load()
funzione per ogni pagina. Ma per questo post, fornirà la scusa di cui abbiamo bisogno per vedere una nuova funzionalità di SvelteKit!
Per prima cosa, andiamo nel nostro list
di pagina +page.server.js
file e rimuovere i tag da esso.
import { getTodos, getTags } from "$lib/data/todoData"; export function load() { const todos = getTodos(); return { todos, };
}
La nostra pagina List ora dovrebbe produrre un errore poiché non c'è tags
oggetto. Risolviamo questo problema aggiungendo a +layout.server.js
file nel nostro gruppo di layout, quindi definire a load()
funzione che carica i nostri tag.
import { getTags } from "$lib/data/todoData"; export function load() { const tags = getTags(); return { tags, };
}
E, proprio così, la nostra pagina Elenco viene nuovamente visualizzata!
Stiamo caricando i dati da più posizioni
Mettiamo un bel punto su ciò che sta accadendo qui:
- Abbiamo definito a
load()
funzione per il nostro gruppo di layout, che abbiamo inserito+layout.server.js
. - Questo fornisce dati per contro tutti i delle pagine servite dal layout, che in questo caso significa le nostre pagine Elenco e Dettagli.
- La nostra pagina Elenco definisce anche a
load()
funzione che va nella sua+page.server.js
file. - SvelteKit fa il duro lavoro di prendere i risultati di queste fonti di dati, unirli insieme e renderli entrambi disponibili in
data
.
La nostra pagina Dettagli
Utilizzeremo la nostra pagina Dettagli per modificare un elemento attività. Innanzitutto, aggiungiamo una colonna alla tabella nella nostra pagina Elenco che si collega alla pagina Dettagli con l'ID dell'elemento da fare nella stringa di query.
<td><a href="/it/details?id={t.id}">Edit</a></td>
Ora costruiamo la nostra pagina Dettagli. Innanzitutto, aggiungeremo un caricatore per afferrare l'elemento da fare che stiamo modificando. Creare un +page.server.js
in /details
, con questo contenuto:
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, };
}
Il nostro caricatore viene fornito con a url
proprietà da cui possiamo estrarre i valori della stringa di query. Ciò semplifica la ricerca dell'elemento da fare che stiamo modificando. Rendiamo quell'attività, insieme alla funzionalità per modificarla.
SvelteKit ha meravigliose capacità di mutazione integrate, purché utilizzi i moduli. Ricordi le forme? Ecco la nostra pagina Dettagli. Ho eliminato gli stili per brevità.
<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>
Stiamo prendendo i tag come prima dal caricatore del nostro gruppo di layout e l'elemento da fare dal caricatore della nostra pagina. Stiamo afferrando il reale tag
oggetti dall'elenco delle cose da fare degli ID tag e quindi il rendering di tutto. Creiamo un form con un input nascosto per l'ID e un input reale per il titolo. Visualizziamo i tag e quindi forniamo un pulsante per inviare il modulo.
Se hai notato il use:enhance
, che dice semplicemente a SvelteKit di utilizzare il miglioramento progressivo e Ajax per inviare il nostro modulo. Probabilmente lo userai sempre.
Come salviamo le nostre modifiche?
Si noti la action="?/editTodo"
attributo sul modulo stesso? Questo ci dice dove vogliamo inviare i nostri dati modificati. Per il nostro caso, vogliamo sottoporre a un editTodo
"azione."
Creiamolo aggiungendo quanto segue al file +page.server.js
file che abbiamo già per Details (che attualmente ha un file load()
funzione, per afferrare le nostre cose da fare):
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"); },
};
Le azioni della forma ci danno a request
oggetto, che fornisce l'accesso al nostro formData
, che ha un get
metodo per i nostri vari campi del modulo. Abbiamo aggiunto quell'input nascosto per il valore ID in modo da poterlo prendere qui per cercare l'elemento da fare che stiamo modificando. Simuliamo un ritardo, chiamiamo un nuovo updateTodo()
metodo, quindi reindirizzare l'utente al /list
pag. Gli updateTodo()
il metodo aggiorna semplicemente i nostri dati statici; nella vita reale eseguiresti una sorta di aggiornamento in qualunque archivio dati tu stia utilizzando.
export async function updateTodo(id, newTitle) { const todo = todos.find(t => t.id == id); Object.assign(todo, { title: newTitle });
}
Proviamo. Andremo prima alla pagina Elenco:
Ora facciamo clic sul pulsante Modifica per uno degli elementi da fare per visualizzare la pagina di modifica /details
.
Stiamo per aggiungere un nuovo titolo:
Ora, fai clic su Salva. Questo dovrebbe riportarci al nostro /list
pagina, con il nuovo titolo dell'attività applicato.
Come si è presentato il nuovo titolo in quel modo? Era automatico. Una volta reindirizzati al file /list
page, SvelteKit ha eseguito automaticamente di nuovo tutti i nostri caricatori proprio come avrebbe fatto a prescindere. Questo è il progresso chiave che i framework applicativi di nuova generazione, come SvelteKit, Remixe Prossimo 13 fornire. Invece di darti un modo conveniente per visualizzare le pagine e poi augurarti buona fortuna per il recupero di qualsiasi endpoint potresti dover aggiornare i dati, integrano la mutazione dei dati insieme al caricamento dei dati, consentendo ai due di lavorare in tandem.
Alcune cose che ti starai chiedendo...
Questo aggiornamento della mutazione non sembra troppo impressionante. I caricatori verranno eseguiti nuovamente ogni volta che navighi. E se non avessimo aggiunto un reindirizzamento nella nostra azione del modulo, ma fossimo rimasti sulla pagina corrente? SvelteKit eseguirà l'aggiornamento nell'azione del modulo, come prima, ma lo farebbe ancora rieseguire tutti i caricatori per la pagina corrente, inclusi i caricatori nei layout di pagina.
Possiamo avere mezzi più mirati per invalidare i nostri dati? Ad esempio, i nostri tag non sono stati modificati, quindi nella vita reale non vorremmo interrogarli nuovamente. Sì, quello che ti ho mostrato è solo il comportamento predefinito dei moduli in SvelteKit. Puoi disattivare il comportamento predefinito tramite fornendo una richiamata a use:enhance
. Quindi SvelteKit fornisce il manuale funzioni di invalidazione.
Il caricamento dei dati su ogni navigazione è potenzialmente costoso e non necessario. Posso memorizzare nella cache questi dati come faccio con strumenti come react-query
? Sì, solo in modo diverso. SvelteKit ti consente di impostare (e quindi rispettare) le intestazioni di controllo della cache che il Web fornisce già. E tratterò i meccanismi di invalidazione della cache in un post successivo.
Tutto ciò che abbiamo fatto in questo articolo utilizza dati statici e modifica i valori in memoria. Se è necessario ripristinare tutto e ricominciare da capo, interrompere e riavviare il file npm run dev
Processo del nodo.
Concludendo
Abbiamo appena scalfito la superficie di SvelteKit, ma speriamo che tu abbia visto abbastanza per entusiasmarti. Non ricordo l'ultima volta che ho trovato lo sviluppo web così divertente. Con cose come raggruppamento, instradamento, SSR e distribuzione tutte gestite immediatamente, posso dedicare più tempo alla codifica che alla configurazione.
Ecco alcune altre risorse che puoi utilizzare come passaggi successivi per imparare SvelteKit:
- Distribuzione di contenuti basati su SEO e PR. Ricevi amplificazione oggi.
- Platoblockchain. Web3 Metaverse Intelligence. Conoscenza amplificata. Accedi qui.
- Fonte: https://css-tricks.com/getting-started-with-sveltekit/
- 1
- 10
- 100
- 11
- 7
- 9
- 98
- a
- capace
- Chi siamo
- a proposito
- accesso
- Il mio account
- Action
- azioni
- Adam
- aggiunto
- aggiunta
- indirizzo
- Admin
- Avanzate
- influenzare
- Tutti
- Consentire
- a fianco di
- già
- sempre
- quantità
- ed
- Un altro
- rispondere
- chiunque
- App
- Applicazioni
- applicazioni
- applicato
- in giro
- Italia
- articolo
- artificiale
- addetto
- Automatico
- automaticamente
- disponibile
- attendere
- precedente
- sfondo
- bandiera
- bar
- basic
- prima
- MIGLIORE
- Meglio
- fra
- Po
- Nero
- Blog
- Post di Blog
- Blu
- Scatola
- portare
- del browser
- bug
- costruire
- costruito
- incassato
- pulsante
- Cache
- chiamata
- Bandi
- funzionalità
- Custodie
- certamente
- impegnativo
- cambiando
- pulire campo
- codice
- codifica
- colore
- Colonna
- Venire
- Uncommon
- Concorsi
- componente
- componenti
- conferenze
- Connettiti
- Collegamento
- consolle
- contenuto
- Comodo
- potuto
- Portata
- copertura
- Copertine
- creare
- creato
- Creazione
- Corrente
- Attualmente
- dati
- Banca Dati
- Predefinito
- definisce
- ritardo
- ritardi
- deployment
- Design
- dettagli
- Dev
- Mercato
- DID
- Dsiplay
- non
- fare
- Dont
- ogni
- altrove
- abbastanza
- Intero
- interezza
- errore
- eccetera
- Anche
- Ogni
- qualunque cosa
- esempio
- eccitato
- Eccitazione
- esiste
- costoso
- export
- fattibile
- caratteristica
- pochi
- campi
- Compila il
- File
- Infine
- sottile
- Antincendio
- Nome
- Fissare
- piatto
- i seguenti
- per sempre
- modulo
- formato
- forme
- essere trovato
- quadri
- da
- pieno
- ti divertirai
- function
- funzionalità
- funzioni
- ottenere
- ottenere
- Dare
- Dare
- globali
- Go
- scopo
- va
- andando
- afferrare
- Gruppo
- Gruppo
- accadere
- Hard
- intestazioni
- Aiuto
- qui
- nascosto
- gerarchia
- alto livello
- detiene
- Fiduciosamente
- Orizzontale
- Come
- HTML
- HTTPS
- MALATO
- immaginazioni
- importare
- importanza
- impressionante
- in
- Compreso
- inizialmente
- ingresso
- invece
- integrare
- interessante
- Introduzione
- IT
- elementi
- stessa
- JavaScript
- Le
- Cognome
- con i più recenti
- disposizione
- apprendimento
- Consente di
- Livello
- Li
- Vita
- leggera
- probabile
- Collegamento
- Lista
- vivere
- caricare
- caricatore
- Caricamento in corso
- carichi
- Lunghi
- Guarda
- SEMBRA
- ricerca
- fortuna
- macchinario
- make
- FA
- Fare
- gestione
- Manuale
- Margine
- Importanza
- si intende
- Memorie
- semplicemente
- fusione
- metodo
- forza
- mente
- Moduli
- Scopri di più
- cambiano
- in movimento
- multiplo
- Nome
- Detto
- nav
- Navigare
- Navigazione
- necessaria
- Bisogno
- New
- GENERAZIONE
- nodo
- normale
- numero
- oggetto
- oggetti
- ONE
- minimo
- Altro
- altrimenti
- proprio
- particolare
- sentiero
- Eseguire
- scegliere
- pezzo
- pezzi
- segnaposto
- Platone
- Platone Data Intelligence
- PlatoneDati
- punto
- Post
- Post
- potenzialmente
- Preparare
- Problema
- processi
- produrre
- progressivo
- progetto
- promette
- proprietà
- protetta
- fornire
- fornisce
- Maglioni
- metti
- domanda
- Crudo
- Leggi
- di rose
- vita reale
- Realtà
- Rosso
- reindirizzare
- Indipendentemente
- rimanere
- ricorda
- rimuovere
- interpretazione
- rende
- richiesta
- Risorse
- Risultati
- ritorno
- di ritorno
- problemi
- ritornare
- Ricco
- radice
- strada
- percorsi
- Correre
- running
- stesso
- Risparmi
- vedendo
- serve
- set
- Shadow
- Condividi
- condiviso
- dovrebbero
- mostrare attraverso le sue creazioni
- Un'espansione
- semplicemente
- da
- singolo
- scivolo
- So
- alcuni
- qualcosa
- fonti
- spendere
- inizia a
- iniziato
- rimasto
- Passi
- Fermare
- inviare
- supporti
- superficie
- sistema
- tavolo
- TAG
- Fai
- presa
- Parlare
- Tandem
- mirata
- dice
- modello
- terminal
- I
- cose
- per tutto
- tempo
- Titolo
- a
- insieme
- pure
- strumenti
- Tour
- trattare
- vero
- TURNO
- Dattiloscritto
- ui
- per
- Aggiornanento
- Aggiornamenti
- URL
- us
- uso
- Utente
- APPREZZIAMO
- Valori
- vario
- via
- Visualizza
- aspettare
- ricercato
- modi
- sito web
- componenti web
- Sviluppo Web
- Che
- quale
- bianca
- volere
- vincere
- senza
- meraviglioso
- Lavora
- lavori
- valore
- sarebbe
- scrivere
- Tu
- Trasferimento da aeroporto a Sharm
- zefiro