Getting Started with Gatsby.js and BCMS

This guide will show you how to integrate BCMS with a Gatsby project.
Let’s dive in!

To quickly set up a simple Gatsby blog with BCMS, run the following command:

npx @thebcms/cli create gatsby starter simple-blog

Follow the prompts as they appear.

This command will:

  • Set up a new BCMS project

  • Add sample content

  • Scaffold a Gatsby project locally

  • Generate an .env file and update the code with the necessary BCMS settings

Afterward, just run:

npm install
npm run develop

If you’d rather go through each step manually, here’s a detailed guide:


Open Your BCMS Project

Visit https://app.thebcms.com and make sure you have some entries in your BCMS project. This is essential for fetching and displaying data in Gatsby.js. For instance, create a template called Blog and add a media property like Cover Image.

1.png

Create a Blog Entry

Add a new blog entry titled My First Blog, include a cover image, and some content, such as lorem ipsum.

2.png

Create an API Key

Go to Administration > Settings > API Keys. Create a new API key, and keep this page open, as you'll need the API key information in the following steps. Ensure that the key has permission to access entries from the Blog template.

3.png

Create a Gatsby.js Project

Open your terminal and use the Gatsby.js CLI to create a new project:

gatsby new

Once the project is created, open it in your code editor.


Install BCMS Packages

Install the necessary BCMS-related packages by running the following command:

npm i --save @thebcms/cli @thebcms/types @thebcms/utils @thebcms/client @thebcms/components-react

Modify package.json

In your project, open package.json and adjust the scripts section to look like this:

{
   "scripts":{
      "develop":"bcms --pull types --lng ts && gatsby develop",
      "start":"bcms --pull types --lng ts && gatsby develop",
      "build":"bcms --pull types --lng ts && gatsby build",
      "serve":"bcms --pull types --lng ts && gatsby serve",
      "clean":"gatsby clean",
      "typecheck":"tsc --noEmit"
   }
}

The bcms --pull types --lng ts command will start the BCMS CLI, pull types from BCMS, and store them in /bcms/types/. These types work for both JavaScript and TypeScript.


Set Up the BCMS Configuration

In the root of your project, create a file named bcms.config.cjs. Add the following configuration:

module.exports = {
  client: {
    orgId: "YOUR_PROJECT_ORG_ID",
    instanceId: "YOUR_PROJECT_INSTANCE_ID",
    apiKey: {
      id: "API_KEY_ID",
      secret: "API_KEY_SECRET",
    },
  },
};

You can find the necessary information for this configuration on the API key page you created earlier.


Initialize BCMS Client

In the root directory, create a new file called bcms-client.ts. Inside, initialize the BCMS client:

import {
  Client
} from "@thebcms/client";
export const bcms = new Client("ORG_ID", "INSTANCE_ID", {
  id: "API_KEY_ID",
  secret: "API_KEY_SECRET",
}, {
  injectSvg: true,
}, );

Create Blog Page Templates

Create two page templates: one to list all blogs (./src/templates/blogs.tsx) and another to display individual blog data (./src/templates/blog.tsx).

Here’s the code for blog.tsx:

import React from "react";
import { BlogEntryMetaItem } from "../../bcms/types/ts";
import { EntryContentParsedItem } from "@thebcms/client/types";
import { BCMSContentManager, BCMSImage } from "@thebcms/components-react";
import { bcms } from "../../bcms-client";
export interface BlogPageTemplateProps {
  blog: {
    meta: BlogEntryMetaItem;
    content: EntryContentParsedItem[];
  };
}
export const BlogPageTemplate: React.FC<{
  pageContext: BlogPageTemplateProps;
}> = ({ pageContext: { blog } }) => {
  return (
    <div className="flex flex-col items-center">
      <div className="relative w-full h-[450px]">
        <BCMSImage
          media={blog.meta.cover_image}
          clientConfig={bcms.getConfig()}
          className="w-full h-full object-cover"
        />
        <div
          className={`absolute top-0 left-0 w-full h-full
                    bg-black bg-opacity-30 backdrop-blur-sm flex flex-col 
                    gap-2 items-center justify-center`}
        >
          <div className="text-3xl text-white font-bold">{blog.meta.title}</div>
        </div>
      </div>
      <div className="max-w-[640px] w-full mt-36">
        <BCMSContentManager items={blog.content} />
      </div>
    </div>
  );
};
export default BlogPageTemplate;

And here’s the code for blogs.tsx:

import React from "react";
import { BCMSImage } from "@thebcms/components-react";
import { BCMSMedia } from "../../bcms/types/ts";
import { bcms } from "../../bcms-client";
import { Link } from "gatsby";
export interface BlogsPageTemplateProps {
  blogs: Array<{ title: string; image: BCMSMedia; slug: string }>;
}
export const BlogsPageTemplate: React.FC<{
  pageContext: BlogsPageTemplateProps;
}> = ({ pageContext: { blogs } }) => {
  return (
    <div className="flex flex-col gap-4">
      {blogs.map((blog, blogIdx) => {
        return (
          <Link
            to={`/blog/${blog.slug}`}
            key={blogIdx}
            className="flex gap-2 items-center bg-gray-50"
          >
            <div className="w-20 h-20">
              <BCMSImage
                className="w-full h-full object-cover"
                media={blog.image}
                clientConfig={bcms.getConfig()}
                options={{
                  sizes: [
                    { width: 80, height: 80 },
                    { width: 160, height: 160 },
                  ],
                }}
              />
            </div>
          </Link>
        );
      })}
      ;
    </div>
  );
};
export default BlogsPageTemplate;

Create Pages in gatsby-node.ts

In gatsby-node.ts, create pages based on the templates you just made:

import { CreatePagesArgs } from "gatsby";
import { BlogEntry, BlogEntryMetaItem } from "./bcms/types/ts";
import path from "path";
import { bcms } from "./bcms-client";
import { BlogsPageTemplateProps } from "./src/templates/blogs";
import { BlogPageTemplateProps } from "./src/templates/blog";
import { EntryContentParsedItem } from "@thebcms/client/types";
export const createPages = async ({
  actions: { createPage },
}: CreatePagesArgs) => {
  const blogs = (await bcms.entry.getAll("blog")) as BlogEntry[];
  const blogsCtx: BlogsPageTemplateProps = {
    blogs: blogs.map((blog) => {
      const meta = blog.meta.en as BlogEntryMetaItem;
      return {
        title: meta.title,
        slug: meta.slug,
        image: meta.cover_image,
      };
    }),
  };
  createPage({
    path: "/blog",
    component: path.resolve("./src/templates/blogs.tsx"),
    context: blogsCtx,
  });
  for (const blog of blogs) {
    const meta = blog.meta.en as BlogEntryMetaItem;
    const blogCtx: BlogPageTemplateProps = {
      blog: {
        meta: meta,
        content: blog.content.en as EntryContentParsedItem[],
      },
    };
    createPage({
      path: `/blog/${meta.slug}`,
      component: path.resolve("./src/templates/blog.tsx"),
      context: blogCtx,
    });
  }
};

That's it—happy coding!