Server-side React in non-SPA websites

Server-side rendering is an excellent feature of React. It’s frequently used for pre-rendering single page applications, improving the experience of an initial page load. Server-side rendering is also useful for non-SPA websites.

ReactDOMServer rendering methods

Server-side rendering with React is easy: React’s server-side rendering package is called ReactDOMServer, and it exposes two methods for rendering a React component. These methods are the server-side equivalents of ReactDOM.render(), however they return a string of the rendered HTML rather than mounting the component to a DOM node in a page.

ReactDOMServer.renderToString() is the method typically used for rendering a SPA server-side. This method returns HTML with hooks that allow client-side ReactDOM.render() to efficiently mount onto the available DOM without re-rendering everything.

ReactDOMServer.renderToStaticMarkup() is a less-used method that returns static HTML without any extra hooks for client-side React. This method is extremely interesting if we consider that not every website needs to be — or should be — a SPA.

Non-SPA use cases

Where would ReactDOMServer.renderToStaticMarkup() be useful?

Server-side templating

If you don’t need a React SPA client-side, rendering with React on the server is a forward-thinking approach. React is great not just for managing state within client-side applications, but also for architecting and developing reusable components across layers of abstraction.

Unlike the simplistic template partials or helpers offered by many server-side frameworks, React’s component and templating model encourages designing component hierarchies, which is sure to ease in maintenance and refactoring. Let’s face it: find and replace for semi-complex HTML structures isn’t as nice as changing one encapsulated instance.

And as a bonus, front-end developers won’t need to learn the nuances of yet another language-specific templating language.

Static site generation

For convenience, I’ve been referring to ReactDOMServer’s rendering methods as server-side rendering, but do you need an application server that’s aware of React at all? For simple sites that might otherwise use Jekyll or another static site generator, there’s a case for React as an alternative.

As an example, this site is currently built with a simple set of scripts to orchestrate React-compatible Inferno rendering of each page at build time.

const deleteRequireCache = path => delete require.cache[require.resolve(path)];
const prependDoctype = html => `<!DOCTYPE html>${html}`;
 
const renderJsxPage = file => {
  const Page = require(file.path).default;
  const result = prependDoctype(
    InfernoServer.renderToStaticMarkup(
      <Shell global={file.data.global} page={file.data.page}>
        <Page global={file.data.global} page={file.data.page} />
      </Shell>
    )
  );
  deleteRequireCache(file.path);
  return result;
};

What the build scripts do is render the pages (written as page-level components) to HTML. Each page is automatically wrapped with a common template for the site’s header and footer, and receives props with metadata parsed from frontmatter.

The result is both performant and a pleasure to work with.

Related articles

Beyond allowing the await keyword to be used within them, JavaScript’s async functions have their own useful aspects. As an alternative to Promise.resolve() and Promise.reject(), consider using async functions to cleanly wrap return values in Promises for convenient mocks in your test suite and to ensure consistent return types.

2018
JavaScript
TypeScript

How to integrate build-time or server-side syntax highlighting for markdown code fences with two libraries: markdown-it and Highlights (Atom’s syntax highlighting engine).

2017
Node.js
JavaScript
Performance

A Firefox issue where right click on a button results in a click event listener firing because of event delegation performed automatically by a JavaScript SPA framework.

2017
Firefox
JavaScript