How to connect BCMSΒ and Gatsby

By Branislav Vajagić
Read time 2 min
Posted on October 25, 2022
Updated on December 13, 2022
Share it on:
 BCMS  and Gatsby

Requirements

Creating a project

In this tutorial, we will use local BCMS with default data to make it easy for you to follow.

We will create a NextJS project using the BCMS CLI by running bcms --website create. After running the command, you will be prompted to decide on a few options:

  • For the project name, you can enter anything, we will leave it as default.

  • When asked to select a framework, select Gatsby.

  • When you asked if you want to connect to the BCMS, answer with y (yes). After this, you will be asked which type of BCMS you want to connect to. Since we are using local BCMS, we will select locale, but if you are using the live version, then select Live.

  • Since our Gatsby project needs an API key to be able to access the data from the BCMS, in the next step, we will need to select an API key that we would like to use. If in your BCMS you do not have any API keys, CLI will automatically create one, but if that is not the case, you will be asked to select an available API key or create a new one.

BCMS CLI steps for creating Gatsby website.
Figure 1 - BCMS CLI steps for creating Gatsby website.

After completing all the above steps, the CLI will initialize the project and install dependencies. The process is done, you can open the project in your favorite code editor (I will use VSCode) and run npm run dev. Now you can open the browser and navigate to http://localhost:3000.

Project structure

As you are able to see, this is a typical Gatsby project, but you might spot a few unusual files and folders. Let's see what those files are and what they are used for.

  • ./bcms - This is a dynamic directory created by the Most, and it is used for caching data and storing data types from the BCMS. Yes, If you are using TypeScript, GraphQL, or even JSDoc, we got you covered! We will explain this in more detail later.

  • ./gatsby-config.js - This is a typical Gatsby configuration file, and inside of it, the BCMS plugin is initialized.

  • ./gatsby-node.js - Here, we have access to the BCMS Most and can create dynamic pages.

That's all the stuff related to the BCMS everything else is the vanilla, Gatsby.

Where to deploy?

You can deploy your Gatsby application powered by the BCMS anywhere you would be able to deploy any other Gatsby application. As mentioned in the Limitations section, you will not benefit from BCMS Cache if you are deploying your app on a platform that uses serverless technology.

We tested and can recommend next platforms:

How to get data on the page?

There are 2 ways you can get data from the BCMS and display it on the page.

Using the Gatsby GraphQL, and the other is using Gatsby Node. The best way to explain this is to show you an example. Let's say that we have Blog entries in our BCMS, and we want to display one blog post on the path /blog/{blog-slug}.

With GraphQL, you can do something like this:

import { graphql } from 'gatsby';
import React, { FC } from 'react';
import type { BlogsEntry } from '../../bcms/types';
import { Layout } from '../components';

interface Props {
  data: {
    blog: {
      bcms: BlogsEntry;
    };
  };
}

const Blog: FC<Props> = (props) => {
  const blog = props.data.blog.bcms;

  return (
    <Layout>
      <pre style={{ fontFamily: 'monospace' }}>
        {JSON.stringify(blog, null, '  ')}
      </pre>
    </Layout>
  );
};

export default Blog;

export const query = graphql`
  {
    blog: bcmsBlogs(
      bcms: {
        meta: {
          en: {
            slug: { eq: "lorem-ipsum-dolor-sit-amet-consectetur-adipiscing" }
          }
        }
      }
    ) {
      bcms {
        meta {
          en {
            title
            slug
          }
        }
      }
    }
  }
`;
          

and with Gatsby Node and BCMS Most you can do something like this:

// File: ./gatsby-node.js

import * as path from 'path';
import { CreatePagesArgs } from 'gatsby';
import { getBcmsMost } from 'gatsby-source-bcms';

export const createPages = async (args: CreatePagesArgs) => {
  const {
    actions: { createPage },
  } = args;
  const most = getBcmsMost();

  const blogPageComp = path.resolve('src', 'templates', 'blog.tsx');

  const blog = await most.content.entry.findOne(
    'blogs',
    async (blog) =>
      blog.meta.en.slug === 'lorem-ipsum-dolor-sit-amet-consectetur-adipiscing',
  );
  if (blog) {
    createPage({
      component: blogPageComp,
      path: `/blog/${blog.meta.en.slug}`,
      context: {
        blog,
      },
    });
  }
};
          

BCMS Image

Usually, websites have a lot of images for blogs, banners, posts, users, and animations... To simplify handling responsive images and performance optimization, we created the BCMSImage component.

BCMSImage is a powerful component, super easy to use. BCMSImage automatically creates multiple variants of the source image, including WEBP format. Let's see how to use it and what we can do with it. We will use the Blog page from the demo dataset (which is available if you are running the BCMS locally), where we have access to the cover image. To start, let's import the BCMSImage component, add it to the render and pass it the cover_image object.

return (
  <Layout>
    {props.entry.meta.en?.cover_image && (
      <BCMSImage media={props.entry.meta.en.cover_image} />
    )}
    <pre>
      <code>{JSON.stringify(props.entry, null, '  ')}</code>
    </pre>
  </Layout>
);
          
BCMSImage with no options.
Figure 2 - BCMSImage with no options.

If you change the size of the viewport, you'll see that the image size is changing. It's not some CSS magic, but the real image source is changing. If you inspect the image, you'll see that the image source is the same size as it appears on the screen.

By default, BCMSImage creates 5 image sizes:

  • width: 350px, height: auto,

  • width: 600px, height: auto,

  • width: 900px, height: auto,

  • width: 1200px, height: auto,

  • width: 1920px, height: auto

with the aspect ratio of an image retained. So, without providing any options, BCMSImage will create 5 sizes of the source, and for each size, it will create WEBP. Just this is good enough for a lot of people.

What can we do if we know that image will appear on the website at a specific size on all devices? If that size is, for example, 200x200, we can do something like that:

return (
  <Layout>
    {props.entry.meta.en?.cover_image && (
      <BCMSImage
        media={props.entry.meta.en.cover_image}
        options={{
          sizes: {
            exec: [
              {
                width: 200,
                height: 200,
              },
            ],
          },
        }}
      />
    )}
    <pre>
      <code>{JSON.stringify(props.entry, null, '  ')}</code>
    </pre>
  </Layout>
);
          
Image with 200px width and height.
Figure 3 - Image with 200px width and height.

Okay, what if we want to display 200x200 images on a small screen and 400x200 on a larger screen? We can do this by adding a new size to the array.

return (
  <div>
    {props.entry.meta.en?.cover_image && (
      <BCMSImage
        media={props.entry.meta.en.cover_image}
        options={{
          sizes: {
            exec: [
              {
                width: 200,
                height: 200,
              },
              {
                width: 400,
                height: 200,
              },
            ],
          },
        }}
      />
    )}
    <pre>
      <code>{JSON.stringify(props.entry, null, '  ')}</code>
    </pre>
  </div>
);
          

If you resize the screen, you will be able to see that image is changing.

It is important to note that BCMSImage will calculate which image size to use depending on the width of a parent container and not the size of the viewport. This means that BCMSImage will display the size closest to a parent container's width.

One more thing that we will cover is SVG. If you have media of type SVG and you want to render it as an SVG and not as a source of an image tag, you can pass the flag svg={true} to the BCMSImage.

Loading pure SVG with BCMSImage.
Figure 4 - Loading pure SVG with BCMSImage.

Where to go next