[Pre-Stable Release] Using Gatsby Themes in a Non-Theme Starter
Tags: gatsby, beginners, webdev
Published: 2019-05-04 22:03:25

---
title: [Pre-Stable Release] Using Gatsby Themes in a Non-Theme Starter
published: true
description: My experiment using the blog-mdx Gatsby theme in a basic hello-world starter
tags: gatsby, gatsbyjs, beginner, webdev
series: Learning Gatsby Themes
---

> ⚠️ **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. ⚠️

---

> _With the introduction of theming in Gatsby, it’s easier than ever to get started building a Gatsby site. Shared functionality, data sourcing, and design can all be prepackaged as a Gatsby Theme that’s an NPM install away._ — [Gatsby Themes Introduction](https://www.gatsbyjs.org/docs/themes/introduction/)

A Gatsby **theme** is a _reusable block of a Gatsby site_ that can be _shared, extended, and customized_ ([source](https://youtu.be/SV2zu9FvUTw?t=406)). It was [introduced 6 months ago](https://www.gatsbyjs.org/blog/2018-11-11-introducing-gatsby-themes/) and is still in experimental phase. As such, among hundreds of currently existing [“starters”](https://www.gatsbyjs.org/starters/?v=2) (boilerplate sites), very few are specifically built to use with themes.

In this post, we are going to use the [gatsby-theme-blog-mdx](https://github.com/gatsbyjs/gatsby/tree/master/themes/gatsby-theme-blog-mdx) theme in a blank site created with the long-standing [hello-world](https://github.com/gatsbyjs/gatsby-starter-hello-world) starter. This is the most basic Gatsby starter site, which  is equivalent to initializing a package, installing  `yarn add gatsby react react-dom`, and returning one line of hardcoded page. I want to see if I could build a theme-powered site with the minimum amount of theme-specific knowledge and packages.

I’m going to start with the “happy path” so you can follow along and see how things work. After that, I’m going to show you the issues I encountered and how I got around them, followed by my notes and conclusion.

**Table of Content:**
- ☀️ The Happy Path
- ⛈ The Winding Path
- 📝 My Notes
- 🚪 Conclusion


----

## ☀️ The Happy Path 

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

### 1. Create a Gatsby site

We use the official [gatsby-starter-hello-world](https://github.com/gatsbyjs/gatsby-starter-hello-world) to create a new Gatsby site. I create it in a folder called `eka-hello-world-starter`; you might want to replace it with your own name. 😀


```sh
# create a new Gatsby site using the hello-world starter
gatsby new eka-hello-world-starter https://github.com/gatsbyjs/gatsby-starter-hello-world

# go to the site folder
cd eka-hello-world-starter

# run to check if it works
# (stop by pressing Ctrl + C)
gatsby develop
```

### 2. Import the theme

```sh
yarn add gatsby-theme-blog-mdx
```

### 3. Add the theme to our site

The starter we use does not have `gatsby-config.js`, so create it in the root of your site with the following content:
```js
// eka-hello-world-starter/gatbsy-config.js
module.exports = {
  __experimentalThemes: [
    {
      resolve: `gatsby-theme-blog-mdx`,
      options: {}, 
    },
  ],
}
```

As you can see, this resembles how we add plugins to our site. We can also set specific options, which we can see in [the theme's README](https://github.com/gatsbyjs/gatsby/tree/master/themes/gatsby-theme-blog-mdx#configuration).

### 4. Add your page content

Create a folder called `posts` in the root of your site, and create an `.mdx` file inside.

```sh
# create "posts" folder
mkdir posts

# create a file called "hello-world.mdx" in "posts"
touch posts/hello-world.mdx
```

Write your page content in the file. This is just an example; you can write anything as long as you fill the `title` field in the [frontmatter](https://github.com/cuttlebelle/website/blob/master/content/documentation/what-is-frontmatter.md).

```markdown
---
title: Hello World
---
Hello, world! This is a demo post for `gatsby-theme-blog-mdx`.
```
<figcaption>eka-hello-world-starter/posts/hello-world.mdx</figcaption>

**Note:** The folder name `posts` is defined in the theme. You _have_ to use that name unless you override the code (which is beyond the scope of this post). However, the file name can be anything you want.

### 5. Create an author list

We don’t actually use an author list in the UI, but the file is required by the theme. I’m going to discuss more about this in the next section. For now, let’s create a folder called `data` inside `src`, and create a file called `author.yaml` there.

```sh
# if you're still in "posts" directory, move up to project root
cd ..

# create "data" folder in "src"
mkdir src/data

# create a file called "author.yaml" in "data"
touch src/data/author.yaml
```

Add a field called `id` with _any_ value.

```yaml
# eka-hello-world-starter/src/data/author.yaml
- id: eka
```

### 6. Remove our site’s `index.js`

The starter site comes with an index page component. But in this case, we would like to use the theme’s index instead, so we shall delete our `eka-hello-world-starter/src/pages/index.js` file.


### 7. Run the app

Run `gatsby develop`. If everything goes well, we can open http://localhost:8000 in the browser and see a simple page with a title and a link to our posts page (*“See writing”*).

![index page](https://thepracticaldev.s3.amazonaws.com/i/m6jlclwuraub23i7xzyb.jpg)

Clicking the link takes us to http://localhost:8000/blog, the post list page. We can see our post title, “Hello World”.

![blog/posts page](https://thepracticaldev.s3.amazonaws.com/i/vlnc2nht6a6u78hbgl5m.jpg)

When we click the title, we go to http://localhost:8000/posts/hello-world, which contains the text we wrote in `hello-world.mdx` earlier. 

![single post page](https://thepracticaldev.s3.amazonaws.com/i/pzhnztom5a88vr8etnks.jpg)

Add another line to our `hello-world.mdx`, and you can see the page automatically update with the new content.

![hello-world.mdx file with a new line](https://thepracticaldev.s3.amazonaws.com/i/4szfpotdakpp4uxs68g6.png)

![the single post page with the newly added line, reflecting the change from the mdx file](https://thepracticaldev.s3.amazonaws.com/i/srzki2nrdg0vugwodwmj.jpg)

We’ve got us a blog! 🎉


### 8. Add a cat (optional)

Now let’s add another page. I’m adding a file called `cat.mdx` here:

```md
---
title: Happy Cat
---
Hello from a happy cat!
```
<figcaption>eka-hello-world-starter/posts/cat.mdx</figcaption>

But wait… we’re going to do something else now. With [MDX](https://mdxjs.com), we can add _React components_ to a Markdown page.

We are going to add this wonderful package [miukimiu/react-kawaii](https://github.com/miukimiu/react-kawaii) and import it into our new page.

```sh
# if you're still in "posts" directory, move up to project root
cd ..

# install the package
yarn add react-kawaii
```

Now let’s go back to our post file and add a component from the newly-installed `react-kawaii` package.

```md
---
title: Happy Cat
---
import { Cat } from "react-kawaii"

Hello from a happy cat!

<Cat size={320} mood="excited" color="#FFD882" />
```
<figcaption>eka-hello-world-starter/posts/cat.mdx</figcaption>

Run the app with `gatsby develop`, open http://localhost:8000/blog, and we can see our new post there.

![the blog/post list page with TWO post items, the second post is "Happy Cat"](https://thepracticaldev.s3.amazonaws.com/i/2s7prfoivh2jmgqo7c5y.jpg)

When we open the post page, we can see our post with the SVG cat image.

![single post page with content from cat.mdx, with a cartoon cat image](https://thepracticaldev.s3.amazonaws.com/i/wsd02nzaj26ab3wi49l5.jpg)

The ability to import components—whether components installed from an external packages or local ones—means we can add all sorts of interesting things to our pages! With Markdown and transformer plugins, we can already embed external media, but now we can add even more rich, interactive content. ✨

Next, I’m going to retrace my (confused) steps before arriving at the “happy path”. You may also skip to the _Notes_ and _Conclusion_ at the end of this post.

---

## ⛈ The Winding Path

###  `gatsby-theme-blog`, the one who got away

* I initially began from the [Getting Started](https://www.gatsbyjs.org/docs/themes/getting-started/) page. I installed `gatsby-starter-blog-theme` as per the instruction. I assumed this would be a starter site for using the `gatsby-theme-blog`, but the starter does not exist (discussed in [this issue](https://github.com/gatsbyjs/gatsby/issues/13481)).
* I searched for `gatsby-theme-blog` and found [the package](https://github.com/gatsbyjs/gatsby/tree/master/themes/gatsby-theme-blog). It was then I wondered if it’s possible to use  `gatsby-theme-blog` in a regular Gatsby site—ie. one _not_ created specifically for `gatsby-theme-blog`—which led me to write this post. Only one way to find out…
* I created a basic `hello-world` site and added `gatsby-theme-blog`, which was the same as steps 1 to 4 in the section above:
	* Ran `yarn add gatsby-theme-blog` in my site folder
	* Added `__experimentalThemes = ["gatsby-theme-blog"]` to `gatsby-config.js`
	* Created an example post and the home page as instructed in [steps 2-3](https://www.gatsbyjs.org/docs/themes/getting-started/#2-scaffold-out-an-example-post) in the page
* With bated breath I ran `gatsby develop`, and… 

```sh
Error: TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be   of type string. Received type undefined

gatsby-config.js:67 module.exports
[eka-hello-world-starter]/[gatsby-theme-blog]/gatsby-config.js:67:34
```

* As we can see, this error occurred because I did not supply the `path`, whatever it might be. I opened the theme’s `gatsby-config.js` in `node_modules` folder. The `typography` plugin options seemed to be the culprit, so I commented it out. 
```js
{
  resolve: 'gatsby-plugin-typography',
  // options: {
  //   pathToConfigModule: path.relative(
  //     root,
  //     require.resolve('./src/utils/typography')
  //   ),
  // },
},
```

* Then cleared cache and restarted the app. The error above was gone… but it’s replaced by another error:

```sh
GraphQLError: Expected type MarkdownRemarkFieldsEnum, found frontmatter___date; Did you mean the enum value frontmatter___title?
### other log message
TypeError: Cannot read property ‘allMarkdownRemark’ of undefined
gatsby-node.js:44 graphql.then.result
[eka-hello-world-starter]/[gatsby-theme-blog]/gatsby-node.js:44:35  
```

* I checked the offending line in the theme’s `gatsby-node.js`. It was `const posts = result.data.allMarkdownRemark.edges`, which merely stated the GraphQL query failed, hence no `result` data. The message before that hinted that the error might be related to the file frontmatter. 
	* I checked and made sure that: (1) I have Markdown files in _both_ `pages` and `posts` folders (just to be sure), and (2) the files have `title` field in the frontmatter.
	* I also checked the theme’s `gatsby-config.js` to ensure `gatsby-source-filesystem` and `gatsby-transformer-remark` plugins existed.
	* Last, I checked the README to ensure there is no required option to include. (Also tried the `postsPerPage` option just because.)

* Restarted the app, and… same error. Gave up, made myself coffee. 😬
* Then I saw in Gatsby’s official themes list that `gatsby-theme-blog-mdx` had an example site, so decided to use it instead.

![Animated GIF, Garfield the Cat chugging down coffee](https://media.giphy.com/media/pHZ8BDWQhJrvLmL29M/giphy.gif)
<figcaption>A coffee later...</figcaption>

### `gatsby-theme-blog-mdx`

* This [theme](https://github.com/gatsbyjs/gatsby/tree/master/themes/gatsby-theme-blog-mdx) has a [corresponding starter](https://github.com/gatsbyjs/gatsby/tree/master/themes/gatsby-starter-theme-blog-mdx), _but_ I did not use the starter directly because I wanted to have better understanding of adding a theme. I just peeked at the starter when I found a problem (more on this below) to compare the code.
* I took steps 1-3 
* I had no idea where to add my content (the MDX files). I’d have been able to investigate in `gatsby-config.js`, but I found out faster by looking at the example site that the MDX path is `posts`. All in all, there are three places I could discover where to put my content:
	* 1) the theme files (_this_ theme provides [a sample post format](https://github.com/gatsbyjs/gatsby/blob/master/themes/gatsby-theme-blog-mdx/posts/__frontmatter.mdx), but I guess other themes might not?)
	* 2) the theme’s associated starter site
	* 3) the theme’s `gatsby-config.js` file
* The [example MDX file](https://github.com/gatsbyjs/gatsby/blob/master/themes/gatsby-starter-theme-blog-mdx/posts/hello.mdx) has three frontmatter fields: `title`, `date`, and `author` out of [eight available fields](https://github.com/gatsbyjs/gatsby/blob/master/themes/gatsby-theme-blog-mdx/posts/__frontmatter.mdx). At this point, I did not know which ones were mandatory. I just deleted everything except `title`; I would add them back if there were any errors.
* **[Related to Step 5 in the previous section]** A quick look at the starter showed the existence of `src/data/author.yml`. But I ran the app anyway, wanting to go with as minimum modification as possible. As expected, I got a error:
```sh
Error: MdxFrontmatter.author cannot convert to OutputType the follow  ing string: ‘AuthorYaml’
```

* I opened the theme’s config and found [the culprit](https://github.com/gatsbyjs/gatsby/blob/master/themes/gatsby-theme-blog-mdx/gatsby-config.js#L14), the line `mapping: { "Mdx.frontmatter.author": `AuthorYaml` }`. I commented out the offending lines, then ran the app again. It worked!! 🙌🏾
* Now that I knew the app worked, I wanted to fix the `AuthorYaml` issue _without_ modifying the package file. Modifying package content is not good practice in the long run—if I were to update the app, I’d have to repeat the step above. If I shared my project in a repo, I’d have to tell everyone cloning the project to do it. I tried to override the `mapping` value with poorly-thought attempts like `"Mdx.frontmatter.author": false` 😝 to no avail. 
* So the choices are either to: (a) modify the theme file, or (b) create `author.yml` file in my site. I went with the latter, adding only the `id` and omitting other fields. 
* At this point, the app already worked. However, I did not know what the URLs of the pages generated by the theme. The “hacky” way to find out is to type any unavailable path (eg. http://localhost:8000/aaa), which would show Gatsby’s dev error page and list the available paths. But I wanted to see the theme’s index page! So… ↓
* **[Related to Step 6 in the previous section]** I removed the `src/pages/index.js` from the `hello-world` starter and restarted the app. Voila, I got what we saw in Step 7! 

That’s the end of my trial and error; the remaining steps went smoothly.

---

## 📝 My Notes

These are the notes and random thoughts I had about using themes. Bear in mind these are mostly my _subjective_ thoughts and I have _not_ fully mastered themes, so they might not be fully accurate!

🤔 __*What kind of Gatsby site can use themes? How much do I have to learn in order to use themes?*__ 
_Any_ Gatsby site—built on any starters OR without starter (ie. you manually installed the dependencies)—can use themes. The single required step is to add `__experimentalThemes` field containing the theme name in `gatsby-config.js`.

🤔 __*So why do we have starters specifically built for a specific theme?*__
A theme’s functionality can range from adding _one_ single empty file—like this “[smallest possible Gatsby theme](https://github.com/ChristopherBiscardi/gatsby-starter-theme/tree/master/gatsby-theme-minimal)”—to a whole complex site. As you can see in our experiment above, even with a fairly simple theme, we still needed to figure out where to put our posts and what the frontmatter should consist of, to name but a few. 

Thus, I understand the need for a theme-specific starter to onboard users painlessly. As described in [Themes Introduction](https://www.gatsbyjs.org/docs/themes/introduction/), “an install of a starter will consist of demo content and a compact gatsby-config”. You may also [convert your old starter to a theme](https://www.gatsbyjs.org/docs/themes/converting-a-starter/) and then consume it from any site.

Despite that benefit, however, I feel that *reliance* on theme-specific starters would defy the motivation of themes. Themes are supposed to be modular “LEGO blocks”—such as blog, ecommerce, search, data from any source—that developers can assemble to meet their needs ([source](https://youtu.be/SV2zu9FvUTw?t=506)). As such they should be resilient enough to be added to any kind of Gatsby site, big or small.

My current approach, if I were to add a Gatsby theme in a real-life situation, would be to treat the theme-specific starter site as a documentation of how to implement that theme (file formats, paths, etc).

🤔 __*I keep seeing yarn workspace in tutorials. Is it required?*__
You do _not_ need yarn workspace to use themes; you need it to _create themes locally_ (in your machine’s folder). If you import a theme published on NPM, like we do in this post, yarn workspace is not necessary. Check out this great post to learn more about yarn workspace: [Setting up Yarn Workspaces for Theme Development](https://github.com/gatsbyjs/gatsby/blob/beacac6215e7a527a937a121a482f0b60bd69126/docs/blog/2019-04-01-setting-up-yarn-workspaces-for-theme-development/index.md)

🍃 Topic I’m keen to explore later: Conflict between different themes, especially once a project grows in size. For instance, what if multiple themes use the same path and file format as source (eg. `/posts`) without capability of customizing the path? We would either need to write lots of conditionals in our config, or modify theme files directly. Is that even likely?

---

## 🚪 Conclusion

For the most part, Gatsby Themes live up to its promise: a theme is indeed “an NPM install away”, and it indeed enables users to add content without touching code. (In my opinion, _building_ a themed site still requires at least intermediate familiarity with Gatsby in general—which is greatly helped by Gatsby’s [exhaustive documentation](https://www.gatsbyjs.org/docs/).) Themes’ helpfulness largely relies on documentation (“how to use this theme?”) and/or a corresponding starter site.

Up next in this series: I’m going to create a Gatsby theme locally. 

Stay tuned and thanks for reading! 🙌🏾

📚 _For a list of Gatsby Themes resources, go to the end of my [Introduction](https://dev.to/ekaonthenet/learning-gatsby-themes-introduction-1gje) post_