How to Resolve Meta Data Issues in React SPA with Server-side Rendering & Firebase Cloud Functions?

Boost social network visibility & metadata accuracy in React single-page apps with server-side rendering & Firebase Cloud Functions.

Ravi Kiran Dhulipala
5 min readJul 29, 2023

Backstory

A Big Thanks to Locofy.ai, which made my work easy to convert my Portfolio Figma designs to React code.

I filled the title and description tags in the Locofy builder

Filling Title and Description tags inside the Locofy builder

It gave me code precisely for my designs by providing the dynamic meta tags which help during social share.

Code generated by Locofy.ai

I deployed the site and while sharing on Whatsapp, I could see the default metadata instead of the content as above.

But why this happens…

Apart from Locofy’s dynamic metadata code, I have also tried to use a node package called “react-helmet”.

But nothing seems to have worked out since the react-helmet package will not work for the latest React v18. Even their git repo has a lot of issues regarding the meta tags.

Now wearing a Detective hat, let's investigate why this happens…

Investigation

React is a single-page app, which means the app will have only a single HTML file and every route will be loaded into the same HTML file with the help of Javascript.

If you are familiar with React you might have seen rending the content into div with id root which was inside the body of HTML.

React sample app

So whatever we code in React will be rendered/injected only after the page load completes.

In technical terms, React components will be rendered after the dom load completes.

After a lot of investigation, I got to know that

Main culprit

Social network crawlers may not execute JavaScript when indexing your website, which means they may not pick up the dynamically generated meta tags.

In other words, For social sharing, the crawlers get the metadata from the static site which is on index.html. It doesn’t have the capability of injecting/executing javascript.

The social crawls the default values in index.html so I could see the default values while sharing. In my case shows empty since there are no values as below

index.html (edited)

Using react-helmet or using Locofy’s dynamic metadata changing won’t work since these both are under the src/app.js which runs only after the dom rendering completes.

Solution

We have to change the default metadata before the page is rendered.

There are 2 ways to do so.

  1. Using Server Side Rendering (SSR). (i.e., Rendering the pages from the server)
  2. Using next.js which has built-in capability to handle the SEO.

Locofy also supports exporting the designs into next.js. But as I stick to React I cannot change my code base

I have taken 1st approach of rendering the pages from the server side.

For this, I took the help of the Firebase cloud function and express.js and deploy the website to the Firebase hosting so that when the route is called it will trigger the express route in Firebase.

before you start make sure that you configure the Firebase project in the Firebase console and

Initialize Firebase to configure the cloud function in the root directory of the React app.

Initializing cloud function

Choose the type of language in which you want to write the cloud function (I selected Javascript)

And after you make all the necessary selections for package.json, and index.js and install all dependencies you are all set to go with the cloud function

run

npm install firebase-admin
npm install express

after we install all the required packages, we can start coding our server-side rendering code.

const functions = require('firebase-functions');
const admin = require("firebase-admin");
const express = require('express');
admin.initializeApp();

const path = require("path")
const fs = require("fs").promises;


const app = express();

//creating a function to return the html based on the route
function createHtmlData(title, desp) {
return `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="theme-color" content="#000" />
<meta name="description" content="" />
<title>${title}</title>
<meta name="description" content="${desp}" />
<script defer="defer" src="/static/js/main.js"></script>
<link href="/static/css/main.css" rel="stylesheet" />
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
`;
}

Defining the routes

app.get('/', (req, res) => {
const htmldata = createHtmlData(
"Ravikiran Dhulipala - UX Designer",
"I describe myself as a Developer by degree and a Designer by passion with a strong focus on people's needs"
);
res.send(htmldata);
})

app.get('/about-me', (req, res) => {
const htmldata = createHtmlData(
"Ravikiran Dhulipala - About me",
"Meet Ravikiran Dhulipala, a UX Engineer with over two years of experience at TCS. His passion for creating user-centered designs and expertise in UX best practices drive success for clients."
);
res.send(htmldata);
});

Exporting the function as an HTTPS callable function so that our routes will be called when the site URL hits.

exports.prerender = functions.https.onRequest(app);

After this build your React app(don’t build the functions folder) using npm run build and eliminate the random characters appended for CSS and js files under build/static/css and build/static/js folders.

Now do a deployment of both function and React app to Firebase using

firebase deploy

if you want to perform an individual deployment

For React app hosting ( here I’m not covering how to deploy your React app to Firebase)

firebase deploy --only hosting

For the Firebase cloud function

firebase deploy --only functions

The result

Before SSR

After SSR (Additionally, I have also added an Image)

You can also check the preview of all socially sharable metatags at https://www.opengraph.xyz/

Hurray you have made it to the end of the story. I hope you liked it.

Thanks for your time.

Happy Designing & Creation✏️

--

--

Ravi Kiran Dhulipala

User experience Designer inclined towards solving for people needs