Server-Side Rendering (SSR) with Angular/React in MEAN/MERN Stack

Server-Side Rendering (SSR) is a powerful technique to improve the performance and SEO of web applications. By rendering the initial view of a web page on the server rather than in the browser, SSR provides several benefits, including faster initial load times and better search engine indexing. In this blog, we will explore SSR with Angular and React in the context of the MEAN and MERN stacks, and cover various related topics in detail.

Understanding Server-Side Rendering (SSR)

What is Server-Side Rendering?

Server-Side Rendering (SSR) refers to the process of rendering web pages on the server instead of the client’s browser. When a request is made to the server, the server processes the request, renders the page, and sends the fully rendered HTML to the client. This approach can improve the initial load time and enhance SEO because search engines can index the rendered HTML.

What are Single-Page Applications (SPAs)?

Single-Page Applications (SPAs) are web applications that load a single HTML page and dynamically update the content as the user interacts with the app. SPAs use client-side rendering, meaning that the browser handles rendering the pages using JavaScript. This results in a seamless user experience but can have drawbacks in terms of initial load time and SEO.

What are Static-Generated Applications?

Static-generated applications (also known as Static Site Generators or SSG) generate HTML at build time. This means that HTML files are created for each route and are served directly to the client. This approach offers excellent performance and SEO benefits because the content is pre-rendered. However, it lacks the dynamic capabilities of SPAs unless combined with client-side JavaScript.

Why Move to React Server-Side Rendering?

React Server-Side Rendering offers the best of both worlds by combining the dynamic capabilities of SPAs with the performance and SEO benefits of pre-rendered HTML. By using SSR, React applications can render content on the server and send fully rendered HTML to the client. This improves the initial load time and makes the content more accessible to search engines.

Why Move to Angular Server-Side Rendering?

Angular Server-Side Rendering (SSR) with Angular Universal offers several benefits:

  • Performance: By pre-rendering the initial view on the server, the application can display content faster to the user.
  • SEO: Pre-rendered HTML improves the discoverability of content by search engines.
  • User Experience: Users see content faster, enhancing the overall experience.
  • Reduced Time to Interactive: Users can interact with the application sooner since the initial HTML is rendered on the server.

Benefits of SSR

  1. Improved Performance: SSR can reduce the time to first meaningful paint by serving the initial HTML content quickly.
  2. SEO Benefits: Search engines can easily crawl and index server-rendered content.
  3. Enhanced User Experience: Users see the content faster, leading to a better overall experience.

SSR with Angular in the MEAN Stack

The MEAN stack includes MongoDB, Express.js, Angular, and Node.js. Angular provides built-in support for SSR with Angular Universal.

Setting Up Angular Universal

  1. Install Angular Universal

    First, add Angular Universal to your existing Angular application:

    ng add @nguniversal/express-engine
  2. Update Server Module

    Angular Universal will create a server.ts file and update the angular.json file to include server-side rendering configurations. Ensure your server.ts looks like this:

    import 'zone.js/dist/zone-node'; import { ngExpressEngine } from '@nguniversal/express-engine'; import * as express from 'express'; import { join } from 'path'; import { AppServerModule } from './src/main.server'; import { APP_BASE_HREF } from '@angular/common'; import { existsSync } from 'fs'; // The Express app is exported so that it can be used by serverless Functions. export function app() { const server = express(); const distFolder = join(process.cwd(), 'dist/your-project-name/browser'); const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index'; server.engine('html', ngExpressEngine({ bootstrap: AppServerModule, })); server.set('view engine', 'html'); server.set('views', distFolder); server.get('*.*', express.static(distFolder, { maxAge: '1y' })); server.get('*', (req, res) => { res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] }); }); return server; } function run() { const port = process.env.PORT || 4000; const server = app(); server.listen(port, () => { console.log(`Node Express server listening on http://localhost:${port}`); }); } // Webpack will replace 'require' with '__webpack_require__' and will replace '.__filename' with '__webpack_filename__' // so we can safely use them in the code below. declare const __non_webpack_require__: NodeRequire; // Ensure that we are not running in a test environment, which would have NODE_ENV=test if (process.env.NODE_ENV !== 'test') { run(); }
  3. Build and Serve

    Build your application for SSR:

    npm run build:ssr npm run serve:ssr

    Your Angular application is now set up for SSR. When users request a page, they will receive pre-rendered HTML from the server.

SSR with React in the MERN Stack

The MERN stack includes MongoDB, Express.js, React, and Node.js. SSR with React involves rendering React components on the server using Node.js.

Setting Up SSR with React

  1. Install Dependencies

    Ensure you have the necessary packages:

    npm install express react react-dom @babel/preset-env @babel/preset-react babel-register ignore-styles
  2. Create Server File

    Create a server.js file to handle SSR:

    import express from 'express'; import React from 'react'; import { renderToString } from 'react-dom/server'; import { StaticRouter } from 'react-router-dom/server'; import App from './src/App'; // Path to your main App component const app = express(); app.use(express.static('public')); app.get('*', (req, res) => { const context = {}; const appHtml = renderToString( <StaticRouter location={req.url} context={context}> <App /> </StaticRouter> ); const html = ` <!DOCTYPE html> <html> <head> <title>SSR with React</title> </head> <body> <div id="root">${appHtml}</div> <script src="/bundle.js"></script> </body> </html> `; res.send(html); }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Server is listening on port ${PORT}`); });
  3. Babel Configuration

    Create a babel.config.js file:

    module.exports = { presets: ['@babel/preset-env', '@babel/preset-react'] };
  4. Run the Server

    To run the server, use Babel to transpile your code:

    node -r ignore-styles -r @babel/register server.js

Rendering with Create React App

What is Create React App?

Create React App (CRA) is a tool provided by Facebook to quickly set up a new React application with a standardized configuration. It simplifies the process of bootstrapping a new React project by handling the setup of build tools and configuration files.

Adding SSR to Create React App

Although CRA doesn't support SSR out of the box, you can integrate SSR by ejecting from CRA and customizing the build process or by using frameworks like Next.js, which provides built-in support for SSR.

Conclusion

Implementing SSR in your Angular or React applications within the MEAN or MERN stack can significantly enhance performance and SEO. While Angular Universal provides an out-of-the-box solution for SSR in Angular, setting up SSR with React requires configuring Babel and Express. By following the steps outlined in this blog, you can create fast, SEO-friendly applications that deliver a better user experience.

Additional Resources

Sample Code Repositories

Comments