Streaming de serveur de framework fantastique

Lorsque vous avez des données lentes et non essentielles qui se chargent dans votre page, le streaming des données peut être un moyen merveilleux de garder la page plus rapide et interactive.
TL; Dr
Nous construisons et analysons un exemple de streaming dans tous les principaux cadres où le streaming est disponible.
Qu’est-ce que le streaming HTTP?
Lorsque nous avons des données dans une page Web qui peuvent prendre plus de temps à charger que les données essentielles, cela peut ralentir la page. Le streaming nous permet d’abord de charger les données importantes, puis de charger les données non essentielles plus tard.
Le streaming s’est avéré aider avec le référencement, y compris plus rapidement Première peinture contentmieux La plus grande peinture de contenance et Il est temps de premier octet.
Le streaming charge les données lents en dernier, puis JavaScript insérera les données au bon endroit une fois la page entière chargée. C’est l’explication la plus simple.
Exemple de blog
Imaginez que vous consultez un article de blog avec de nombreux commentaires. Vous devez d’abord être en mesure de visualiser les données du billet de blog, afin que des éléments comme le titre et la description puissent être immédiatement affichés dans le <head>
et en-tête de votre article.
Si vous avez plusieurs commentaires, il serait préférable de séparer votre requête de base de données afin que vous puissiez obtenir les commentaires plus tard. Les commentaires sont moins importants et peuvent être affichés une fois les données essentielles chargées.
Exemple de Todo Application
Dans nos applications, nous allons récupérer un élément de TODO aléatoire à partir d’un exemple externe API en latin.
type Todo = {
title: string
};
export const getTodo = async () => {
const randomTodo = Math.floor(Math.random() * 200) + 1;
return await fetch(`https://jsonplaceholder.typicode.com/todos/${randomTodo}`)
.then(r => r.json()) as Todo;
};
Cette API dispose de 200 éléments TODO différents, nous en sélectionnerons donc un dans le hasard chaque fois que la page est chargée. Si vous actualisez la page, vous devriez obtenir un nouvel élément.
Next.js
Bien que je déteste personnellement React et JSX, je donne beaucoup d’accessoires à l’équipe suivante.js de Vercel. Suivant.js a été controversé ces derniers temps, mais le streaming est définitivement un costume fort.
Tout composant
// todo.tsx
'use server';
type Todo = {
title: string
};
export const getTodo = async () => {
const randomTodo = Math.floor(Math.random() * 200) + 1;
return await fetch(`https://jsonplaceholder.typicode.com/todos/${randomTodo}`, {
cache: 'no-cache'
})
.then(r => r.json()) as Todo;
};
export default async function Todo() {
const todo = await getTodo();
return (
<h2>{todo.title}</h2>
);
}
Nous utilisons un composant de serveur avec use server
. Remarque que nous devons ajouter no-cache
Option pour empêcher Next.js de mettre en cache notre page.
Spinner de chargement
J’utilise également un spinner de chargement. Gardez à l’esprit que c’est la beauté du streaming. Nous chargeons directement à partir du serveur puis du navigateur.
export default function Loading() {
return (
<div role="status">
<svg
aria-hidden="true"
className="w-8 h-8 text-gray-200 animate-spin dark:text-gray-600 fill-blue-600"
viewBox="0 0 100 101"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor"
/>
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill"
/>
</svg>
<span className="sr-only">Loading...</span>
</div>
);
}
Note: Cet exemple de spinner a été tiré de Débiter et nécessite un vent arrière.
Vous pouvez essayer le Composant de chargeur disponible avec Kendoreact gratuit.
Attente
React a déjà un élément qui peut charger des données lentes. Il s’appelle <Suspense />
.
import { Suspense } from "react";
import Todo from "./todo";
import Loading from "./loading";
export default function Home() {
return (
<main className="flex flex-col justify-center items-center mt-5 gap-3">
<h1 className="text-2xl">Todo</h1>
<Suspense fallback={<Loading />}>
<Todo />
</Suspense>
</main>
);
}
En emballant notre élément en suspense et en utilisant notre chargeur comme secours, tout fonctionne parfaitement.
Démo: Vercel
Repo: Girub
Docs: Chargement de l’interface utilisateur et streaming
Sveltek
Sveltekit n’a pas de composants de serveur, mais des chargeurs de page.
Chargeur de serveur de page
import type { PageServerLoad } from "./$types";
type Todo = {
title: string
};
const getTodo = async () => {
const randomTodo = Math.floor(Math.random() * 200) + 1;
return await fetch(`https://jsonplaceholder.typicode.com/todos/${randomTodo}`)
.then(r => r.json()) as Todo;
};
export const load: PageServerLoad = () => {
return {
todos: getTodo()
};
};
Lorsque nous retournerons notre fonction asynchrone directement, la fonction sera diffusée au navigateur au fur et à mesure de sa résolution.
export const load: PageServerLoad = () => {
return {
post: getPost()
};
};
À moins que nous ayons des données essentielles qui doivent être chargées en premier.
export const load: PageServerLoad = () => {
const post = await getPost();
return {
post
};
}
// OR
export const load: PageServerLoad = () => {
return {
post: await getPost()
};
}
Note: Assurez-vous qu’une promesse ne peut pas être rejetée avant de retourner la fonction pour gérer correctement les erreurs.
Composant de page
Nous pouvons obtenir les données de la page en utilisant await
à l’intérieur de notre composant. Nous attrapons l’erreur si nécessaire ou affichons le chargeur. Beau!
<script lang="ts">
import type { PageProps } from "./$types";
import Loading from "./loading.svelte";
let { data }: PageProps = $props();
</script>
<main class="flex flex-col justify-center items-center mt-5 gap-3">
<h1 class="text-2xl">Todo</h1>
{#await data.todos}
<Loading />
{:then todo}
<h2>{todo.title}</h2>
{:catch error}
<p>{error.message}</p>
{/await}
</main>
Svelte est de loin mon cadre préféré, donc je suis content que cette fonctionnalité soit disponible!
Démo: Vercel
Repo: Girub
Docs: Streaming avec des promesses
Qwik
Qwik suit le même modèle, mais n’est pas encore prêt.
Chargeur
type Todo = {
title: string
};
export const useTodo = routeLoader$(() => {
return async () => {
const randomTodo = Math.floor(Math.random() * 200) + 1;
return await fetch(`https://jsonplaceholder.typicode.com/todos/${randomTodo}`)
.then(r => r.json()) as Todo;
}
});
Composant
Similaire à <Suspense />
Qwik a un <Resource />
composant qui charge les données comme prévu.
export default component$(() => {
const todo = useTodo();
return (
<main class="flex flex-col justify-center items-center mt-5 gap-3">
<h1 class="text-2xl">Todo</h1>
<Resource
value={todo}
onPending={() => <Loading />}
onResolved={(todo) => <h2>{todo.title}</h2>}
/>
</main>
);
});
Note: Actuellement, le onPending
ne fonctionne pas correctement pour afficher un état de chargement, et il y a un Problème de github pour ça. Qwik diffuse techniquement la réponse, mais attend toujours de terminer. V2 résoudra ceci.
Solide
Le framework serveur de SolidJS est conçu pour le streaming, littéralement.
Chargeur de requête
La requête doit être chargée avec use server
pour fonctionner correctement.
type Todo = {
title: string
};
const getTodo = query(async () => {
'use server';
const randomTodo = Math.floor(Math.random() * 200) + 1;
const todo = await fetch(`https://jsonplaceholder.typicode.com/todos/${randomTodo}`);
return await todo.json() as Todo;
}, 'todo');
export const route = {
preload: () => getTodo()
} satisfies RouteDefinition;
Et la fonction doit être ajoutée à preload
.
Composant
export default function Home() {
const todo = createAsync(() => getTodo());
return (
<main class="flex flex-col justify-center items-center mt-5 gap-3">
<h1 class="text-2xl">Todo</h1>
<ErrorBoundary fallback={<div>Something went wrong!</div>}>
<Suspense fallback={<Loading />}>
<Show when={todo()}>
{(data) => (
<h2>{data().title}</h2>
)}
</Show>
</Suspense>
</ErrorBoundary>
</main>
);
}
Nous devons obtenir les données avec createAsync
d’abord. Nous pouvons le mettre à l’intérieur d’un ErrorBoundary
pour attraper des erreurs. Suspense
détermine quand nous chargeons, et Show
Affichera le composant lorsqu’il sera disponible.
Je trouve que SolidJS a trop de passe-partout pour mes goûts personnels, mais il a fonctionné avec le streaming dès le premier jour.
Démo: Vercel
Repo: Girub
Docs: Chargement des données toujours sur le serveur
Nuxt
Nuxt a actuellement un problème d’ouverture Et prévoit d’ajouter la fonctionnalité bientôt!
Angulaire / analogique
Angular ne l’implémentera probablement jamais, même s’il s’agit d’un cadre semi-serveur avec @angular/ssr
. Il y avait un ancienne demande de fonctionnalité qui a été refusé. Analog a un nouveau demande de fonctionnalitémais aucune confirmation.
Conclure
Le streaming est un outil incroyable à ajouter à votre répertoire. Lorsque vous devez accélérer votre page, cela vous aidera certainement à surpasser la concurrence avec de meilleures vitesses de chargement de page.
Source link