Primeros pasos con SvelteKit | trucos CSS
SvelteKit es lo último de lo que yo llamaría marcos de aplicaciones de próxima generación. Por supuesto, crea una aplicación para usted, con enrutamiento basado en archivos, implementación y representación del lado del servidor, lo que Next ha estado haciendo desde siempre. Pero SvelteKit también admite diseños anidados, mutaciones de servidor que sincronizan los datos de su página y algunas otras sutilezas que cubriremos.
Esta publicación pretende ser una introducción de alto nivel para, con suerte, crear entusiasmo para cualquiera que nunca haya usado SvelteKit. Este será un recorrido tranquilo. Si te gusta lo que ves, los documentos completos están aquí.
En cierto modo, es un desafío de escritura. SvelteKit es marco de aplicación. Existe para ayudarlo a crear... bueno, aplicaciones. Esto hace que sea difícil de demostrar. No es posible crear una aplicación completa en una publicación de blog. Entonces, en cambio, vamos a usar un poco nuestra imaginación. Vamos a construir una aplicación de esqueleto, hay algunos contenedores de interfaz de usuario vacíos y datos estáticos codificados. El objetivo no es crear una aplicación real, sino mostrarle cómo funcionan las partes móviles de SvelteKit para que pueda crear su propia aplicación.
Con ese fin, crearemos la aplicación To-Do probada y verdadera como ejemplo. Pero no se preocupe, se tratará mucho más de ver cómo funciona SvelteKit que de crear otra aplicación To-Do.
El código para todo en esta publicación es disponible en GitHub.Este proyecto es demasiado ubicado en Vercel para una demostración en vivo.
Creando tu proyecto
Crear un nuevo proyecto SvelteKit es bastante simple npm create [email protected] your-app-name
en la terminal y responde las preguntas. Asegúrese de seleccionar "Proyecto esqueleto", pero de lo contrario, haga las selecciones que desee para TypeScript, ESLint, etc.
Una vez creado el proyecto, ejecútelo. npm i
y npm run dev
y el servidor de desarrollo debe estar en funcionamiento localhost:5173
en el navegador y obtendrá la página del contenedor de la aplicación de esqueleto.
Enrutamiento básico
darse cuenta routes
carpeta debajo src
Este contiene código para todas nuestras rutas. ya hay un +page.svelte
archivo allí con contenido para root /
No importa en qué parte de la jerarquía de archivos se encuentre, la página real para esa ruta siempre tiene el nombre +page.svelte
Con eso en mente, creemos páginas para /list
, /details
, /admin/user-settings
y admin/paid-status
y también agregue algunos contenedores de texto para cada página.
El diseño de su archivo debería verse así:
Debería poder navegar cambiando las rutas URL en la barra de direcciones del navegador.
Diseños
Querremos enlaces de navegación en nuestra aplicación, pero ciertamente no queremos copiar el marcado para ellos en cada página que creamos. Así que vamos a crear +layout.svelte
archivo en la raíz de nuestro routes
carpeta que SvelteKit tratará como una plantilla global para todas las páginas. Agreguemos algo de contenido:
<nav>
<ul>
<li>
<a href="https://css-tricks.com/">Home</a>
</li>
<li>
<a href="https://css-tricks.com/list">To-Do list</a>
</li>
<li>
<a href="https://css-tricks.com/admin/paid-status">Account status</a>
</li>
<li>
<a href="https://css-tricks.com/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>
Un poco de navegación básica con un estilo básico. Es de especial importancia <slot />
etiqueta Esto es todo no slot que usas con web components y shadow DOM, sino más bien una función de Svelte que indica dónde poner nuestro contenido. Cuando se representa la página, el contenido de la página se deslizará hacia donde está la ranura.
¡Y ahora tenemos algo de navegación! No vamos a ganar ningún concurso de diseño, pero no lo intentaremos.
Diseños anidados
¿Qué pasa si queremos que todas nuestras páginas de administración hereden el diseño normal que acabamos de crear, pero también compartimos algunas cosas comunes a todas las páginas de administración (pero solo a las páginas de administración)? No hay problema, estamos agregando otro +layout.svelte
archivo en nuestra raíz admin
directorio que será heredado por todo lo que esté debajo de él. Hagamos esto y agreguemos este contenido:
<div>This is an admin page</div>
<slot />
<style>
div {
padding: 15px;
margin: 10px 0;
background-color: red;
color: white;
}
</style>
Agregamos un banner rojo que indica que esta es una página de administración y luego, como antes, un <slot />
especificando dónde queremos que vaya el contenido de nuestra página.
Nuestro diseño básico anterior es el renderizado. Dentro del diseño principal hay un <slot />
El contenido del diseño anidado va al diseño principal <slot />
Finalmente, el diseño anidado define su propio <slot />
en el que se representa el contenido de la página.
Si navega a las páginas de administración, debería ver el nuevo banner rojo:
Definiendo nuestros datos
Bien, grafiquemos algunos datos reales, o al menos veamos cómo podemos graficar algunos datos reales. Hay cientos de formas de crear y conectarse a una base de datos. Sin embargo, esta publicación trata sobre SvelteKit, no sobre la administración de DynamoDB, por lo que "cargaremos" algunos datos estáticos en su lugar. Pero usaremos los mismos motores para leerlos y actualizarlos que usted usaría para datos reales. Para una verdadera aplicación web, reemplace las funciones que devuelven datos estáticos con funciones que se conectan y consultan cualquier base de datos que esté utilizando.
Vamos a crear un módulo muy simple en lib/data/todoData.ts
que devuelve algunos datos estáticos junto con retrasos artificiales para simular solicitudes reales. verás esto lib
carpeta importada en otro lugar a través de $lib
Esta es una característica de SvelteKit para esta carpeta en particular e incluso puede agregue sus propios 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 función para devolver una matriz plana de nuestras tareas, una búsqueda de nuestras etiquetas y una función para recuperar una sola tarea (usaremos esta última en nuestra página de detalles).
Nuestros datos se están cargando
¿Cómo conseguimos estos datos en nuestras páginas Svelte? Hay muchas formas, pero por ahora vamos a crear +page.server.js
archivo en nuestro list
carpeta y poner este contenido en ella:
import { getTodos, getTags } from "$lib/data/todoData";
export function load() {
const todos = getTodos();
const tags = getTags();
return {
todos,
tags,
};
}
Hemos definido un load()
función que descarga los datos necesarios para la página. Tenga en cuenta que estamos no await
llama a nuestro getTodos
y getTags
funciones asíncronas. Esto crearía una cascada de carga de datos mientras esperamos que lleguen nuestros trabajos antes de cargar nuestras etiquetas. En su lugar, devolvemos las promesas en bruto de load
y SvelteKit hace el trabajo para await
ellos.
Entonces, ¿cómo accedemos a estos datos desde nuestro componente de página? SvelteKit proporciona un data
prop para nuestro componente con datos. Accederemos a nuestras tareas y etiquetas desde él usando un asignación reactiva.
Nuestro componente de página de lista ahora se ve así.
<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>
¡Y esto debería representar nuestras tareas!
Grupos de diseño
Antes de saltar a la página de detalles y cambiar los datos, echemos un vistazo a una característica realmente genial de SvelteKit: grupos de diseñoYa hemos visto diseños anidados para todas las páginas de administración, pero ¿qué pasa si queremos compartir un diseño entre páginas arbitrarias en el mismo nivel de nuestro sistema de archivos? En particular, ¿qué pasa si solo queremos compartir un diseño entre nuestra página de lista y nuestra página de detalles? Ahora tenemos un diseño global en este nivel. En su lugar, podemos crear un nuevo directorio, pero con un nombre entre paréntesis, como este:
Ahora tenemos un grupo de diseño que cubre nuestra lista y las páginas de detalles. la llamé (todo-management)
pero puedes ponerle el nombre que quieras. Para ser claros, este nombre servirá no afectan las URL de las páginas dentro del grupo de diseño. Las URL seguirán siendo las mismas; Los grupos de diseño le permiten agregar diseños compartidos a las páginas sin que todos compongan el directorio completo en routes
.
nosotros podría agregado +layout.svelte
archivo y alguna estupidez <div>
un cartel que dice: "Oye, gestionamos tareas". Pero hagamos algo más interesante. Los diseños pueden definir load()
funciones para proporcionar datos para todas las rutas por debajo de ellos. Usemos esta funcionalidad para cargar nuestras etiquetas, ya que usaremos nuestras etiquetas en el details
página — además de list
página que ya tenemos.
En realidad, es casi seguro que no vale la pena obligar a un grupo de diseños solo a proporcionar un solo dato; es mejor duplicar estos datos en load()
Función para cada página. ¡Pero para esta publicación, proporcionará la excusa que necesitamos para ver una nueva característica de SvelteKit!
Primero, entremos en lo nuestro. list
paginas +page.server.js
archivo y elimine las etiquetas de él.
import { getTodos, getTags } from "$lib/data/todoData";
export function load() {
const todos = getTodos();
return {
todos,
};
}
Nuestra página de lista ahora debería generar un error ya que no tags
Arreglemos esto agregando un +layout.server.js
archivo en nuestro grupo de diseño, luego defina un load()
función que carga nuestras etiquetas.
import { getTags } from "$lib/data/todoData";
export function load() {
const tags = getTags();
return {
tags,
};
}
¡Y así, nuestra página de listado se muestra de nuevo!
Cargamos datos desde múltiples ubicaciones
Pongamos letra pequeña en lo que está pasando aquí:
- Definimos un
load()
función para nuestro grupo de diseño que colocamos+layout.server.js
. - Esto proporciona datos para todo de las páginas que sirve el diseño, lo que en este caso significa nuestras páginas de lista y detalles.
- Nuestra página de lista también define un
load()
función que entra en él+page.server.js
expediente. - SvelteKit hace el trabajo agotador de tomar los resultados de estas fuentes de datos, fusionarlos y proporcionar ambos en
data
.
Nuestra página de detalles
Usaremos nuestra página de detalles para editar un elemento de tarea. Primero, agreguemos una columna a la tabla en nuestra página de lista que se vincule a la página de detalles con el ID del elemento de la tarea en la cadena de consulta.
<td><a href="https://css-tricks.com/details?id={t.id}">Edit</a></td>
Ahora construyamos nuestra página de detalles. Primero agregaremos un cargador para capturar el elemento de la tarea que estamos editando. Crear +page.server.js
en /details
con el siguiente contenido:
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,
};
}
Nuestro cargador viene con un url
propiedad de la que podemos recuperar valores de cadena de solicitud. Esto facilita la búsqueda del elemento de la tarea que estamos editando. Veamos una vista previa de esta tarea, junto con la funcionalidad para editarla.
SvelteKit tiene maravillosas capacidades de mutación incorporadas siempre que use formularios. ¿Recuerdas los formularios? Aquí está nuestra página de detalles. Eliminé los estilos por brevedad.
<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>
Tomamos las etiquetas como antes de nuestro cargador de grupos de diseño y el elemento de tareas de nuestro cargador de páginas. Tomamos los reales tag
objetos de la lista de tareas con ID de etiquetas y luego renderizar todo. Creamos un formulario con una entrada oculta para la identificación y una entrada real para el título. Mostramos las etiquetas y luego proporcionamos un botón para enviar el formulario.
si te has dado cuenta use:enhance
que solo le dice a SvelteKit que use la mejora progresiva y Ajax para enviar nuestro formulario. Probablemente siempre usarás esto.
¿Cómo guardamos nuestras ediciones?
darse cuenta action="?/editTodo"
atributo de la forma en sí? Esto nos dice dónde queremos enviar nuestros datos editados. Para nuestro caso queremos enviar a editTodo
"acción".
Vamos a crearlo agregando lo siguiente al +page.server.js
archivo que ya tenemos para detalles (que actualmente tiene un load()
función para obtener nuestras tareas):
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, "https://css-tricks.com/list");
},
};
Las acciones del formulario nos dan una request
objeto que nos proporciona acceso formData
que tiene un get
para nuestros diversos campos de formulario. Hemos agregado esta entrada oculta para el valor de ID para que podamos tomarla aquí y buscar el elemento de la tarea que estamos editando. Simulamos un retraso, llamamos uno nuevo updateTodo()
método, luego redirigir al usuario de nuevo a /list
página. updateTodo()
método simplemente actualiza nuestros datos estáticos; en la vida real, realizaría algún tipo de actualización en cualquier almacén de datos que esté utilizando.
export async function updateTodo(id, newTitle) {
const todo = todos.find(t => t.id == id);
Object.assign(todo, { title: newTitle });
}
Probémoslo. Primero iremos a la página de lista:
Ahora hagamos clic en el botón Editar de uno de los elementos de la tarea para que aparezca la página de edición. /details
.
Añadiremos un nuevo título:
Ahora haga clic en Guardar. Eso debería traernos de vuelta a lo nuestro. /list
página con el título de la nueva tarea adjunto.
¿Cómo surgió el nuevo título? Fue automático. Después de redirigir a /list
página, SvelteKit reinicia automáticamente todos nuestros cargadores tal como lo haría de forma independiente. Este es el avance clave que los marcos de aplicaciones de próxima generación, como SvelteKit, remezclary Siguiente 13 En lugar de brindarle una forma conveniente de representar páginas y luego desearle buena suerte para recuperar los puntos finales en los que necesita actualizar los datos, integran la mutación de datos junto con la carga de datos, lo que permite que los dos funcionen en conjunto.
Algunas cosas que te estarás preguntando...
Esta actualización de mutación no parece demasiado impresionante. Los cargadores se ejecutarán de nuevo cuando navegues. ¿Qué pasaría si no hubiéramos agregado una redirección a nuestra acción de formulario y nos hubiéramos quedado en la página actual? SvelteKit realizará la actualización en la acción de formulario como antes, pero todavía reinicie todos los cargadores para la página actual, incluidos los cargadores en los diseños de página.
¿Podríamos tener un medio más específico para invalidar nuestros datos? Por ejemplo, nuestras etiquetas no se editaron, por lo que en la vida real no querríamos volver a reclamarlas. Sí, lo que le he mostrado es solo el comportamiento predeterminado de los formularios en SvelteKit. Puede desactivar el comportamiento predeterminado desde proporcionar una devolución de llamada a use:enhance
.SvelteKit luego proporciona una guía funciones de invalidación.
Cargar datos en cada navegación es potencialmente costoso e innecesario. ¿Puedo almacenar en caché estos datos como lo hago con herramientas como react-query
?Sí, sólo que de una manera diferente. SvelteKit le permite establecer (y luego respetar) los encabezados de control de caché que ya proporciona la red. Y cubriré los mecanismos de invalidación de caché en una publicación de seguimiento.
Todo lo que hemos hecho en este artículo usa datos estáticos y cambia valores en la memoria. Si necesita volver atrás y empezar de nuevo, deténgase y reinicie npm run dev
Un proceso de nodo.
resumiendo
Apenas hemos arañado la superficie de SvelteKit, pero esperamos que hayas visto lo suficiente como para emocionarte. No puedo recordar la última vez que encontré el desarrollo web tan divertido. Con cosas como la agrupación en clústeres, el enrutamiento, SSR y la implementación que se manejan desde el primer momento, paso más tiempo codificando que configurando.
Aquí hay algunos recursos más que puede usar como próximos pasos para aprender el EsbeltoKit:
Deja una respuesta