Code-Splitting with SSR Preact

Published on Oct 4, 2020

It took me 3 days to figure out how to implement route-based code-splitting with server-side rendered Preact because of the lack of documentation, so I'm going to share with you in this article how I did it.

Preact has the same API as React with only a fraction of the size (3kb), so it's interesting to increase your app's time-to-interactive metrics while decreasing your static website generator's build time.

Traditional routing with Preact looks like this:

The single-page app is rendered, each component is downloaded, and the router displays the one corresponding to the current route.

It works well, but the more routes you have, the longer it will take to download the Javascript bundle. A better solution would be to download only the Javascript we need, which is called lazy loading, or code splitting:

Instead of loading the components, we use dynamic imports to only record the references to the components. When the app needs a component, it is downloaded asynchronously while a loading message is displayed.

That's nice, but what about server-side rendered application? Websites that can't go around search engine optimization can't afford to use a traditional single page application, so we need to make it work. This part isn't documented anywhere so it took me many trials and errors to figure it out.

You simply need to import your Router component from the server and tell it what to render, but it's a bit tricky. In ExpressJS, for example:

server.js

app.js

Basically, we tell the Router our current server-side route, and it will figure out which front-end route to render. In the front-end, we hydrate our SSR output. 

If you use the code as-is, however, nothing will be rendered server-side because of the dynamic imports. Dynamic imports are asynchronous actions, so you have to wait for the results to be sent back to use them. Unfortunately, the way NodeJS parses imports make it impossible to happen: the promises are skipped entirely and you are left with the loading components.

The trick is to use the synchronous instruction require when you're on the server-side, and only use dynamic imports in the browser. To do that, we update the getComponent property of each route:

And voilà! Routes are lazy-loaded and server-side rendered, the best of both worlds! You can also leverage the incredible speed of Preact to make your application even more performant.