Server-Sent Events (SSE)
Server Sent Events (SSE) allow for the server to send realtime data to the browser. In Sircl, SSE can be used to update the UI realtime by having the server send chuncks of a web page.
Introduction
Server-Sent Events (SSE) is a technology that allows servers to push real-time updates to a client over a single, long-lived HTTP connection making it ideal for streaming updates like notifications, live scores, or real-time dashboards. It's lightweight, easy to implement, and supported natively in modern browsers via the EventSource API.
The Server-sent events functionality of Sircl offers the capability to update the page content based in a server-sent event.
Because Sircl sends the page updates to it's page rendering pipeline, different integrations can be triggered by SSE. For instance, updating the content within a Dialog or a Bootstrap modal or offcanvas will trigger the dialog/modal/offcanvas to show up.
Setup
The Server-sent events functionality of Sircl is provided by the serversentevents extension that requires the addition of a reference to the sircl-serversentevents.js or sircl-serversentevents.min.js file. You can install the file locally and reference it (as in the following sample), or you can reference the jsDeliver CDN version:
<script src="/lib/sircl/sircl-serversentevents.min.js"></script>
For more about installation options of Sircl and Sircl extensions, see the Get Started section.
Setting up a connection
To create an SSE connection, define the sse-url
attribute on an element. The attribute's value is the URL of the SSE endpoint on the server. I.e:
<div sse-url="/sse-endpoint?tag=D24">
...
</div>
Establishing a connection is an essential step in the SSE setup, but incoming events will not be handled unless you also define event listeners or a content dispatcher.
Listen for page updates
To listen and act upon incoming SSE events, and have page content updated, one option is to define an event listener using the Sircl sse-event
attribute. The attribute can be used on or inside the element having the sse-url
attribute (but not outside) and it's value is the names of the events to listen to (multiple event names can be separated by spaces). For instance:
<div sse-url="/clockendpoint" sse-event="clock">
</div>
This element sets up a SSE connection and listens for "clock" events. When such an event is received, the content of the DIV
element will be replaced by the data of the event.
The following code is an example Node.js server-side implementation sending "clock" events every second:
const http = require('http');
const server = http.createServer((req, res) => {
if (req.url === '/clockendpoint') {
// Set headers for SSE:
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
});
// Send an initial event:
res.write(`data: Welcome\n\n`);
// Update clock every second:
const interval = setInterval(() => {
const time = new Date().toTimeString();
res.write(`event: clock\n`);
res.write(`data: ${time}\n\n`);
}, 1000);
// Cleanup when the connection is closed:
req.on('close', () => {
clearInterval(interval);
});
} else {
// Handle other routes:
res.writeHead(404);
res.end('Not found');
}
});
server.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
In this example, the server returns a simple time string. In more elaborated cases, the server can return whole HTML page parts.
To handle multiple events of a same endpoint in a different way, define separate sse-event
attributes (on separate elements) as in this example:
<body sse-url="/sse-endpoint?subscription=22125">
<header>
<span class="badge" sse-event="weather-update"></span>
</header>
<main sse-event="notification" target-method="append">
<h1>Your notifications:</h1>
</main>
</body>
The target-method
attribute - defined in the Partial Loading chapter - applied on the MAIN
element, instructs SSE to append new "notification" event datas resulting in a growing page where each notification is appended to the existing content.
Dispatching content
Another approach to allow Server-Sent Events to update the page content, supported by Sircl, is the dispatch method.
Again, a connection is established with the sse-url
attribute, but this time the element holding that attribute also holds a sse-dispatch
attribute. Both attributes must be on the same element!
<div sse-url="/events" sse-dispatch>
</div>
The sse-dispatch
attribute takes no value. It is a marker to indicate the SSE connection on this element can be used to dispatch content accross the page.
The server can then send "content" events with a JSON serialized object as data providing the following properties:
Property | Description |
---|---|
target | A CSS selector expression indicating the element to receive the content. Relative CSS selectors can be used and are evaluated relative to the element holding the sse-dispatch attribute. |
content | The HTML content to render in the target. |
targetMethod | (Optional) method to use to render the target ("content", "prepend", "append" or "replace") as described in the Partial Loading chapter. |
The following code could be Node.js code sending a "content" event:
const evnt = {
target: "#newmailbadge",
content: "<span>You've got mail!</span>"
};
res.write(`event: content\n`);
res.write(`data: ${JSON.stringify(evnt)}\n\n`);
This event will replace the content of the element matching the "#newmailbadge" selector (that is the element with id = newmailbadge) with the given HTML content.
While more complex because of the use of JSON, this method offers the server the capability to update any part of the web page in real-time.
Configuration
Event id validation
By default the Sircl SSE integration does not check the "id" of the events which may result in a same event being rendered multiple times.
To avoid this, use the sse-distinct
attribute. Either on the element holding the sse-url
attribute, or any parent of it.
The sse-distinct attribute can take one of these 2 values:
- "last" : if the id of the new event is identical to the id of the last received event, then the new event is ignored.
- "sequential" : if the id of the new event is identical or "smaller" than the id of the last received event, then the new event is ignored. Note that the id of an event is considered a string value, even if it is made up entirely of digits, a string comparizon will be used.
For instance:
<div sse-url="/sse-endpoint?tag=D24" sse-distinct="sequential">
...
</div>
CORS credentials
If the element holding the sse-url
attribute, or any parent of it, holds a sse-withcredentials
attribute, then the EventSource object will be instantiated with cross-origin (CORS) credentials set.
The sse-withcredentials
attribute is a marker attribute, it takes no value.
For instance:
<div sse-url="/sse-endpoint?tag=D24" sse-withcredentials>
...
</div>