DEV Community

Eka
Eka

Posted on • Updated on

[Pre-Stable Release] Getting Started with Our First Gatsby Theme

⚠️ UPDATE 7/7/2019: This post was written before themes was stable. Some API and code in this post might not be accurate now. Proceed with caution. ⚠️


🧐 To learn more about Gatsby themes, check out my first and second posts in this series.

A Gatsby theme is a reusable block of a Gatsby site that can be shared, extended, and customized (source). It enables us to separate functionalities of our site to share, reuse, and modify in multiple sites in a modular way.

In this post, we get started with theming by building a basic, bare-bones theme called gatsby-theme-hello-world. We are creating this locally, meaning the files are on our local machine and we are not going to publish the theme yet. To check if the theme is usable, we are also going to create a new blank site, add the theme, and add content from our site.

This is mostly based on the first 24 minutes of this video by John Otander and Jason Lengstorf with minor modifications.

Let's go!

the band Ramones on stage with text Hey Ho, Let's Go!

Table of Contents

  1. Create folders
  2. Create package.json in ROOT, THEME, and SITE
  3. Add devDependencies and peerDependencies to THEME
  4. Add dependencies to THEME
  5. Create index page and post in THEME
  6. Add dependencies (including the theme) to SITE
  7. Create a post in SITE
  8. Add a ghost (optional)

⚠️ Gatsby Themes are currently experimental. Theme API might change in the future. ⚠️


1. Create our folders

We are creating our project folder that contains two folders for the theme and the site respectively. Therefore, we are talking about three locations:

  • project (workspace) ROOT — I’m calling it eka-site-with-theme, feel free to use any other name
  • THEME — eka-site-with-theme/gatsby-theme-hello-world
  • SITE — eka-site-with-theme/example-site
# create and go to our project folder
mkdir eka-site-with-theme
cd eka-site-with-theme

# make our theme and site folders
mkdir gatsby-theme-hello-world example-site 

If you are comparing with this video, the project root is gatsby-themes, the theme folder is gatsby-themes/packages/gatsby-theme-livestream, and the site folder is gatsby-themes/site. You can arrange and name your folders any way you want. Just make sure to refer to the subfolders correctly in the next step!

Note: You don’t have to create the SITE part from scratch. Alternatively, you can use gatsby new command as usual , or use the theme with your existing Gatsby site. To read more about the latter, see my post below.

2. Create package.json

We are going to create package.json by running yarn init in all three of our folders. You may fill out or skip most of the defaults, but make sure you fill out the required content below.

2a) ROOT

// eka-site-with-theme/package.json
{
  "name": "eka-site-with-theme",
  "private": true,
  "workspaces": [
    "example-site",
    "gatsby-theme-hello-world",
  ]
}

As you can see, we add our site and theme folders in the workspaces array. This enables us to use themes—just the one theme, in this case—locally. Read this post about yarn workspaces if you’d like to know more.

The workspaces field accepts wildcards. If you have multiple local themes, for instance, you can put them in a folder called packages and add "packages/*" in the array instead of listing the theme folders one by one.

2b) SITE (example-site)

// eka-site-with-theme/example-site/package.json
{
  "name": "example-site",
  "version": "1.0.0",
  "private": "true"
}

This folder is not meant to be published, so we can set private to true and omit the entry point (main).

2c) THEME (gatsby-theme-hello-world)

// eka-site-with-theme/gatsby-theme-hello-world/package.json
{
  "name": "gatsby-theme-hello-world",
  "version": "1.0.0",
  "license": "MIT",
  "main": "index.js"
}

We have to provide an entry point (main) in our theme package for when Gatsby/Node attempts to resolve the package. Don’t forget to create an empty index.js in this folder; otherwise we would not be able to use this theme from our site later. Omitting license will not cause error but will throw a warning.

Now we’ve got all three package files created, go back to the root folder and run yarn workspaces info. Your command line should print something like this:

# eka-site-with-theme/gatsby-theme-hello-world
**yarn workspaces v1.15.2**
{
  "example-site": {
    "location": "example-site",
    "workspaceDependencies": [
      "gatsby-theme-hello-world"
    ],
    "mismatchedWorkspaceDependencies": []
  },
  "gatsby-theme-hello-world": {
    "location": "gatsby-theme-hello-world",
    "workspaceDependencies": [],
    "mismatchedWorkspaceDependencies": []
  }
}

In steps 3 to 5 we are going to work in the theme folder, and in steps 6 and 7 we are going to work in the site folder.

3. Install devDependencies and peerDependencies in THEME

We are installing the following packages as both devDependencies and peerDependencies:

  • gatsby
  • react
  • react-dom
# eka-site-with-theme/gatsby-theme-hello-world
yarn add gatsby react react-dom -D -P

devDependencies are dependencies you need for developing (creating) the theme, while peerDependencies are for ensuring the same copy of these dependencies is used when our theme is installed by users.

4. Add dependencies to THEME

We are adding the following dependencies:

  • gatsby-plugin-page-creator
  • gatsby-mdx, @mdx-js/mdx, @mdx-js/tag, @mdx-js/react

4a) gatsby-plugin-page-creator

By default, Gatsby creates pages from components in the src/pages folder. It’s fine for non-themed sites, but when we use a theme, we’d like our site to include the theme’s src/pages folder as well. To enable that, we use gatsby-plugin-page-creator. Run the line below to install, then create a new gatsby-config.js file and register the plugin there.

# eka-site-with-theme/gatsby-theme-hello-world
yarn add gatsby-plugin-page-creator
// eka-site-with-theme/gatsby-theme-hello-world/gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: "gatsby-plugin-page-creator",
      options: {
        path: `${__dirname}/src/pages`
      }
    }
  ]
};

4b) gatsby-mdx

MDX is a new format that enables you to use JSX in your Markdown files. We’re going to add this plugin and its dependencies so Gatsby can read MDX files. Like with the previous dependency, we install the packages, open our config file, and add gatsby-mdx into the plugins array.

# eka-site-with-theme/gatsby-theme-hello-world
yarn add gatsby-mdx @mdx-js/mdx @mdx-js/tag @mdx-js/react
// eka-site-with-theme/gatsby-theme-hello-world/gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: "gatsby-plugin-page-creator",
      options: {
        path: `${__dirname}/src/pages`
      }
    },
    `gatsby-mdx`
  ]
};

📝 Note: gatsby-mdx is just an example; feel free to substitute with other source and transformer plugins (for instance gatsby-source-filesystem and gatsby-transformer-remark) if you are familiar with them.

5. Add pages to THEME

Themes are regular Gatsby sites, so we can develop it as we normally do.

5a) Home page

First, let’s create the src/pages folder and create index.js that exports a simple component that renders a heading text. This is the standard way to create a page using React component.

# eka-site-with-theme/gatsby-theme-hello-world
# create src/pages folder
mkdir src && mkdir src/pages 

# create index.js 
touch src/pages/index.js
// eka-site-with-theme/gatsby-theme-hello-world/src/pages/index.js

import React from "react";
export default () => <h1>Theme Home Page</h1>;

5b) "hello-theme" page

Second, make a file called hello-theme.mdx in src/pages and add some text. Here, we can use the MDX format because we already installed gatsby-mdx. In real use case, you are free to choose whichever best suits your needs.

# Hello world from theme

This content is created from the `gatsby-theme-hello-world` theme.
eka-site-with-theme/gatsby-theme-hello-world/src/pages/hello-theme.mdx

Now let’s run our theme as a regular site to check whether everything works correctly.

# eka-site-with-theme/gatsby-theme-hello-world
gatsby develop

Go to http://localhost:8000 and see our index page. Then go to http://localhost:8000/hello-theme to see our "Hello world" post.

Page with title Theme Home Page Page with title Hello World from Theme

🌮 Extra: the yarn workspace way

Instead of using gatsby develop from the theme folder as usual, we can also use the yarn workspace command from the workspace root. To do that, we need to add the gatsby develop command to the theme’s package.json file.

// eka-site-with-theme/gatsby-theme-hello-world/package.json
{
  "name": "gatsby-theme-hello-world",
  // other things
  "scripts": {
    "develop": "gatsby develop"
  }
}

Now go to the workspace root folder and run this command.

# from workspace root (eka-site-with-theme)
yarn workspace gatsby-theme-hello-world develop

# is equal to this
# in theme folder (eka-site-with-theme/gatsby-theme-hello-world)
yarn develop

This also applies to any other yarn commands.

Now we’ve already got a working theme, time to create our site and use the theme from there!

6. Add dependencies (including the theme) to SITE

Go to our site folder, then install our dependencies:

  • gatsby
  • react
  • react-dom
# eka-site-with-theme/example-site
yarn add gatsby react react-dom

We are also adding our theme, gatsby-theme-hello-world, as a dependency. Since we are using a local theme, we can add it to package.json like so:

// eka-site-with-theme/example-site/package.json
{
  "name": "example-site",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "gatsby": "^2.4.2",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "gatsby-theme-hello-world": "*"
  }
}

Just like with plugin dependencies in step 4, we are also adding our theme to gatsby-config.js in a similar manner. First create the file in our site folder, and add the following:

// eka-site-with-theme/example-site/gatsby-config.js
module.exports = {
  __experimentalThemes: [`gatsby-theme-hello-world`]
};

Now try running the app. Once the app is running, you should be able to access http://localhost:8000 and http://localhost:8000/hello-theme like we did from the theme.

7. Create a post in SITE

As a user, we’d want to add our own site content. We can do so by creating a file—let’s call it hello-user.mdx—in src/pages. This step resembles step 6 above, but we are doing this from the site folder now.

# Hello world from user

This content is created from the example user site.
eka-site-with-theme/example-site/src/pages/hello-user.mdx

Now run the app again, and head to http://localhost:8000/hello-user. You can see than in addition to the home page and the “hello-theme” page, we have a new page that only exists in our site.

Page with title Hello World from User

8. Add a ghost (optional)

A theme developer can integrate any necessary components for users’ convenience, so users don’t have to install and configure the components themselves. (Also, this is really just an excuse to use the miukimiu/react-kawaii library, which I’m quite smitten with.)

Go back to the gatsby-theme-hello-world folder, run yarn add react-kawaii to intall the package.

Open the user post file hello-user.mdx and add a component from react-kawaii.

import { Ghost } from "react-kawaii";

# Hello world from user

This content is created from the example user site.

<Ghost size={160} mood="happy" color="#f0f0f0" />
eka-site-with-theme/example-site/src/pages/hello-user.mdx

Now run the example-site app again, and go to http://localhost:8000/hello-user. You should see your post with a ghost illustration underneath.

Same page as Hello World from User above, but with ghost illustration

Thus, we have successfully built a theme and used it in our new site. Yay! 🎉


📝 Notes and Thoughts

As usual, I’m sharing my (subjective!) thoughts about what I've been creating in this post. Feel free to chip in if you’ve got anything to add.

🤔 Isn’t this overengineering?

If you only need to create a “Hello World” page, YES, definitely! However, I do find the potential use cases—which you can find in the links in my first post—legitimate. I’m doing this kind of basic implementation to grok the principles before going into more complex (and more realistic) usage.

Related to step 3 — I still have not understood peerDependency for themes.

What if my existing site uses eg. gatsby version 2.0.0 but the theme uses 2.1.1 as devDependency and peerDependency? Will it force my entire site to run the theme’s copy of gatsby? Or just the part that uses the theme? What if my site uses another theme that uses eg. 2.0.0 as peerDepencency?

The setup I used in this post is used in livestream-gatsby-themes and gatsby-theme-carbon. However, other themes use different setup, such as gatsby-theme-minimal (only peerDependencies) and gatsby-theme-example-component-extending (neither dev nor peerDependencies). If anyone could explain the rationale, I would be grateful.


That’s all for now, folks.

Up next: I’m going to continue developing the theme, demonstrating Component Shadowing and playing around with gatsby-node.js to create pages programmatically.

Stay tuned and thanks for reading! 🙌🏾

Top comments (0)