Perform a React disappearing act with react-snap ✨🧙💨
Tags: javascript, react, webdev
Published: 2020-01-23 16:52:34

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?

![disappear](https://media.giphy.com/media/kbu4VYj9mM5ctgYLIN/giphy.gif)

<center><i>Bwa-ha-ha-ha!</i></center>

It's remarkably easy to do for any static, non-interactive page. Here's how!

## SSR & [react-snap](https://github.com/stereobooster/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](https://github.com/stereobooster/react-snap#basic-usage-with-create-react-app)):

```jsx
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:

```json
"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](https://github.com/stereobooster/react-snap#%EF%B8%8F-customization):

```json
"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](https://github.com/peterbe/minimalcss/issues/223). There's a [patched version](https://github.com/stereobooster/react-snap/pull/357) 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.

![goodboye](https://i.giphy.com/media/14wXMGbHjXK2k0/giphy.gif)

<center><i>There is no dog, there is just snoot.</i></center>

## 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!