Skip to content

Instantly share code, notes, and snippets.

@rauschma rauschma/README.md

Last active Jul 26, 2020
Embed
What would you like to do?

Using server-sent events

Why and how?

Important gotcha

  • The server sends a stream to the browser. Conceptually, that stream is infinite: the server never closes it, only the client, by breaking the connection.
  • If the stream is ever closed by the server (restart etc.), then the client immediately tries to reconnect.

Sketch: hot-reloading via server-sent events

  • The server watches a directory and server-sends timestamps when something changes.
  • The current timestamp is embedded in each HTML file that is served.
  • A script in each HTML file listens to the server-sent events.
    • If the embedded timestamp is different from the received data: location.reload()

Acknowledgement

Thanks for feedback:

const evtSource = new EventSource('/server-sent-events');
// 'message' is the default event (used if there is no `event:` field).
// Servers can create different events via the `event:` field.
evtSource.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
console.log(data);
});
const readables = new Set();
function startServer() {
// ···
server.get('/server-sent-events', async (request, reply) => {
reply.type('text/event-stream').code(200);
const readable = new SimpleReadable();
// Optional: send the current full status
// The server closes the readable for us – if the connection is broken
readable.addListener('close', () => {
readables.delete(readable);
});
// This is how we send incremental updates:
readables.add(readable);
return readable; // send to client
});
// ···
}
let count = 0;
function sendIncrementalUpdate(date) {
const data = {
dateString: date.toISOString(),
count,
};
// Must not contain newlines (apart from those at the end)!
const chunk = `data: ${JSON.stringify(data)}\n\n`;
for (const readable of readables) {
readable.push(chunk);
}
count++;
}
//========== Helper class
/**
* Use `.push()` to add data chunks to instances of this class.
*/
class SimpleReadable extends stream.Readable {
_read() {
// do nothing
}
closeSimpleReadable() {
this.push(null);
}
}
@mtrefzer

This comment has been minimized.

Copy link

mtrefzer commented Feb 12, 2020

Where should SimpleReadable.closeSimpleReadable() be called?
I assume inside the CloseListener.

BTW it looks really nice and awesome lean.

@rauschma

This comment has been minimized.

Copy link
Owner Author

rauschma commented Feb 15, 2020

@mtrefzer The server closes the Readables for us; we don’t have to close them ourselves in this case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.