Adding Live Reload to a C++ Static Site Generator with WebSockets and morphdom
Live reload isn't supposed to be hard in 2025. Unless, apparently, you decided to build your static site generator in C++. Most SSGs either skip live reload entirely or give you a clunky full-page refresh. I wanted something better: the kind of smooth, state-preserving updates you get from Vite or webpack's HMR.
The Context
My initial idea was building me a new portfolio. But I didn't want to use another javascript framework that would be either slow or too much for what I simply want: A static website where I can write posts. My goal was to use raw html, css and vanilla javascript. You can read more about this in my previous post.
The Problem with Polling
After two days, I finally had what I wanted. Markdown parser was working, templates were working, static files were also working... But while I had "live reload", it wasn't actually a true live reload, as it was simply injecting a polling script into the html during development. During initial load, it generated a BUILD_VERSION which was basically timestamp. The script sent a request each 500ms to /version, which returned the build_version in server, then the script compared the build_version in the html, if they were different we would force the browser to reload the page.
But that method had several obvious trade-offs, for example, we were refreshing the page every time a page changed... Making me lose CSS and Javascript state, which was obviously a bad UX... I hated that everytime I made a new change, I would simply lose my css animations state.
Websockets to the rescue
After researching a bit (definitely not using Claude), I found there was a better method to this, that was more efficient, stable and faster... Websockets. They were the perfect fit for this, since basically they open a connection and keep it alive until the clients closes it or the server does.
But what matters here is that instead of polling /version each 500ms, which was slow and inefficient, we could just replace our whole polling script with a websocket client that receives messages from the server. Then the server's only task is to watch changes in the files, if something changed the server will send the client a message telling it files changed so it must reload. But there was still an issue...
Morphdom: Surgical DOM Updates
We were still doing full page reloads, just that they were instantly after each change. While this might have been enough for most of SSGs, I like perfection, and I hated again, losing CSS animations state, because they made my site like it was loading again. But, then I wondered... What's the point of websockets and all of this if my site is still needing make a full page reload...?
I had some solutions like fetching the page and replace the new html with the old html or sending with websockets what just changed... But honestly, those solutions were overengineering and still inefficient because they would still wouldn't detect some cases like when frontmatter changed(Meta tags in header will also change), or when templates changed, etc.
After more research again, I learned about morphdom. This library feels like magic, because instead of needing to fully reload my site, I could simply fetch the current page, which was already modified but changes wont be visible until next refresh, but I didnt want to refresh so instead, I just made a fetch and gave Morphdom the old and new HTML DOM, it will compare both and just change what was actually changed, not everything, while keeping CSS and scrolling state... You can learn more about it in its github repo if you're interested.
CSS and Javascript files
Morphdom will only handle changes in the HTML DOM, but it can't handle changes in CSS or Javascript files, that requires different methods. For CSS I made it simple, if a CSS file changed, the server will send the type "css", the client will detect it and map through every link stylesheet in the DOM then put in each a search param "t", this will make the CSS or Javascript files to be reloaded in real time.
However, while it might seem like its possible to do the same for javascript, and cant say its impossible, its important to know that javascript files cant be "hot reloaded" as once a file is loaded, it gets immediately executed, making it too complex or nearly impossible for me to do this. Even Webpack or another libraries seems to not be able to do that.
Thank you for reading this post, I hope you found it interesting!