Exécution client
Le module @bext-stack/framework/client fournit un script côté client autonome (2 à 6 Ko) qui ajoute une navigation de type SPA et un rechargement en direct aux sites de modèles bext. Aucune étape de construction n'est nécessaire : elle est injectée sous la forme d'une balise <script> en ligne.
Démarrage rapide#
import { clientRuntime } from "@bext-stack/framework/client";
function RootLayout({ children }) {
return (
<html>
<body>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
<a href="/blog">Blog</a>
</nav>
<main>{children}</main>
{clientRuntime()}
</body>
</html>
);
}
Sans configuration, cela permet :
- Cliquez sur un lien → le contenu de la page s'échange instantanément (pas de rechargement complet)
- Les boutons Précédent/Suivant du navigateur fonctionnent
- Mises à jour des URL via
history.pushState
Le rechargement en direct est désactivé par défaut ( liveReload: false ). Passez liveReload: true pour l'activer - le mode de détection automatique essaie d'abord SSE et revient à l'interrogation ETag si la fonctionnalité realtime n'est pas compilée.
Possibilités#
clientRuntime({
navigation: true, // Client-side link interception (default: true)
liveReload: true, // Auto-refresh on server rebuild (default: false)
contentSelector: "main", // Element to swap on navigation (default: "main")
viewTransitions: true, // Use View Transitions API (default: true)
pollInterval: 2000, // Polling interval for live reload (default: 2000ms)
sseEndpoint: "/__bext/events?topics=reload", // SSE endpoint (default)
})
Navigation côté client#
Lorsque navigation: true (valeur par défaut), le script :
- Intercepte les clics sur les liens — Les balises
<a>de même origine naviguent viafetch()au lieu du chargement complet de la page - Swaps
<main>— le sélecteur de contenu est remplacé par le contenu de la nouvelle page - met à jour la description des
<title>et<meta>à partir de la nouvelle page - Pousse l'historique — Modifications d'URL via
pushState, travaux en arrière/avant - Pré-récupère au survol — après 65 ms de survol d'un lien, pré-récupère la page
- Afficher les transitions — lorsque le navigateur prend en charge
document.startViewTransition(), les navigations s'animent avec un fondu enchaîné fluide
Ce qui est préservé#
<nav>,<header>,<footer>— tout ce qui se trouve en dehors de<main>reste- La position de défilement est réinitialisée en haut de la navigation
- Les feuilles de style externes persistent (pas de retéléchargement)
Ce qui est exclu#
Ceux-ci sont traités normalement (chargement de la page entière) :
- Liens externes (origine différente)
- Liens avec l'attribut
target="_blank"oudownload - Touches de modification : Ctrl+clic, Cmd+clic, clic du milieu
- Liens de fichiers :
.pdf,.zip,.png, etc. - Liens de hachage uniquement (
#section) - Liens
mailto:ettel:
Afficher les transitions CSS#
Ajoutez ceci à votre feuille de style pour des transitions de page fluides :
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 0.2s;
}
main {
view-transition-name: main;
}
Modes de rechargement en direct#
Consultez la documentation Rechargement en direct pour plus de détails. Résumé:
| Mode | Configuration | Comment ça marche |
|---|---|---|
| Détection automatique | liveReload: true |
S'essaye à l'ESS, mais revient aux sondages |
| ESS uniquement | liveReload: "sse" |
Événements envoyés par le serveur (nécessite une fonctionnalité en temps réel) |
| Sondage uniquement | liveReload: "poll" |
La requête HEAD vérifie ETag toutes les 2 secondes |
| Désactivé | liveReload: false |
Pas de rafraîchissement automatique |
Tailles des scripts#
| Configuration | Taille |
|---|---|
| Navigation + rechargement en direct (auto) | ~6 Ko |
| Navigation + SSE uniquement | ~5,4 Ko |
| Navigation + sondage uniquement | ~5,6 Ko |
| Navigation uniquement | ~3,7 Ko |
| Tout est éteint | ~150B |
Exemple complet#
import { createSite } from "@bext-stack/framework/entry";
import { defineRoutes } from "@bext-stack/framework/router";
import { clientRuntime } from "@bext-stack/framework/client";
import { stylesheet } from "@bext-stack/framework";
import { h } from "@bext-stack/framework";
const router = defineRoutes({
layout: ({ children }) => (
<html lang="en">
<head>
<meta charset="utf-8" />
{stylesheet("/styles.css")}
<style>{`
::view-transition-old(root),
::view-transition-new(root) { animation-duration: 0.15s; }
main { view-transition-name: main; }
`}</style>
</head>
<body class="bg-gray-50 min-h-screen">
<nav class="bg-white shadow-sm border-b px-6 py-3 flex gap-6">
<a href="/" class="font-bold text-gray-900">My Site</a>
<a href="/about" class="text-gray-600 hover:text-gray-900">About</a>
<a href="/blog" class="text-gray-600 hover:text-gray-900">Blog</a>
</nav>
<main class="max-w-4xl mx-auto px-4 py-12">
{children}
</main>
<footer class="border-t px-6 py-4 text-sm text-gray-400 text-center">
Built with bext
</footer>
{clientRuntime({ navigation: true, liveReload: true })}
</body>
</html>
),
routes: {
"/": { page: () => <h1 class="text-4xl font-bold">Welcome</h1> },
"/about": { page: () => <div><h1>About</h1><p>We build things.</p></div> },
"/blog": {
page: () => (
<div>
<h1>Blog</h1>
<a href="/blog/hello">First Post</a>
</div>
),
children: {
"/[slug]": {
page: (ctx) => <article><h1>Post: {ctx.params.slug}</h1></article>,
},
},
},
},
});
createSite({ hostname: "my-site.dev", router });
Le fait de cliquer entre les pages s'anime en douceur, les URL sont mises à jour dans la barre d'adresse, la prélecture en survol rend les transitions instantanées et la modification des fichiers sources actualise automatiquement le navigateur.
En rapport#
- Rechargement en direct — détails complets sur SSE par rapport à l'interrogation, les modes de reconstruction et la sécurité de la production
- Cadre PRISM — la structure de serveur entre laquelle le runtime client navigue entre les pages
- Routage et mises en page —
defineRoutes()pour le routeur imbriqué câblé danscreateSite() - Cadre de modèle —
createSite()etSiteConfigavec lesquels le runtime fonctionne - CSS vent arrière — intégration de feuilles de style avec suppression du cache avec le chemin d'actualisation logicielle