[logo] a small computer

Adding A Sitemap To Your React App

adding a sitemap to your react app

Bradley Kingsley
Published 10 months ago.
7 minute read
logo of undefined

Adding A Sitemap To Your React App

Having a sitemap is one of the most repeated pieces of advice in the SEO community. A sitemap is a structured file that has information about pages and other files on your site and the relationships between them. It's presence on makes it much easier for search engines to crawl your site.

Think of a sitemap as a blueprint to a house or a treasure map to treasure that would otherwise take a lot of random searching to find. Aside from telling Google (and other search engines) exactly where to find what, it also provides additional information such as when the page was last updated and how often it’s changed. If your site is available in multiple languages, it can also help point Google to the right direction.

The immediate problem you’re going to face is that manually updating a sitemap doesn’t scale very well. Once your site gets large, adding new routes is going to be a chore. Ironically enough, the larger your site is, the more urgent the need for a sitemap.

Installing Dependencies

If you come from the WordPress world, adding a sitemap to your blog might have been as simple as installing a plugin. With more modern technologies like React, you have to get your hands dirty.

In our case, we’ll make use of a few dependencies, but this tutorial assumes you used create-react-app to start your project. However, it should work fine in either case.

  • react-router-sitemap
  • react-router-dom
  • babel-preset-es2015
  • babel-preset-react
  • babel-register

react-router-dom provides routing functionality to our app and react-router-sitemap has several convenience methods to help us save some time.

To install them run,

npm install react-router-dom react-router-sitemap babel-register babel-preset-react babel-preset-es2015 --save

//or

yarn add react-router-dom react-router-sitemap babel-register babel-preset-react babel-preset-es2015

Creating The Project

If you already have a project up and running, feel free to skip to the final section of this tutorial. For this project, we’ll use six simple pages that look like this:

import React from 'react';
class PageOne extends React.Component {
  render() {
  return (
  <div>
  <p>Page 1</p>
  </div>
  );
  }
}
export default PageOne;
//And so on..

And our routes.js file should be structured like so:

import React from 'react';
//Switch was introduced in react router v4
import {BrowserRouter, Route, Switch} from 'react-router-dom';
import PageOne from "./pages/page-1";
import PageTwo from "./pages/page-2";
import PageThree from "./pages/page-3";
import PageFour from "./pages/page-4";
import PageFive from "./pages/page-5";
import PageSix from "./pages/page-6";
import App from "./App";
function Routes() {
  return (
  <BrowserRouter>
  <Switch> 
  <Route exact path='/' component={App}/>
  <Route exact path='/page-1' component={PageOne}/>
  <Route exact path='/page-2' component={PageTwo}/>
  <Route exact path='/page-3' component={PageThree}/>
  <Route exact path='/page-4' component={PageFour}/>
  <Route exact path='/page-5' component={PageFive}/>
  <Route exact path='/page-6' component={PageSix}/>
  </Switch>
  </BrowserRouter>
  );
}
export default Routes;

Instructions on how to use react-router-dom) is outside the scope of this project, but most of the code should be pretty self-explanatory.We create a function that contains `BrowserRouter`, a react component that allows us to use the `Route`, `Switch` and `Link` components. A quick rundown is as follows:

  • TheRoute component allows us to render a UI when the path provided matches the current URL.
  • TheSwitch component renders the first Route or Redirect that matches the provided location. This is distinctly different from using a bunch of Routes without it because it renders a route exclusively, rather than inclusively. That is, it allows you to render exact paths.`
  • The Link component provides accessible navigation to your app.

Generating the sitemap

All that’s left now is to plug in react-router-sitemap to our application and we should be good to go.

//Babel allows us to convert modern js code into backwards compatible versions
//This includes converting jsx into browser-readable code

const es2015 = require('babel-preset-es2015');
const presetReact = require('babel-preset-react');
require("babel-register")({
  presets: [es2015, presetReact]
});
//Import our routes
const router = require("./routes").default;
const Sitemap = require("react-router-sitemap").default;

function generateSitemap() {
  return (
  new Sitemap(router())
  .build("https://www.example.com")
 //Save it wherever you want
  .save("../public/sitemap.xml")
  );
}

generateSitemap();

Now, generating a sitemap should be as simple as running

node sitemap-generator.js

Which produces the following handy code:

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
  <loc>https://www.example.com/</loc>
  </url>
  <url>
  <loc>https://www.example.com/</loc>
  </url>
  <url>
  <loc>https://www.example.com/</loc>
  </url>
  <url>
  <loc>https://www.example.com/page-1</loc>
  </url>
  <url>
  <loc>https://www.example.com/page-2</loc>
  </url>
  <url>
  <loc>https://www.example.com/page-3</loc>
  </url>
  <url>
  <loc>https://www.example.com/page-4</loc>
  </url>
  <url>
  <loc>https://www.example.com/page-5</loc>
  </url>
  <url>
  <loc>https://www.example.com/page-6</loc>
  </url>
</urlset>

If your site is fairly small, that should be enough. We can make it so that you don’t have to bother with manually running that script every time by integrating it in our build environment.

Automating Sitemap creation

For that, we’ll make use of concurrently.

npm install concurrently -S
//or
yarn add concurrently

We are going to edit our package.json so that every time the project is built, a sitemap is generated and saved to the public directory. Of course, you won’t always be adding new routes with every build, but it’s such little overhead, you’ll barely notice.

{
    //...
    "scripts": {
        //...
      "generate-sitemap": "node src/sitemap-generator.js"
        "build": "concurrently \"react-scripts build\" \"npm run generate-sitemap\"",
        //...
    },
    // ...
}

You could always skip concurrently altogether and use react-scripts build & npm run generate-sitemap if you don’t want to add more dependencies to your program. However, it makes debugging considerably harder if anything fails along the way.

Adding dynamic routes

One of the pieces of functionality that react-router allows is for the addition of dynamic routes. This makes it considerably easier to reuse components.

Consider the following jsx code

//imports excluded for brevity

function Routes() {
  return (
      <BrowserRouter>
          <Switch> 
              <Route exact path='/' component={App}/>
              <Route exact path='/page-1' component={PageOne}/>
              <Route exact path='/page-2' component={PageTwo}/>
              <Route exact path='/page-3' component={PageThree}/>
              <Route exact path='/page-4' component={PageFour}/>
              <Route exact path='/page-5' component={PageFive}/>    
              <Route exact path='/page-6' component={PageSix}/>
              <Route path={/user/:id’} component={User}/>  
          </Switch>
      </BrowserRouter>
  );
}
export default Routes;

It’s exactly the same as last time with the exception of one additional route:

 <Route path={'/user/:id'} component={User}/>

This allows two hypothetical users: “Brandon” and “Braxter” to both have the same UI presented to them with the exception of details like their name, avatar and so on. This is all based on the ‘:id’ param.

It’s a bit tricker to do but is still entirely feasible.

A few ways to do this include:

  • Crawling your site once all the necessary routes are generated and automating uploading of the xml file to your server. There are several services online that can do this for you, but hardly any are free.
  • We could also provide react-router-sitemap with a list of urls to append to the “:id” parameter so that it completes the routes on its own.

In this case, we’re going to cover the second method.

It’s worth noting that properly structuring files is one of the good development practices you should pick up along the way. This might be useful for a blog that converts all markdown files stored in a certain directory into HTML the same way Gatsby does.

For example, this example, we'll just have a list of names stored in a user_ids.json file, which looks like this:

{
 "user_ids": [
 "baxter",
 "cena",
 "liam",
 "jason"
 ]
}

Of course, if you have a list of users stored in the database and want Google to index all of them, retrieving them via an API will achieve the same effect.

The user.js file is just as simplistic:

class User extends React.Component {
 render() {
     return (
     <div>
 {
         userIds.user_ids.find(element=>             element.toLowerCase()===this.props.match.params.id.toLowerCase()) ?
         <div>
             Welcome, {this.props.match.params.id}!
         </div> :
         <div>
             Could not find a user with id: {this.props.match.params.id}
         </div>
     }
         </div>
         );
     }
}
export default User;

All it does is look for a match from our array of users using theArray.find function. If it finds a match, it renders Welcome #id. If not, the error message is rendered instead.

To plug this into react-router-sitemap, we use the applyParams method as follows:

//...
function generateSitemap() {
    const pathsConfig = {
        '/user/:id': [
            {
                id: userIds.user_ids
            }
        ]
    };
    return (
        new Sitemap(router())
            .applyParams(pathsConfig)
            .build("https://www.example.com")
            .save("./public/sitemap.xml")
    );
}
//...

Copyright © 2020 The Kenyan Dev