ft-interactive / starter-kit

A template for IG pages
64 stars 15 forks source link

Pre-render (SSR) story HTML using Vike #321

Closed pandringa closed 9 months ago

pandringa commented 9 months ago

This PR adapts the starter-kit to server-side render (SSR) its pages, compiling the React code into raw HTML using a tool called vike. While react-snap used to perform this functionality in the old starter-kit, we've currently been without SSR support since switching away from webpack.

Since starter-kit stories are static, we technically use server-side generation (SSG) - a variant of SSR that pre-renders a React app into static HTML at build time, rather than live in a server each time page is requested. The main benefits of doing so are for page load and hydration times: rather than need to download, parse, and run all the javascript to display the page, browsers will display the initial HTML then hydrate the page to make it interactive once the JS is parsed.

The main change here involves creating two new files (index.server.js and index.client.js), to replace what was previously index.js - the main entrypoint to run the React app in app/app.jsx. The rest of the starter-kit should mostly work the same, although users must to be sure to avoid using browser-only objects (e.g. window, document) or writing components that render different elements on the browser and the server (which leads to hydration errors when the client tries to reconcile the component tree with the prerendered HTML). By grouping client logic and conditional behavior into useEffects, users will be sure that components will render correctly on both the client and the server.

I did have to make a few changes to the config behavior — rather than writing configuration settings to config.json, it loads it in the server handler (index.server.js) and passes it as a prop into <App />.

I also created a new data-loading pattern, with a new file (config/data.js) where we can encourage template users to add their data-fetching or loading logic. By default, this method will be called on every build - although it is written so that users can instead run npm run data, which caches the results in config/data.json. This pattern is particularly useful for storing data so that changes are easily observable and revertible, since it's checked into git; in many cases it is useful if reading story text from ArchieML in a Google Doc.