logo

Fill The Head The Rest Will Follow

In the previous post I created a basic website, this post is about filling it up.

I started with stuffing the <head>. This is not something trivial using React, but Gatsby has a plugin for just about everything.

Adding a plugin to Gatsby is as simple as installing it and adding it to gatsby-config.js.

The code in this post continues where the code from the previous post stopped.

Helmet

npm install --save gatsby-plugin-react-helmet react-helmet
gatsby-config.js
module.exports = {
  plugins: [`gatsby-plugin-react-helmet`]
};
src/pages/index.js
import React from "react";
import { Helmet } from "react-helmet";

export default () => (
  <>
    <Helmet>
      <title>My Website</title>
      <meta name="description" content="The description of my website" />
    </Helmet>
    <div>Hello world!</div>
  </>
);

I use gatsby-plugin-react-helmet and they use react-helmet.

In index.js I added the title and some metadata of my website. Let's hope I can handle all the traffic coming from Google now that I have SEO.

GraphQL

The title and description of my website seems like data that I might need mutliple times in different places.

Gatsby uses GraphQL to reuse common data in different places.

gatsby-config.js
module.exports = {
  siteMetadata: {
    title: `My Website`,
    siteUrl: `https://my.web.site`,
    description: `The best website in the world`
  },
  plugins: [`gatsby-plugin-react-helmet`]
};

I centralized the metadata of my site in a siteMetadata object in gatsby-config.js. This makes the data accessible for static queries.

mkdir src/hooks
touch src/hooks/use-site-metadata.js
src/hooks/use-site-metadata.js
import { useStaticQuery, graphql } from "gatsby";

export const useSiteMetadata = () => {
  const {
    site: {
      siteMetadata: { title, siteUrl, description }
    }
  } = useStaticQuery(
    graphql`
      query SiteMetadata {
        site {
          siteMetadata {
            title
            siteUrl
            description
          }
        }
      }
    `
  );
  return { title, siteUrl, description };
};
src/pages/index.js
import React from "react";
import { Helmet } from "react-helmet";
import { useSiteMetadata } from "../hooks/use-site-metadata";

export default () => {
  const { title, description } = useSiteMetadata();
  return (
    <>
      <Helmet htmlAttributes={{ lang: "en" }}>
        <title>{title}</title>
        <meta name="description" content={description} />
      </Helmet>
      <h1>{title}</h1>
      <div>Hello world!</div>
    </>
  );
};

I created a custom react hook to use my site metadata in different components. It is just a little extra abstraction on top of the useStaticQuery hook provided by Gatsby.

I then used this hook to get the site metadata in index.js. The <Helmet> component fills up the html <head> component.

My html went from:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="x-ua-compatible" content="ie=edge" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
    />
  </head>
  <body>
    ...
  </body>
</html>

to

<!DOCTYPE html>
<html lang="en" data-react-helmet="lang">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="x-ua-compatible" content="ie=edge" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, shrink-to-fit=no"
    />
    <title>My Website</title>
    <meta
      name="description"
      content="The best website in the world"
      data-react-helmet="true"
    />
  </head>
  <body>
    ...
  </body>
</html>

Manifest

I expect everyone to add my blog on their phone homescreen. This means it needs to some extra stuff, PWA stuff. I don't really think it will see a lot of use but it's so easy to do with Gatsby so I'm just going ahead with it.

npm install --save gatsby-plugin-manifest
gatsby-config.js
const siteMetadata = {
  title: `My Website`,
  siteUrl: `https://my.web.site`,
  description: `The best website in the world`
};

module.exports = {
  siteMetadata,
  plugins: [
    `gatsby-plugin-react-helmet`,
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: siteMetadata.title,
        short_name: `Short`,
        start_url: `/`,
        background_color: `#ffffff`,
        theme_color: `#000000`,
        display: `standalone`,
        icon: `src/images/icon.svg`
      }
    }
  ]
};

I installed the gatsby-plugin-manifest plugin and added some configuration to gatsby-config.js.

Now my head is full of stuff!

<head>
  <meta charset="utf-8" />
  <meta http-equiv="x-ua-compatible" content="ie=edge" />
  <meta
    name="viewport"
    content="width=device-width, initial-scale=1, shrink-to-fit=no"
  />
  <meta name="note" content="environment=development" />
  <title>My Website</title>
  <link
    rel="icon"
    href="/icons/icon-48x48.png?v=25c1108dca65f3b5b5f7f91dd3c5dfbb"
  />
  <link rel="manifest" href="/manifest.webmanifest" />
  <meta name="theme-color" content="#000000" />
  <link
    rel="apple-touch-icon"
    sizes="48x48"
    href="/icons/icon-48x48.png?v=25c1108dca65f3b5b5f7f91dd3c5dfbb"
  />
  <link
    rel="apple-touch-icon"
    sizes="72x72"
    href="/icons/icon-72x72.png?v=25c1108dca65f3b5b5f7f91dd3c5dfbb"
  />
  <link
    rel="apple-touch-icon"
    sizes="96x96"
    href="/icons/icon-96x96.png?v=25c1108dca65f3b5b5f7f91dd3c5dfbb"
  />
  <link
    rel="apple-touch-icon"
    sizes="144x144"
    href="/icons/icon-144x144.png?v=25c1108dca65f3b5b5f7f91dd3c5dfbb"
  />
  <link
    rel="apple-touch-icon"
    sizes="192x192"
    href="/icons/icon-192x192.png?v=25c1108dca65f3b5b5f7f91dd3c5dfbb"
  />
  <link
    rel="apple-touch-icon"
    sizes="256x256"
    href="/icons/icon-256x256.png?v=25c1108dca65f3b5b5f7f91dd3c5dfbb"
  />
  <link
    rel="apple-touch-icon"
    sizes="384x384"
    href="/icons/icon-384x384.png?v=25c1108dca65f3b5b5f7f91dd3c5dfbb"
  />
  <link
    rel="apple-touch-icon"
    sizes="512x512"
    href="/icons/icon-512x512.png?v=25c1108dca65f3b5b5f7f91dd3c5dfbb"
  />
  <script src="/socket.io/socket.io.js"></script>
  <meta
    name="description"
    content="The best website in the world"
    data-react-helmet="true"
  />
</head>

It also shows a favicon in the browser tab. And when I add my site to my phone's homescreen it has a nice splash screen.