Zephyrnet-logo

Aan de slag met SvelteKit

Datum:

SvelteKit is het nieuwste van wat ik next-gen applicatieframeworks zou noemen. Het ondersteunt natuurlijk een applicatie voor u, met de op bestanden gebaseerde routering, implementatie en weergave aan de serverzijde die Next voor altijd heeft gedaan. Maar SvelteKit ondersteunt ook geneste lay-outs, servermutaties die de gegevens op uw pagina synchroniseren en enkele andere leuke dingen waar we op in zullen gaan.

Dit bericht is bedoeld als een introductie op hoog niveau om hopelijk wat opwinding op te bouwen voor iedereen die SvelteKit nog nooit heeft gebruikt. Het wordt een relaxte toer. Als je het leuk vindt wat je ziet, de volledige documenten zijn hier.

In sommige opzichten is dit een uitdagende post om te schrijven. SvelteKit is een toepassingskader. Het bestaat om u te helpen bij het bouwen van ... nou ja, applicaties. Dat maakt het moeilijk om te demonstreren. Het is niet haalbaar om een ​​hele applicatie in een blogpost te bouwen. Dus in plaats daarvan gebruiken we onze verbeelding een beetje. We bouwen het skelet van een applicatie, hebben enkele lege tijdelijke aanduidingen voor de gebruikersinterface en hardgecodeerde statische gegevens. Het doel is niet om een ​​echte applicatie te bouwen, maar om u te laten zien hoe de bewegende delen van SvelteKit werken, zodat u uw eigen applicatie kunt bouwen.

Daartoe bouwen we de beproefde To-Do-applicatie als voorbeeld. Maar maak je geen zorgen, dit gaat veel, veel meer over zien hoe SvelteKit werkt dan het maken van weer een andere To-Do-app.

De code voor alles in dit bericht is beschikbaar op GitHub. Dit project is ook ingezet op Vercel voor een live demo.

Uw project maken

Een nieuw SvelteKit-project opstarten is eenvoudig genoeg. Rennen npm create [email protected] your-app-name in de terminal en beantwoord de vraagprompts. Zorg ervoor dat u "Skeleton Project" kiest, maar maak verder de gewenste selecties voor TypeScript, ESLint, enz.

Nadat het project is gemaakt, voert u het uit npm i en npm run dev en een dev-server zou moeten beginnen te draaien. Vuur op localhost:5173 in de browser en je krijgt de placeholder-pagina voor de skeleton-app.

Basisroutering

Let op de routes map onder src. Dat bevat de code voor al onze routes. Er is al een +page.svelte bestand daar met inhoud voor de root / route. Het maakt niet uit waar u zich in de bestandshiërarchie bevindt, de eigenlijke pagina voor dat pad heeft altijd de naam +page.svelte. Laten we met dat in gedachten pagina's maken voor /list, /details, /admin/user-settings en admin/paid-status, en voeg ook enkele tijdelijke aanduidingen voor tekst toe voor elke pagina.

Uw bestandsindeling zou er ongeveer zo uit moeten zien:

Eerste bestanden.

U zou moeten kunnen navigeren door de URL-paden in de adresbalk van de browser te wijzigen.

Browseradresbalk met localhost-URL.

lay-outs

We willen navigatielinks in onze app, maar we willen zeker niet de markeringen ervoor kopiëren op elke pagina die we maken. Laten we dus een maken +layout.svelte bestand in de root van onze routes map, die SvelteKit zal behandelen als een globale sjabloon voor alle pagina's. Laten we er wat inhoud aan toevoegen:

<nav> <ul> <li> <a href="/nl/">Home</a> </li> <li> <a href="/nl/list">To-Do list</a> </li> <li> <a href="/nl/admin/paid-status">Account status</a> </li> <li> <a href="/nl/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>

Wat rudimentaire navigatie met enkele basisstijlen. Van bijzonder belang is de <slot /> label. Dit is niet de sleuf die u gebruikt met webcomponenten en schaduw-DOM, maar eerder een Svelte-functie die aangeeft waar onze inhoud moet worden geplaatst. Wanneer een pagina wordt weergegeven, schuift de pagina-inhoud naar binnen waar de sleuf is.

En nu hebben we wat navigatie! We zullen geen ontwerpwedstrijden winnen, maar dat proberen we ook niet.

Horizontale navigatie met lichtgele achtergrond.

Geneste lay-outs

Wat als we wilden dat al onze beheerderspagina's de normale lay-out zouden erven die we zojuist hebben gemaakt, maar ook enkele dingen gemeen hebben met alle beheerderspagina's (maar alleen met beheerderspagina's)? Geen probleem, we voegen er nog een toe +layout.svelte bestand in onze root admin directory, die zal worden overgenomen door alles eronder. Laten we dat doen en deze inhoud toevoegen:

<div>This is an admin page</div> <slot /> <style> div { padding: 15px; margin: 10px 0; background-color: red; color: white; }
</style>

We voegen een rode banner toe die aangeeft dat dit een beheerderspagina is en vervolgens, zoals voorheen, een <slot /> geeft aan waar we onze pagina-inhoud naartoe willen laten gaan.

Onze rootlay-out van vóór wordt weergegeven. Binnenin de rootlay-out bevindt zich een <slot /> label. De inhoud van de geneste lay-out gaat naar de hoofdlay-out <slot />. En tot slot definieert de geneste lay-out zijn eigen lay-out <slot />, waarin de pagina-inhoud wordt weergegeven.

Als u naar de beheerpagina's navigeert, zou u de nieuwe rode banner moeten zien:

Rood vak onder navigatie dat zegt dat dit een admin-pagina is.

Het definiëren van onze gegevens

OK, laten we wat feitelijke gegevens weergeven - of in ieder geval kijken hoe we enkele werkelijke gegevens kunnen weergeven. Er zijn honderd manieren om een ​​database te maken en er verbinding mee te maken. Dit bericht gaat echter over SvelteKit, niet over het beheer van DynamoDB, dus we zullen in plaats daarvan wat statische gegevens "laden". Maar we zullen allemaal dezelfde machines gebruiken om het te lezen en bij te werken die u zou gebruiken voor echte gegevens. Voor een echte web-app vervangt u de functies die statische gegevens retourneren door functies die verbinding maken met en query's uitvoeren op de database die u toevallig gebruikt.

Laten we een vuil-simpele module maken in lib/data/todoData.ts die enkele statische gegevens retourneert, samen met kunstmatige vertragingen om echte zoekopdrachten te simuleren. Je zult dit zien lib map elders geïmporteerd via $lib. Dit is een SvelteKit-functie voor die specifieke map, en dat kan zelfs voeg je eigen aliassen toe.

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);
}

Een functie om een ​​platte reeks van onze actiepunten te retourneren, een zoekopdracht van onze tags en een functie om een ​​enkele taak op te halen (we gebruiken die laatste op onze pagina Details).

Onze gegevens laden

Hoe krijgen we die gegevens op onze Svelte-pagina's? Er zijn een aantal manieren, maar laten we voor nu een maken +page.server.js bestand in onze list map en plaats deze inhoud erin:

import { getTodos, getTags } from "$lib/data/todoData"; export function load() { const todos = getTodos(); const tags = getTags(); return { todos, tags, };
}

We hebben een load() functie die de gegevens binnenhaalt die nodig zijn voor de pagina. Merk op dat we dat zijn niet await-oproepen naar onze getTodos en getTags asynchrone functies. Als u dit wel doet, ontstaat er een waterval voor het laden van gegevens terwijl we wachten tot onze actiepunten binnenkomen voordat we onze tags laden. In plaats daarvan geven we de ruwe beloften terug van load, en SvelteKit doet het nodige werk om await Hen.

Dus, hoe krijgen we toegang tot deze gegevens vanuit onze paginacomponent? SvelteKit biedt een data prop voor onze component met gegevens erop. We hebben toegang tot onze actiepunten en tags met behulp van een reactieve opdracht.

Onze lijstpaginacomponent ziet er nu zo uit.

<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>

En dit zou onze to-do-items moeten weergeven!

Vijf actiepunten in tabelvorm.

Lay-out groepen

Voordat we verder gaan naar de Details-pagina en gegevens muteren, laten we een kijkje nemen in een echt nette SvelteKit-functie: lay-out groepen. We hebben al geneste lay-outs gezien voor alle beheerpagina's, maar wat als we een lay-out willen delen tussen willekeurige pagina's op hetzelfde niveau van ons bestandssysteem? Wat als we met name een lay-out willen delen tussen alleen onze lijstpagina en onze detailpagina? We hebben al een globale lay-out op dat niveau. In plaats daarvan kunnen we een nieuwe map maken, maar met een naam tussen haakjes, zoals deze:

Bestandsmap.

We hebben nu een lay-outgroep die onze lijst- en detailpagina's omvat. Ik noemde het (todo-management) maar je kunt het noemen wat je wilt. Voor alle duidelijkheid, deze naam zal niet invloed op de URL's van de pagina's binnen de lay-outgroep. De URL's blijven hetzelfde; met lay-outgroepen kunt u gedeelde lay-outs aan pagina's toevoegen zonder dat ze allemaal de volledige map in beslag nemen routes.

We kon Voeg een ... toe +layout.svelte bestand en wat gek <div> spandoek met de tekst: "Hé, we zijn bezig met to-do's". Maar laten we iets interessants doen. Lay-outs kunnen definiëren load() functies om gegevens te verstrekken voor alle routes eronder. Laten we deze functionaliteit gebruiken om onze tags te laden - aangezien we onze tags in onze zullen gebruiken details pagina — naast de list pagina die we al hebben.

In werkelijkheid is het bijna zeker niet de moeite waard om een ​​lay-outgroep te dwingen om slechts één stuk gegevens te verstrekken; het is beter om die gegevens te dupliceren in de load() functie voor elke pagina. Maar voor dit bericht biedt het het excuus dat we nodig hebben om een ​​nieuwe SvelteKit-functie te zien!

Laten we eerst naar onze gaan list Pagina's +page.server.js bestand en verwijder de tags ervan.

import { getTodos, getTags } from "$lib/data/todoData"; export function load() { const todos = getTodos(); return { todos, };
}

Onze lijstpagina zou nu een fout moeten opleveren, aangezien er geen is tags voorwerp. Laten we dit oplossen door een toe te voegen +layout.server.js bestand in onze lay-outgroep, definieer vervolgens een load() functie die onze tags laadt.

import { getTags } from "$lib/data/todoData"; export function load() { const tags = getTags(); return { tags, };
}

En zomaar wordt onze lijstpagina weer weergegeven!

We laden gegevens van meerdere locaties

Laten we een punt zetten op wat hier gebeurt:

  • We hebben een load() functie voor onze lay-outgroep, die we hebben ingevoerd +layout.server.js.
  • Dit levert gegevens op voor allen van de pagina's waarvoor de lay-out dient - wat in dit geval onze Lijst- en Details-pagina's betekent.
  • Onze lijstpagina definieert ook een load() functie die erin gaat +page.server.js bestand.
  • SvelteKit doet het gromwerk door de resultaten van deze gegevensbronnen te nemen, ze samen te voegen en beide beschikbaar te maken in data.

Onze Details-pagina

We gebruiken onze Details-pagina om een ​​actiepunt te bewerken. Laten we eerst een kolom toevoegen aan de tabel op onze lijstpagina die linkt naar de pagina Details met de ID van het actiepunt in de querystring.

<td><a href="/nl/details?id={t.id}">Edit</a></td>

Laten we nu onze Details-pagina uitbouwen. Eerst voegen we een lader toe om het actiepunt te pakken dat we aan het bewerken zijn. Maak een +page.server.js in /details, met deze inhoud:

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, };
}

Onze lader wordt geleverd met een url eigenschap waaruit we querytekenreekswaarden kunnen halen. Dit maakt het gemakkelijk om het actiepunt op te zoeken dat we aan het bewerken zijn. Laten we die taak weergeven, samen met de functionaliteit om deze te bewerken.

SvelteKit heeft geweldige ingebouwde mutatiemogelijkheden, zolang je maar formulieren gebruikt. Formulieren onthouden? Dit is onze Details-pagina. Ik heb de stijlen kortheidshalve weggelaten.

<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>

We halen de tags zoals voorheen uit de lader van onze lay-outgroep en het actiepunt uit de lader van onze pagina. We pakken de actualiteit tag objecten uit de takenlijst met tag-ID's en vervolgens alles renderen. We maken een formulier met een verborgen invoer voor het ID en een echte invoer voor de titel. We geven de tags weer en bieden vervolgens een knop om het formulier in te dienen.

Als je de use:enhance, dat vertelt SvelteKit gewoon om progressieve verbetering te gebruiken en Ajax om ons formulier in te dienen. Die zul je waarschijnlijk altijd gebruiken.

Hoe slaan we onze bewerkingen op?

Let op de action="?/editTodo" attribuut op het formulier zelf? Dit vertelt ons waar we onze bewerkte gegevens naartoe willen sturen. Voor ons geval willen we ons onderwerpen aan een editTodo "actie."

Laten we het maken door het volgende toe te voegen aan de +page.server.js bestand dat we al hebben voor Details (dat momenteel een load() functie, om onze to-do te grijpen):

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"); },
};

Vormacties geven ons een request object, dat toegang geeft tot onze formData, die een heeft get methode voor onze verschillende formuliervelden. We hebben die verborgen invoer voor de ID-waarde toegevoegd, zodat we die hier kunnen pakken om het actiepunt op te zoeken dat we aan het bewerken zijn. We simuleren een vertraging, bellen een nieuw updateTodo() methode, en leid de gebruiker vervolgens terug naar de /list pagina. De updateTodo() methode werkt alleen onze statische gegevens bij; in het echte leven zou je een soort update uitvoeren in welke datastore je ook gebruikt.

export async function updateTodo(id, newTitle) { const todo = todos.find(t => t.id == id); Object.assign(todo, { title: newTitle });
}

Laten we het eens proberen. We gaan eerst naar de lijstpagina:

Lijstpagina met to-do-items.

Laten we nu op de knop Bewerken klikken voor een van de taken om de bewerkingspagina weer te geven /details.

Detailspagina voor een actiepunt.

We gaan een nieuwe titel toevoegen:

De titel van de actie wijzigen in een bewerkbare tekstinvoer.

Klik nu op Opslaan. Dat zou ons terug moeten brengen naar onze /list pagina, met de nieuwe taaktitel toegepast.

Het bewerkte actiepunt in de volledige lijstweergave.

Hoe kwam de nieuwe titel zo opdagen? Het ging automatisch. Zodra we doorverwezen naar de /list pagina, heeft SvelteKit automatisch al onze laders opnieuw uitgevoerd, net zoals het hoe dan ook zou hebben gedaan. Dit is de belangrijkste vooruitgang die next-gen applicatieframeworks, zoals SvelteKit, Remix en Volgend 13 voorzien in. In plaats van u een handige manier te bieden om pagina's weer te geven en u vervolgens veel succes te wensen bij het ophalen van alle eindpunten die u nodig heeft om gegevens bij te werken, integreren ze gegevensmutatie naast het laden van gegevens, waardoor de twee samen kunnen werken.

Een paar dingen die je je misschien afvraagt...

Deze mutatie-update lijkt niet al te indrukwekkend. De laders worden opnieuw uitgevoerd wanneer u navigeert. Wat als we geen omleiding hadden toegevoegd aan onze formulieractie, maar op de huidige pagina waren gebleven? SvelteKit zou de update uitvoeren in de vormactie, zoals voorheen, maar zou dat wel doen nog voer alle laders voor de huidige pagina opnieuw uit, inclusief de laders in de paginalay-out(s).

Kunnen we meer gerichte middelen hebben om onze gegevens ongeldig te maken? Onze tags zijn bijvoorbeeld niet bewerkt, dus in het echte leven zouden we ze niet opnieuw willen opvragen. Ja, wat ik je heb laten zien, is gewoon het standaardformuliergedrag in SvelteKit. U kunt het standaardgedrag uitschakelen door terugbellen naar use:enhance. Dan levert SvelteKit een handleiding invaliderende functies.

Het laden van gegevens op elke navigatie is potentieel duur en onnodig. Kan ik deze gegevens cachen zoals ik doe met tools zoals react-query? Ja, alleen anders. Met SvelteKit kunt u de cache-control-headers instellen (en vervolgens respecteren) die het web al biedt. En ik zal cache-invalidatiemechanismen behandelen in een vervolgpost.

Alles wat we in dit artikel hebben gedaan, gebruikt statische gegevens en wijzigt waarden in het geheugen. Als u alles moet terugdraaien en opnieuw moet beginnen, stopt u het npm run dev Knooppunt proces.

Afsluiten

We hebben nauwelijks het oppervlak van SvelteKit bekrast, maar hopelijk heb je genoeg gezien om er enthousiast over te worden. Ik kan me niet herinneren wanneer ik webontwikkeling voor het laatst zo leuk heb gevonden. Met zaken als bundeling, routering, SSR en implementatie die allemaal kant-en-klaar worden afgehandeld, kan ik meer tijd besteden aan coderen dan aan configureren.

Hier zijn nog een paar bronnen die u kunt gebruiken als volgende stappen om SvelteKit te leren:

spot_img

Laatste intelligentie

spot_img