Skip to content

Next.js: Use Server-Side Rendering in your React App // Part 1

Baptiste Jan7 min read

Usually, we are completely running React.js on client-side: Javascript is interpreted by your browser. The initial html returned by the server contains a placeholder, e.g. <div id="root"></div>, and then, once all your scripts are loaded, the entire UI is rendered in the browser. We call it client-side rendering.

The problem is that, in the meantime, your visitor sees… nothing, a blank page!

Looking for how to get rid of this crappy blank page for a personal project, I discovered Next.js: in my opinion the current best framework for making server-side rendering and production ready React applications.

Why SSR (Server-Side Rendering)?

This is not the point of this article, but here is a quick sum-up of what server-side rendering can bring to your application:

If you want to know more about it, please read this great article: Benefits of Server-Side Over Client Side Rendering.

But let’s focus on the “how” rather than the “why” here.

What’s the plan?

For this article, I start with a basic app made with create-react-app. Your own React application is probably using similar settings.

This article is split in 3 sections matching 3 server-side-rendering strategies:

  1. How tomanually upgrade your React app to get SSR
  2. How to start with Next.js from scratch
  3. Migrate your existing React app to server-side with Next.js

I won’t go through all the steps, but I will bring your attention on the main points of interesting. I also provide a repository for each of the 3 strategies. As the article is a bit long, I’ve split it in 2 articles, this one will only deal with the first 2 sections. If your main concern is to migrate your app to Next.js, you can go directly to the second article (coming soon).

1) Look how twisted manual SSR is…

Injury due to manual server-side rendering

In this part, we will see how to implement Server-side Rendering manually on an existing React app. Let’s take the create-react-app starter code:

Checking rendering type

I just added to the code base a simple function isClientOrServer based on the availability of the Javascript object window representing the browser’s window:

const isClientOrServer = () => {
  return (typeof window !== 'undefined' && window.document) ? 'client' : 'server';
};

so that we display on the page what is rendering the application: server or client.

Test it by yourself

I am now simulating a ‘3G network’ in Chrome so that we really understand what is going on:

Client Side Rendering

Implementing Server-side Rendering

Let’s fix that crappy flickering with server-side rendering! I won’t show all the code (check the repo to see it in details) but here are the main steps.

We first need a node server using Express: yarn add express.

In our React app, Webpack only loads the src/ folder, we can thus create a new folder named server/ next to it. Inside, create a file index.js where we use express and a server renderer.

// use port 3001 because 3000 is used to serve our React app build
const PORT = 3001; const path = require('path');

// initialize the application and create the routes
const app = express();
const router = express.Router();

// root (/) should always serve our server rendered page
router.use('^/$', serverRenderer);

To render our html, we use a server renderer that is replacing the root component with the built html:

// index.html file created by create-react-app build tool
const filePath = path.resolve(__dirname, '..', '..', 'build', 'index.html');

fs.readFile(filePath, 'utf8', (err, htmlData) => {
  // render the app as a string
  const html = ReactDOMServer.renderToString(<App />);

  // inject the rendered app into our html
  return res.send(
    htmlData.replace(
      '<div id="root"></div>',
      `<div id="root">${html}</div>`
    )
  );
}

This is possible thanks to ReactDOMServer.renderToString which fully renders the HTML markup of a page to a string.

We finally need an entry point that will tell Node how to interpret our React JSX code. We achieve this with Babel.

require('babel-register')({
  ignore: [ /(node_modules)/ ],
  presets: ['es2015', 'react-app']
});

Test it by yourself

Still simulating the ‘3G network’ in Chrome, here is the result:

Server Side Rendering

Do not be mistaken, the page is rendered by server. But as soon as the javascript is fully loaded, window.document is available and the isClientOrServer() function returns client.

We proved that we can do Server-side Rendering, but what’s going on with that React logo?!

We’re missing many features

Our example is a good proof of concept but very limited. We would like to see more features like:

and performance is bad on large pages: ReactDOMServer.renderToString() is a synchronous CPU bound call and can starve out incoming requests to the server. Walmart worked on an optimization for their e-commerce website.

It is possible to make Server-side Rendering work perfectly on top of create-react-app, we won’t go through all the painful work in this article. Still, if you’re interested in it, I attached just above some great articles giving detailed explanations.

Seriously… Next.js can bring you all these features!

2) Next.js helps you building server rendered React.js Application

Next.js ease of use

What is Next.js?

Next.js is a minimalistic framework for server-rendered React applications with:

Get started in 1 minute

In this short example, we are going to see how crazy simple it is to have a server-side rendering app ready with Next.js.

First, generate your package.json with npm init and install Next.js with npm install --save next react react-dom. Then, add a script to your package.json like this:

"scripts": {
  "dev": "next",
  "build": "next build",
  "start": "next start"
}

Create a pages/ folder. Every .js file becomes a route that gets automatically processed and rendered. Add a index.js file in that pages/ folder (with the execution of our isClientOrServer function):

const Index = ({ title = 'Hello from Next.js' }) => (
  <div>
    <h1>{title}</h1>
    <p className="App-intro">
      Is my application rendered by server or client?
    </p>
    <h2><code>{isClientOrServer()}</code></h2>
  </div>
);

export default Index;

No need to import any library at the top of our index.js file, Next.js already knows that we are using React.

Now enter npm run dev into your terminal and go to http://localhost:3000: Tadaaaaa!

Next.js started in a minute

Repeat the same operation inside your pages/ folder to create a new page. The url to access it will directly match the name you give to the file.

You’re ready to go! You’re already doing SSR. Check the documentation on Next.js official repository.

Use create-next-app

You want to start a server-side rendered React app, you can now stop using create-react-app, and start using create-next-app:

npm install -g create-next-app

create-next-app my-app
cd my-app/
npm run dev

This is all you need to do to create a React app with server-side rendering thanks to Next.js.

Finally, better than a simple Hello World app, check this Hacker News clone implementing Next.js. It is fully server-rendered, queries the data over Firebase and updates in realtime as new votes come in.

Vue.js and Nuxt

You’re maybe a Vue.js developer. Just after Next.js first release, two french brothers made the same for Vue.js: Nuxt was born! Like Vue, the Nuxt documentation is very clear and you can use the same starter template vue-cli for you app:

 vue init nuxt-community/starter-template <project-name> 

What’s Next? :)

Hope you liked this article which was mainly written in order to introduce server-side rendering with Next.

If you are interested in server-side rendering for your existing React application, in the following, I am going to demonstrate how to migrate your existing create-react-app to Next.js. Coming soon…