Maison >interface Web >tutoriel CSS >Cache de données dans sveltekit
Mon article précédent a fourni un aperçu général des capacités de Sveltekit. Cet article plonge dans un aspect crucial du développement Web: cache . Si vous ne l'avez pas déjà fait, veuillez lire mon article précédent pour le contexte. Le code complet et une démo en direct sont disponibles sur github.
Ce message se concentre sur une gestion efficace des données. Nous implémenterons les fonctionnalités de recherche de base qui modifie la chaîne de requête de la page (en utilisant les fonctionnalités intégrées de Sveltekit) et re-remanie le chargeur de la page. Au lieu d'interroger à plusieurs reprises une base de données, nous ferons tirer parti de la mise en cache pour récupérer rapidement les données recherchées précédemment. Nous explorerons les techniques de gestion de l'expiration du cache et, de manière critique, de l'invalidation manuelle du cache. Enfin, nous allons montrer comment mettre à jour les données côté client après une mutation tout en nettoyant simultanément le cache.
Il s'agit d'un sujet plus avancé que d'habitude. Nous implémenterons des fonctionnalités similaires à celles trouvées dans des bibliothèques comme react-query
, mais sans compter sur des dépendances externes. Nous n'utiliserons que les API de plate-forme Web et les fonctionnalités Sveltekit.
Bien que les fonctionnalités de la plate-forme Web soient de niveau inférieur, nécessitant plus d'efforts manuels, le bénéfice est réduit la taille du faisceau en raison de l'absence de bibliothèques externes. Cependant, n'utilisez ces techniques que lorsque cela est absolument nécessaire. La mise en cache peut être complexe et facilement mal gérée. Si votre magasin de données et votre interface utilisateur sont suffisamment performants, permettez à Sveltekit de gérer la récupération des données directement - la simplicité est la clé. Ce message fournit des solutions pour quand ce n'est plus suffisant.
Notez que react-query
a maintenant le support Svelte! Si vous avez fréquemment besoin de mise en cache manuelle, envisagez d'explorer cette bibliothèque.
Nous modifierons notre code précédent pour illustrer des fonctionnalités sveltekit supplémentaires.
Tout d'abord, déplaçons le chargement des données du chargeur page.server.js
vers une route API. Créez un fichier server.js
dans routes/api/todos
et ajoutez une fonction Get:
import { json } from "@sveltejs/kit"; import { getTodos } from "$lib/data/todoData"; export async function GET({ url, setHeaders, request }) { const search = url.searchParams.get("search") || ""; setHeaders({ "cache-control": "max-age=60" }); // Add caching header const todos = await getTodos(search); return json(todos); }
Ensuite, renommez le chargeur de page de page.server.js
à page.js
(ou .ts
). Cela en fait un chargeur universel, fonctionnant sur le serveur et le client. La fetch côté client utilisera la fonction native du navigateur fetch
.
export async function load({ fetch, url, setHeaders }) { const search = url.searchParams.get("search") || ""; const resp = await fetch(`/api/todos?search=${encodeURIComponent(search)}`); const todos = await resp.json(); return { todos }; }
Ajoutez un formulaire de recherche simple à la page /list
:
<div> <label for="search">Search:</label> <input type="text" id="search" bind:value="{searchQuery}" on:keypress="{(e)"> { if (e.key === 'Enter') { navigate(`/list?search=${encodeURIComponent(searchQuery)}`) } }}> </div>
Maintenant, la saisie d'un terme de recherche mettra à jour la chaîne de requête de l'URL, déclenchera le chargeur et recherchera des éléments à faire.
Enfin, augmentez le retard dans todoData.js
pour observer facilement le comportement de mise en cache:
export const wait = async (amount) => new Promise((res) => setTimeout(res, amount ?? 500));
Le code complet est sur github.
Ajoutons de la mise en cache à notre point final /api/todos
en modifiant le fichier server.js
:
import { json } from "@sveltejs/kit"; import { getTodos } from "$lib/data/todoData"; export async function GET({ url, setHeaders, request }) { const search = url.searchParams.get("search") || ""; setHeaders({ "cache-control": "max-age=60" }); // Add caching header const todos = await getTodos(search); return json(todos); }
Cette API cache appelle 60 secondes. Ajustez cette valeur au besoin. Considérez stale-while-revalidate
pour des stratégies de mise en cache plus sophistiquées.
Maintenant, les recherches ultérieures dans la fenêtre de 60 secondes se chargeront instantanément à partir du cache. N'oubliez pas de désactiver la mise en cache dans les outils de développeur de votre navigateur pour observer le comportement de mise en cache.
La charge initiale rendu du serveur est récupérée sur le serveur et envoyée au client. Sveltekit observe l'en-tête Cache-Control
et utilise des données mises en cache dans le délai spécifié. Les recherches côté client utiliseront le cache du navigateur, potentiellement persistant même après les recharges de page (en fonction de l'implémentation de cache).
Pour invalider manuellement le cache, nous ajouterons une valeur de buste de requête à l'URL. Nous stockons cette valeur dans un cookie, réglable sur le serveur mais lisible sur le client.
Créez un fichier layout.server.js
à la racine de votre dossier de routes:
export async function load({ fetch, url, setHeaders }) { const search = url.searchParams.get("search") || ""; const resp = await fetch(`/api/todos?search=${encodeURIComponent(search)}`); const todos = await resp.json(); return { todos }; }
Cela définit un cookie sur la demande initiale et le lit sur les demandes suivantes. httpOnly: false
permet l'accès côté client à des fins de cache.
Notre chargeur universel doit lire cette valeur de cache, quel que soit l'environnement d'exécution. Sur le client, nous analyserons document.cookie
:
<div> <label for="search">Search:</label> <input type="text" id="search" bind:value="{searchQuery}" on:keypress="{(e)"> { if (e.key === 'Enter') { navigate(`/list?search=${encodeURIComponent(searchQuery)}`) } }}> </div>
Maintenant, envoyez cette valeur au point de terminaison /api/todos
:
export const wait = async (amount) => new Promise((res) => setTimeout(res, amount ?? 500));
Mettez à jour la valeur de cache de cache dans toute action du serveur en utilisant:
setHeaders({ "cache-control": "max-age=60" });
Nous avons couvert les primitives nécessaires. Maintenant, intégrons-les. Nous allons ajouter des fonctionnalités d'édition à la page /list
. Ajoutez ces lignes à votre table:
export function load({ cookies, isDataRequest }) { const initialRequest = !isDataRequest; const cacheValue = initialRequest ? +new Date() : cookies.get("todos-cache"); if (initialRequest) { cookies.set("todos-cache", cacheValue, { path: "/", httpOnly: false }); } return { todosCacheBust: cacheValue }; }
Créer un fichier page.server.js
dans le dossier /list
:
export function getCookieLookup() { if (typeof document !== "object") { return {}; } return document.cookie.split("; ").reduce((lookup, v) => { const parts = v.split("="); lookup[parts[0]] = parts[1]; return lookup; }, {}); } export const getCurrentCookieValue = (name) => { const cookies = getCookieLookup(); return cookies[name] ?? ""; };
Cela gère les soumissions de formulaires, met à jour l'élément de tâche et efface le cache.
Après l'édition, une récupération de /todos
récupère les données mises à jour.
Pour éviter la récupération post-édition, mettez à jour l'interface utilisateur directement. Modifiez le chargeur pour retourner une boutique en écriture:
import { getCurrentCookieValue } from "$lib/util/cookieUtils"; export async function load({ fetch, parent, url, setHeaders }) { const parentData = await parent(); const cacheBust = getCurrentCookieValue("todos-cache") || parentData.todosCacheBust; const search = url.searchParams.get("search") || ""; const resp = await fetch(`/api/todos?search=${encodeURIComponent(search)}&cache=${cacheBust}`); const todos = await resp.json(); return { todos }; }
Utilisez $todos
dans votre modèle: {#each $todos as t}
. Maintenant, mettez à jour le magasin directement:
cookies.set("todos-cache", +new Date(), { path: "/", httpOnly: false });
Cela met à jour le magasin sans déclencher de refonte. Le cache est effacé et les changements sont immédiatement visibles.
Le code pour les mises à jour immédiates est sur github.
Ajoutons un bouton de rechargement pour effacer le cache et recharger la requête actuelle. Ajoutez une action du serveur:
<tr> <td><input type="text" bind:value="{t.title}" name="title"></td> <td><input type="hidden" name="id" value="{t.id}"></td> <td><button type="submit" form="edit-{t.id}">Save</button></td> </tr>
et une forme:
import { getTodo, updateTodo, wait } from "$lib/data/todoData"; export const actions = { async editTodo({ request, cookies }) { const formData = await request.formData(); const id = formData.get("id"); const newTitle = formData.get("title"); await wait(250); updateTodo(id, newTitle); cookies.set("todos-cache", +new Date(), { path: "/", httpOnly: false }); }, };
Pour améliorer cela, ajoutons l'invalidation des commentaires et du contrôle:
return { todos: writable(todos) };
Ceci utilise invalidate
pour contrôler ce qui est rechargé, empêchant les redevateurs inutiles. Mettez à jour le chargeur:
import { json } from "@sveltejs/kit"; import { getTodos } from "$lib/data/todoData"; export async function GET({ url, setHeaders, request }) { const search = url.searchParams.get("search") || ""; setHeaders({ "cache-control": "max-age=60" }); // Add caching header const todos = await getTodos(search); return json(todos); }
Le code du bouton de rechargement est sur github.
Ce post a exploré des techniques de mise en cache avancées à Sveltekit. N'oubliez pas de les utiliser uniquement lorsque cela est nécessaire. Prioriser le code propre et simple et optimiser uniquement lorsque les performances deviennent un problème. L'objectif était de fournir des outils lorsque l'optimisation est vraiment nécessaire.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!