What if I told you I could build a frontend in React then compile & deploy it, without a server, as HTML without any trace of javascript?

It's remarkably easy to do for any static, non-interactive page. Here's how!
SSR & react-snap 👏
Server-side rendering (SSR) is not a new concept. Websites, especially high-traffic ones, have been doing this for years to optimize for pageload performance. This was always in the forefront when I was at GMG/The Onion, as a fast reading experience was paramount.
SSR in React-land usually this refers to doing something like this (taken from the react-snap readme):
import { hydrate, render } from "react-dom";
const rootElement = document.getElementById("root");
if (rootElement.hasChildNodes()) {
hydrate(<App />, rootElement);
} else {
render(<App />, rootElement);
}
The server performs the initial render
then the client detects it and can just hydrate
. But sometimes I don't want to hydrate
, and instead prefer to completely abandon the code that got me there.
Luckily, there's a "zero-configuration framework-agnostic static prerendering" tool supports just that! react-snap uses puppeteer (headless Chrome) to virtually render the page, then does some additional optimizations.
Simply adding the package to any project with a build script (not just React, despite the name) and adding it as a postbuild
script will enable it:
"scripts": {
"postbuild": "react-snap"
}
And this gets us half of the way. To get this to be asset-less we'll also need a few other flags:
"reactSnap": {
"inlineCss": true,
"removeBlobs": true,
"removeScriptTags": true,
"removeStyleTags": true
}
Note:
inlineCss
is still an experimental feature and doesn't currently work because of a service worker issue. There's a patched version that includes a fix.
Now after running build
, react-snap and minimalcss will turn the virtual DOM into actual DOM, strip out all the assets, and return plain old HTML!
Why this is cool 🔮
- It provides the benefits of SSR without a real server.
- The client can just parse the HTML markup and be done with it. No script time, asset loading, etc.
- Styles are inlined, so no need to worry about hosting a stylesheet.
- Or correctly linking to it.
- Use any CSS-in-JS library you'd like; it won't be loaded on the client.
- All the heavy lifting happens once.
- Caching with traditional SSR can do this too, but then you have to worry about cache invalidation when making changes.
- It also gives your app SEO for free.
- Web crawlers don't care about your beautiful React bundle, just the HTML markup they can see.

Not for every use case
Obviously this approach falls apart when you need any interactivity on the page. But this shines when you're rendering a static, read-only page (like a blog article) and don't need any other bloat.
Stay tuned for another post where I'll share a project that applies this with CI!
Top comments (1)
Can you talk a bit more about the exception cases? I am using this package, but as soon as I run npm run build, it crawls the pages, but then gives an error. I am not sure if this is the reason.