A Complete Guide to Server-Side Rendering (SSR) with React.js
Welcome to this comprehensive guide on server-side rendering (SSR) with React.js. In this tutorial, we will dive deep into the concept of SSR, understand its benefits, and learn how to implement it using React.js. We will be covering this topic step by step, making sure it is easy to understand even for beginners. So, without further ado, let's get started!
What is Server-Side Rendering (SSR)?
Server-side rendering (SSR) is the process of rendering web pages on the server rather than on the client (browser). In a typical single-page application (SPA) built with React.js, the browser receives an empty HTML document, and React renders the components on the client-side. With SSR, the server generates the HTML and sends it to the browser, which displays the content immediately.
Benefits of SSR
There are several benefits to using SSR in your React application:
- Improved initial load time: With SSR, users see the content immediately, which improves the perceived performance of your application.
- Better SEO: Search engine crawlers can more easily index server-rendered pages, which improves your site's search engine optimization (SEO).
- More reliable performance: Because the server handles rendering, users with slow devices or poor network conditions will still receive a fully-rendered page.
Prerequisites
Before we begin, make sure you have the following tools and knowledge:
- Basic understanding of React.js and Node.js.
- Node.js installed on your local machine.
- A code editor (e.g., Visual Studio Code).
Setting up the Project
To get started, we'll create a new React project using the create-react-app
command-line tool. Open your terminal and run the following command:
npx create-react-app ssr-react-app cd ssr-react-app
This will create a new React project called ssr-react-app
and navigate into the project directory.
Adding Express Server
Now, we'll set up an Express server to handle server-side rendering. First, install the necessary dependencies:
npm install express
Next, create a new folder called server
at the root of your project and add a new file called index.js
. This file will contain the Express server configuration.
// server/index.js const express = require('express'); const app = express(); const PORT = process.env.PORT || 3001; app.listen(PORT, () => { console.log(`Server is listening on port ${PORT}`); });
In this code snippet, we create an Express app and start listening on port 3001.
Building React Components for SSR
Now, let's create a simple React component to render on the server. In the src
folder, create a new file called AppServer.js
. This component will be the server-rendered version of our application.
// src/AppServer.js import React from 'react'; const AppServer = () => { return ( <div> <h1>Hello from Server-Side Rendered React App!</h1> </div> ); }; export default AppServer;
In this file, we define a simple functional component that displays a heading.
Setting up Webpack for SSR
To use server-side rendering, we need to bundle our React application using Webpack. First, let's install the required dependencies:
npm install webpack webpack-cli webpack-node-externals @babel/core @babel/preset-env @babel/preset-react babel-loader --save-dev
Next, create a new file called webpack.server.js
at the root of your project. This file will contain the Webpack configuration for server-side rendering.
// webpack.server.js const path = require('path'); const nodeExternals = require('webpack-node-externals'); module.exports = { target: 'node', mode: 'development', externals: [nodeExternals()], entry: './server/index.js', output: { filename: 'server.js', path: path.resolve(__dirname, 'build'), }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: [ '@babel/preset-env', '@babel/preset-react', ], }, }, }, ], }, resolve: { extensions: ['.js', '.jsx'], }, };
In this configuration, we set the target to node
and configure the input and output paths. We also set up the Babel loader to transpile our JavaScript files, enabling support for modern syntax and React components.
Now, add a new script to your package.json
file to build the server-side bundle:
"scripts": { ... "build:server": "webpack --config webpack.server.js" }
Rendering the React Component on the Server
With the Webpack configuration in place, it's time to render the React component on the server. First, build the server-side bundle by running the following command:
npm run build:server
This command generates a server.js
file in the build
folder.
Next, update the server/index.js
file to render the AppServer
component:
// server/index.js const express = require('express'); const React = require('react'); const ReactDOMServer = require('react-dom/server'); const AppServer = require('../src/AppServer').default; const app = express(); const PORT = process.env.PORT || 3001; app.get('/', (req, res) => { const content = ReactDOMServer.renderToString(<AppServer />); const html = ` <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>React SSR</title> </head> <body> <div id="root">${content}</div> </body> </html> `; res.send(html); }); app.listen(PORT, () => { console.log(`Server is listening on port ${PORT}`); });
In this file, we import the AppServer
component, use ReactDOMServer.renderToString()
to convert it into an HTML string, and send the generated HTML to the client.
Running the Application
Now that our server is set up, we can run the application. Add a new script to your package.json
file to start the server:
"scripts": { ... "start:server": "node build/server.js" }
To start the server, run the following command:
npm run start:server
Open your browser and navigate to http://localhost:3001
. You should see the "Hello from Server-Side Rendered React App!" message.
Hydrating the Application
To improve the user experience, we can "hydrate" the server-rendered HTML with client-side React. This allows the client to take over and enable interactivity.
First, update the src/AppServer.js
file to include an interactive element, such as a button:
// src/AppServer.js import React, { useState } from 'react'; const AppServer = () => { const [count, setCount] = useState(0); return ( <div> <h1>Hello from Server-Side Rendered React App!</h1> <p>Counter: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }; export default AppServer;
In this updated component, we added a simple counter state and a button to increment the count.
Next, update the src/index.js
file to use the ReactDOM.hydrate()
method:
// src/index.js import React from 'react'; import ReactDOM from 'react-dom'; import AppServer from './AppServer'; ReactDOM.hydrate(<AppServer />, document.getElementById('root'));
Finally, update the server/index.js
file to serve the client-side bundle:
// server/index.js const path = require('path'); // ... app.use(express.static(path.resolve(__dirname, '../build'))); // ...
Add a new script to your package.json
file to build the client-side bundle:
"scripts": { ... "build:client": "npm run build" }
Now, build both the client-side and server-side bundles:
npm run build:client npm run build:server
Start the server:
npm run start:server
Navigate to http://localhost:3001
in your browser. You should see the server-rendered React app with a functional counter button.
Conclusion
In this tutorial, we explored server-side rendering (SSR) with React.js. We set up an Express server, created a simple React component, and used Webpack and Babel to bundle the application. We also implemented server-side rendering and hydration to improve the user experience.
By following this guide, you can build more sophisticated server-rendered React applications with improved performance and SEO benefits. Happy coding!
Sharing is caring
Did you like what Mehul Mohan wrote? Thank them for their work by sharing it on social media.
No comments so far
Curious about this topic? Continue your journey with these coding courses: