ENbext.dev
DocumentationInclusions côté serveur

Traduction automatique depuis l’anglais. Consulter l’original.

Sur cette page

Le temps réel inclut

Une inclusion peut s'abonner à une chaîne en temps réel. Au premier chargement, il s'affiche côté serveur comme n'importe quelle autre inclusion ; après cela, un abonnement SSE côté client récupère le fragment chaque fois que le serveur publie sur le canal.

html
<bext-include src="/partials/order-status"
  realtime="orders:123"
></bext-include>

Pas de cadre, pas de gestion étatique. Juste un <div> qui se met à jour lorsque le serveur le demande.

Attributs#

Attribut But
realtime Nom de la chaîne/du sujet auquel s'abonner
realtime-mode replace (par défaut), append, prepend
realtime-event Filtrer sur un type d'événement spécifique

Comment ça marche#

Sur SSR : L'inclusion se résout normalement – HTML complet côté serveur. bext encapsule le résultat dans un conteneur avec des métadonnées en temps réel :

html
<div data-bext-realtime="orders:123"
     data-bext-include-src="/partials/order-status"
     data-bext-realtime-mode="replace">
  <p>Order #123: Preparing</p>
</div>

Sur le client : bext injecte un petit script en ligne (une fois par page) qui découvre tous les éléments [data-bext-realtime] et s'abonne à leurs chaînes via EventSource :

javascript
// Injected automatically when any realtime include is present
var es = new EventSource('/__bext/realtime/sse?topic=orders:123');
es.onmessage = function(ev) {
  // Re-fetch the include HTML
  fetch('/__bext/include?src=/partials/order-status')
    .then(r => r.text())
    .then(html => {
      el.innerHTML = html;  // or append/prepend based on mode
    });
};

Lors de la publication : Tout code côté serveur qui met à jour les données sous-jacentes est publié sur le canal :

rust
realtime_hub.publish("orders:123", json!({
    "event": "order-update",
    "status": "shipped"
}));

Tous les clients abonnés récupèrent automatiquement l'inclusion.

Modes de mise à jour#

Contrôlez la manière dont les mises à jour s'appliquent au DOM :

html
<!-- Replace: new content replaces current (default) -->
<bext-include src="/partials/status"
  realtime="orders:123"
  realtime-mode="replace"
></bext-include>

<!-- Append: new content added to the end (live feeds) -->
<bext-include src="/partials/latest-message"
  realtime="chat:42"
  realtime-mode="append"
></bext-include>

<!-- Prepend: new content added to the start (notifications) -->
<bext-include src="/partials/notification"
  realtime="user:42:notifs"
  realtime-mode="prepend"
></bext-include>

Filtrage des événements#

Un canal peut diffuser plusieurs types d'événements. Utilisez realtime-event pour vous abonner à un seul :

html
<!-- Only re-render when the server publishes event="price-change" -->
<bext-include src="/partials/price-tag"
  realtime="stock:AAPL"
  realtime-event="price-change"
></bext-include>

<!-- Only re-render when event="volume-update" -->
<bext-include src="/partials/volume-meter"
  realtime="stock:AAPL"
  realtime-event="volume-update"
></bext-include>

Tous deux sont abonnés à stock:AAPL mais react à différents événements. Le serveur publie :

rust
realtime_hub.publish("stock:AAPL", json!({
    "event": "price-change",
    "price": 171.25
}));

Seul le price-tag inclut les nouvelles récupérations. Le volume-meter ignore cet événement.

Conseil

Plusieurs inclusions partagent le même canal sur une page ouverte , une connexion EventSource, pas une par inclusion. Lorsqu'une publication se déclenche, toutes sont récupérées via le point de terminaison /__bext/include/batch en un seul aller-retour.

Autorisation de chaîne#

Le hub en temps réel applique des règles d'authentification par canal (même système que les autres abonnements en temps réel) :

toml
[realtime.auth]
# User-specific channels require authentication
"user:*" = { auth = "required" }

# Admin-only channels
"admin:*" = { auth = "required", role = "admin" }

# Public channels — no auth needed
"public:*" = { auth = "none" }

Les abonnés non autorisés reçoivent 403 Forbidden du point de terminaison SSE. Le SSR de l'inclusion se produit toujours (sous réserve du propre attribut auth de l'inclusion) — seul l'abonnement en direct est bloqué.

Attention

Le canal en temps réel autorise l'abonnement en direct séparément du propre attribut auth de l'inclusion. Une chaîne publique ( auth = "none" ) peut toujours être utilisée avec une inclusion auth="required" – mais l'abonnement lui-même sera ouvert à tous.

Couplage avec la mise en cache#

Le SSR initial d'une inclusion en temps réel peut toujours être mis en cache avec une courte durée de vie pour absorber les rafales de requêtes :

html
<bext-include src="/partials/live-scores"
  realtime="scores:match-42"
  ttl="5s"
></bext-include>
  • La première requête est résolue et mise en cache pendant 5 secondes.
  • Les chargements initiaux ultérieurs de la page (au cours de la fenêtre de 5 secondes) ont atteint le cache.
  • L'abonnement côté client conserve le contenu à jour après le chargement.

N'utilisez pas de longues durées de vie : le cache est un filet de sécurité, pas la source de vérité. La chaîne en temps réel est ce qui maintient le contenu à jour.

Gestion des connexions#

Plusieurs inclusions sur la même page partageant la même chaîne partagent une seule connexion :

html
<bext-include src="/partials/order-header" realtime="orders:123"></bext-include>
<bext-include src="/partials/order-timeline" realtime="orders:123"></bext-include>
<bext-include src="/partials/order-total" realtime="orders:123"></bext-include>

Un EventSource est ouvert pour orders:123 ; les trois incluent l’écoute et la récupération lorsqu’un événement arrive. Le point de terminaison par lots /__bext/include/batch résout les trois en une seule requête :

code
POST /__bext/include/batch
[
  { "src": "/partials/order-header" },
  { "src": "/partials/order-timeline" },
  { "src": "/partials/order-total" }
]

Renvoie un tableau de chaînes HTML résolues, chacune échangée dans son élément respectif.

Reconnexion côté client#

Le script injecté gère la reconnexion automatique :

  • Lors de la déconnexion, il attend 1 à 5 secondes (intervalle exponentiel) et se reconnecte.
  • Côté serveur, le hub temps réel de bext reprend l'abonnement en toute transparence.
  • Les événements en cours qui se sont produits lors de la déconnexion sont relus si le client envoie un en-tête Last-Event-ID (comportement SSE standard).

Performance#

  • Un EventSource par canal unique par page (pas par inclusion).
  • La récupération utilise /__bext/include?src=... qui respecte le cache de l'inclusion.
  • Les publications côté serveur sont diffusées via la pub/sub interne du hub en temps réel.
  • Avec le backend Redis, les publications se propagent sur des instances à l'échelle horizontale.

Exemple : tableau de bord en direct#

html
<body>
<h1>Dashboard</h1>

<section>
  <h2>Active orders</h2>
  <bext-include src="/partials/active-order-count"
    realtime="system:orders"
    ttl="10s"
  ></bext-include>
</section>

<section>
  <h2>Recent events</h2>
  <bext-include src="/partials/event-feed"
    realtime="system:events"
    realtime-mode="prepend"
  >Loading events...</bext-include>
</section>

<section>
  <h2>Server health</h2>
  <bext-include src="/partials/health-metrics"
    realtime="system:health"
    realtime-event="alert"
    ttl="30s"
  ></bext-include>
</section>
</body>

Trois canaux différents, trois modes de mise à jour différents, tous auto-mis à jour. Pas de framework de tableau de bord, pas de code de gestion WebSocket.

Voir aussi#

Modifier cette page ↗Besoin d’aide ? ↗
Rechercher dans la documentation

Saisissez un sujet, une commande ou une question.