Zum Hauptinhalt springen
•
IT NachrichtenSean Parker is rebuilding Stability AI around music(02.10.2026 um 23:09 Uhr)
•
IT NachrichtenMeta open sources code to let you make Muse AI gadgets(02.10.2026 um 23:08 Uhr)
•••
IT NachrichtenTelekom und 1&1: Preise für Internettarife steigen(02.10.2026 um 20:45 Uhr)
••••••
IT NachrichtenSean Parker is rebuilding Stability AI around music(02.10.2026 um 23:09 Uhr)
•
IT NachrichtenMeta open sources code to let you make Muse AI gadgets(02.10.2026 um 23:08 Uhr)
•••
IT NachrichtenTelekom und 1&1: Preise für Internettarife steigen(02.10.2026 um 20:45 Uhr)
•••••
Intelligence View
⚡ tsecurity.de Intelligence

Live reload HTML with Bun

TL;DR This articles shows how I made bun-html-live-reload. The code will refresh the browser everytime the server is hot-reloaded, by sending Server Sent…

Beitrag
0
Seite
0
↗ Quelle (dev.to)
Social ReaktionenReagiere als Erste:r — dein Feedback zählt!




TL;DR



This articles shows how I made bun-html-live-reload.

The code will refresh the browser everytime the server is hot-reloaded, by sending Server Sent Events (SSE).





Introduction



Building server-rendered website using Bun's builtin HTTP server is pretty easy.




// server.ts
Bun.serve({
fetch: (req) => {
const path = new URL(req.url).pathname;
if (path === "/") {
return new Response("<h1>Hello, World!</h1>", {
headers: { "Content-Type": "text/html" },
});
}
return new Response("Not Found", { status: 404 });
},
});






You can run this code with hot reload enabled by using bun --hot command. And now everytime you change the html content, Bun will automatically reload the server.



Problem with this approach is that, while the server is reloaded, the browser is not.

So you don't see the changes in the browser, and you have to manually refresh the page yourself.



Instead, we want to live reload our HTML like this.



In this article, we will build a simple live reload mechanism for HTML content,

so everytime you change the server.ts file, or any other files that imported by it,

the browser will automatically refresh the page, and you will see the changes immediately.



The end result will look like this from user's perspective:




// server.ts
import { withHtmlLiveReload } from "bun-html-live-reload";

Bun.serve({
fetch: withHtmlLiveReload(async (req) => {
const path = new URL(req.url).pathname;
if (path === "/") {
return new Response("<h1>Hello, World!</h1>", {
headers: { "Content-Type": "text/html" },
});
}
return new Response("Not Found", { status: 404 });
}),
});









The idea (Server Sent Events)



The idea is very simple. Everytime the server is reloaded, we will tell the browser to refresh the page.

We can either use WebSockets or Server Sent Events (SSE) to achieve this.



In this article we will use SSE for these reasons:




  • The message is one way (server to browser), not bidirectional.

  • No need to upgrade the connection like WebSocket.



Sending SSE message is pretty simple.

We will need to:




  • Prepare endpoint to send the message.

  • Inject SSE listener script to every HTML response.





Understanding Bun's hot reload



Before sending the reload message, we need to understand how Bun's hot reload works.

Let's run following code with bun --hot server.ts:




// server.ts
let message = "hello";
console.log(message);






As expected, the server will print hello to the console.



Without toucing the terminal, if we edit the message and save the file.




// server.ts
let message = "hello world";
console.log(message);






The server will print hello world to the console.



So basically everytime we change the file, Bun will re-run all the top level code in the file.



In the next section, we will need to persist a variable between reloads.

To do that, we can use globalThis.




globalThis.counter = globalThis.counter ?? 0;
globalThis.counter += 1;

console.log("Counter: ", counter);






Everytime we change our code, the counter will be increased by 1.



For type safetiness in typescript, we can define the type of the variable in a global scope.




declare global {
var counter: number | undefined;
}

globalThis.counter = globalThis.counter ?? 0;
globalThis.counter += 1;

console.log("Counter: ", counter);









Listening to SSE event



To make browser listen to SSE event, we will use EventSource API.

The /__bun_live_reload endpoint will be used as the source of the event.

Then we will use location.reload() to refresh the browser everytime the event is received.




new EventSource("/__bun_live_reload").onmessage = () => {
location.reload();
};






We will inject this script to every HTML response on the later section.




// TODO: Inject this script to every HTML response
const liveReloadScript = `
<script>
new EventSource("/__bun_live_reload").onmessage = () => {
location.reload();
};
</script>
`
;









Injecting the script



To inject the script to every HTML response, we will create a wrapper for fetch function.




// bun-html-live-reload.ts
type Fetch = (req: Request) => Promise<Response>;
export function withHtmlLiveReload(handler: Fetch): Fetch {
return async (req) => {
const response = await handler(req);

// TODO: Inject the script to every HTML response

return response;
};
}






We will detect weather the response is HTML or not by checking the Content-Type header.




export function withHtmlLiveReload(handler: Fetch): Fetch {
return async (req) => {
const response = await handler(req);

if (response.headers.get("Content-Type")?.startsWith("text/html")) {
// TODO: Inject the script
}

return response;
};
}






For simplicity of this tutorial, we will simply append the client's live reload script to the end of the HTML content.




export function withHtmlLiveReload(handler: Fetch): Fetch {
return async (req) => {
const response = await handler(req);

if (response.headers.get("Content-Type")?.startsWith("text/html")) {
const htmlText = await response.text();
const newHtmlText = htmlText + liveReloadScript;
return new Response(newHtmlText, { headers: response.headers });
}

return response;
};
}









Sending the SSE message



To send the SSE message, we will need to create a new endpoint /__bun_live_reload, and return ReadableStream object as the response.



Don't forget to add text/event-stream as the Content-Type header.




export function withHtmlLiveReload(handler: Fetch): Fetch {
return async (req) => {
const response = await handler(req);

if (new URL(req.url).pathname === "/__bun_live_reload") {
const stream = new ReadableStream({
start(client) {},
});
return new Response(stream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
},
});
}

// ...
return response;
};
}






Then we can save the client object as a global variable.



After that, on the next reload, we can send the message to the client by calling enqueue on the top level.




// withHtmlLiveReload
const stream = new ReadableStream({
start(client) {
globalThis.client = client;
},
});
// withHtmlLiveReload

// This will send the message to the client
globalThis.client?.enqueue("data:\n\n");






The message string data:\n\n is the minimum message that required to trigger the event. You can add more data here if you want to send it to the client.



Also you might want to add type definition for this




declare global {
var client: ReadableStreamDefaultController | undefined;
}









Putting it all together



Here is the full code of bun-html-live-reload.ts:




// bun-html-live-reload.ts
declare global {
var client: ReadableStreamDefaultController | undefined;
}

type Fetch = (req: Request) => Promise<Response>;

globalThis.client?.enqueue("data:\n\n");

const liveReloadScript = `
<script>
new EventSource("/__bun_live_reload").onmessage = () => {
location.reload();
};
</script>
`
;

export function withHtmlLiveReload(handler: Fetch): Fetch {
return async (req) => {
const response = await handler(req);

if (new URL(req.url).pathname === "/__bun_live_reload") {
const stream = new ReadableStream({
start(client) {
globalThis.client = client;
},
});
return new Response(stream, {
headers: {
"Content-Type": "text/event-stream",
"Cache-Control": "no-cache",
},
});
}

if (response.headers.get("Content-Type")?.startsWith("text/html")) {
const htmlText = await response.text();
const newHtmlText = htmlText + liveReloadScript;
return new Response(newHtmlText, { headers: response.headers });
}

return response;
};
}


Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Live reload HTML with Bun

Thematisch verwandte Begriffe: Live, reload, HTML, with · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

💬 Kommentare werden geladen…
Zum Aktualisieren ziehen
tsecurity.de Icon
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag