How quickly a user sees something when your website loads is invaluable. Studies from 2006 found that most users will abandon your site if it hasn’t loaded in 3 seconds. Unsurprisingly, users haven’t become more forgiving in the last 13 years.
Unfortunately, modern web frameworks like React are pretty bad with page load speed out of the box.
But all is not lost, you don’t need to drop React to have fast page loads. There’s lots you can do to speed up your page load — this post focuses on Static Rendering, a variant of Server Side Rendering.
Static Rendering is basically Server Side Rendering done without a server. So let’s first of all explain what Server Side Rendering is.
A vanilla JavaScript application cannot render anything until the browser has downloaded the JavaScript bundle, parsed it, and started executing it.
This means that there’s a long period where the user is just looking at a blank page. Users don’t like looking at blank pages — they have places to be, memes to enjoy.
It also means that search engines will struggle to crawl your site, since they often assume that they can ignore a lot of JavaScript. Advanced web crawlers like Google’s are getting better at loading JavaScript, but generally giving web crawlers a hard time isn’t a good idea.
Server Side Rendering is where your server also executes the JavaScript application. This way, it can give your browser the JavaScript application to run (like before), but also the HTML prefilled with your application’s initial state.
This means that while your user’s browser is downloading the JavaScript, they are already looking at the app. No more looking at blank pages.
Static Rendering is basically just pretending you’re doing Server Side Rendering, but doing it all at build time. In other words, when bundling your app you run a local server, check what all the HTML is, and then put that HTML somewhere.
Compared to traditional Server Side Rendering, this has a few downsides:
but also a few upsides:
To make our lives at Thread easier, we created a tool to do this static rendering automatically for us, alongside our normal webpack build. We open-sourced it, so feel free to give it a spin: @teamthread/react-static-render-plugin.
To use it, we take our old React Router code:
ReactDOM;
and we replace it with:
import render from '@teamthread/react-static-render-plugin/render';<Router><Route ="/" = /></Router>;
and then we add a new plugin to our webpack config:
const StaticRenderPlugin = ;moduleexport =// ...module:rules: loaderRulesplugins:// ...pages:'index-signed-in':path: '/'locals: signedIn: true'index-signed-out':path: '/'locals: signedIn: false;
and we’re done! Webpack will now build us a index-signed-in.html
and
index-signed-out.html
, alongside our normal build assets.
The next challenge we have is that we want to render some components differently when static rendering. For example, we have a component that encourages you to sign up to Thread by offering you a discount.
The discount amount, however, is actually a dynamic value provided by the server. We don’t know what it is at build time.
Fortunately, our plugin sets a global STATIC_RENDER
environment variable, so
we can replace:
<li>Register to get amount off if you order within 3 days</li>
with:
<li>Register to get processenvSTATIC_RENDER ? '—' : amount off if you orderwithin 3 days</li>
Generally, we want our statically rendered app to be a watered down version of our full app. By gracefully adding more to the app when going from the statically rendered version, and the full version, we can make the whole page load feel very smooth to the user.
Ideally, the user shouldn’t realise that any transition happened at all.
To recap, we use Static Rendering at Thread. If you load thread.com with JavaScript disabled, you will still see a large portion of the site load.
We used @teamthread/react-static-render-plugin, and you can too — give it a spin!
If you have any questions, feel free to ping me on Twitter @StephenCookDev. And if you’re looking for a job, check out our jobs page and get in touch! 🙂