Gatsby React Minimum Viable Markdown Template / Component
Tags: webdev, gatsby, jamstack, tutorial
Published: 2020-06-18 12:59:55

---
title: Gatsby React Minimum Viable Markdown Template / Component
description:  "Continuing from my minimum viable build"
published: true
date: 2020-06-18 12:00:00 UTC
tags: webdev,gatsby,jamstack,tutorial
series: Playing With Gatsby
canonical_url: https://katiekodes.com/gatsby-hello-world-variations/
---

I [discovered that a directory only needs two small files in it for the Gatsby static website generator to turn it into a functioning `index.html`](https://dev.to/katiekodes/gatsby-minimum-viable-build-3n13) with a body of `<div>Hello world!</div>`.

{% link https://dev.to/katiekodes/gatsby-minimum-viable-build-3n13 %}

My next project is to build it up from an `index.md` Markdown file containing the message of "`Hello world!`" and have Gatsby inject it into `index.html`.

I'm still just shooting for some variation on this HTML for the contents of `index.html`:

```html
<html>
	<head></head>
	<body>
		<div>Hello World</div>
	</body>
</html>
```

---

## `index.md` looks different than I'm used to

In this case, I'm going to use an `index.md` file that doesn't have a Markdown-formatted "body;" it just has YAML-formatted "front matter" serving as data, like this:

```yaml
---
message: Hello World
---
```

Again, note that I put "`Hello World`" in the "front matter" up top, not down in the body as Markdown like this:

```
---
---

Hello World
```

{% link https://dev.to/katiekodes/jamstack-conf-takeaways-and-hopin-thoughts-54h3 %}

Since Topher Zimmerman's training on behalf of [Magnolia CMS](https://documentation.magnolia-cms.com/display/DOCS62/Hello+Magnolia) at [Jamstack Conf](https://dev.to/katiekodes/jamstack-conf-takeaways-and-hopin-thoughts-54h3) 2 weeks ago, while further exploring [Stackbit](https://www.stackbit.com/) and [TinaCMS](https://tinacms.org/), I've been learning that it's pretty common for Markdown files being used as data for static site generation with highly "WYSIWYG" **drag-and-drop content management systems _(CMSes)_** to have most data stored in the **front matter** of the `.md` file, not the **body**.

This lets you take advantage of YAML's ability to store "[nested, ordered data](https://katiekodes.com/intro-xml-json-2/)" nicely.

That property CMSes help authors specify, with drag-and-drop interactivity, intent such as:

> "Page sub-component B2 goes inside of page component B, after page sub-component B1, which is also inside of thing B.
> 
> "Page component B goes between page component A and page component C."

In fact, even if I wanted to let an author use Markdown to format "`Hello World`" into `<ul><li>Hello</li><li>World</li></ul>`, it's not unheard of to store _that_ in the front matter too, like this:

```yaml
---
message: |-
  * Hello
  * World
---
```

Instead of in the "body" of the `.md` file like this:

```
---
---

* Hello
* World
```

In Gatsby, it's traditional to put such an `index.md` file in a folder called `pages` that in turn is in a folder called `src`.

Furthermore, I have to include some "front matter" to specify what JavaScript "template" file I'm going to use to wrap the words "`Hello World`" between `<div>` & `</div>` tags, and it's conventional to simply call that front-matter property "`template`."  I'm planning on naming the template "`xyzzy`," so I'll add `template: xyzzy` to the front matter.

---

## Files

### `/src/pages/index.md`

In short, _my_ **`index.md`** file will have the following contents:

```yaml
---
template: xyzzy
message: Hello World
---
```

---

### `/package.json`

As in the 2-file [Gatsby minimum viable build](https://katiekodes.com/gatsby-minimum-viable-build/), I have to specify that certain [Node](https://en.wikipedia.org/wiki/Node.js) packages like React and like Gatsby itself are essential to building the static site.  I'll also specify two Gatsby plugins called `gatsby-source-filesystem` and `gatsby-transformer-remark` that I'll need:

```json
{
	"name" : "netlify-gatsby-test-02",
	"description" : "Does this really work?",
	"version" : "0.0.2",
	"scripts" : {
		"develop": "gatsby develop",
		"start": "npm run develop",
		"build": "gatsby build",
		"serve": "gatsby serve"
	},
	"dependencies" : {
		"gatsby": ">=2.22.15",
		"gatsby-source-filesystem": ">=2.3.11",
		"gatsby-transformer-remark": ">=2.8.15",
		"react": ">=16.12.0",
		"react-dom": ">=16.12.0"
	}
}
```

---

### `/gatsby-config.js`

I need to "activate" the Gatsby plugins `gatsby-source-filesystem` and `gatsby-transformer-remark` with a file called `gatsby-config.js`:

```javascript
module.exports = {
    plugins: [
        {
            resolve: `gatsby-source-filesystem`,
            options: {
                name: `pages`,
                path: `${__dirname}/src/pages`,
            },
        },
		`gatsby-transformer-remark`
    ]
};
```

---

### `/src/templates/xyzzy.js`

Gatsby leans heavily upon a JavaScript library called **React**, and specifically upon its notion of "React components" _(not to be confused with the contents of `/src/components/` in this project's folder structure, although that most certainly is a folder full of files defining **React components** -- it's just that `/src/templates` is also full of **React components**)_.

* The best way to learn what I mean by "React component" is to read the first 4 sections of the [official React documentation](https://reactjs.org/docs/hello-world.html).  They're well-written in tutorial style, so don't worry -- it's not a dry read.

Whenever Gatsby is told to use a given React component such as `xyzzy.js` to render a given "page" of a web site that it's decided needs rendering _(I'll soon write code in a file called `gastby-node.js` telling `xyzzy.js` about `index.md`)_, it passes information into the `Xyzzy` component as `pageContext`.

* If you define your React component [as a function](https://reactjs.org/docs/components-and-props.html#function-and-class-components), name its parameter `pageContext`.
* If you defined your React component [as a class](https://reactjs.org/docs/components-and-props.html#function-and-class-components) that extends `React.Component`, you'll automatically have this information accessible within your class as `this.props.pageContext`.

I'll dynamically fetch the text "`Hello World`" from `/src/pages/index.md` as a detail of `pageContext` called `pageContext.frontmatter.message` _(or, if I had been using classes, `this.props.pageContext.frontmatter.message`)_.

Note that the "`frontmatter`" property of `pageContext` doesn't exist yet.  I'll soon write code in a file called `gastby-node.js` that makes Gatsby include `frontmatter` in `pageContext`.

For now, just trust that `{pageContext.frontmatter.message}` is the equivalent of `Hello World` because that's what's in the "front matter" of `index.md`.

#### Variation 1 _(standalone template)_

```javascript
import React from "react"

export default function Xyzzy({ pageContext }) {
  return (
    <div>
	  {pageContext.frontmatter.message}
    </div>
  )
}
```

If I don't have anything too complicated to put into the home page of my web site, I can write `DIV` tags directly into `xyzzy.js` surrounding `{pageContext.frontmatter.message}`.

Note that `<div>{pageContext.frontmatter.message}</div>` technically isn't HTML -- it's [JSX](https://reactjs.org/docs/introducing-jsx.html) / a [React element](https://reactjs.org/docs/rendering-elements.html).

* If you're not sure what I mean by that, read the first 4 sections of the [official React documentation](https://reactjs.org/docs/hello-world.html).  It won't take you long.

#### Variation 2 _(leveraging another component)_

```javascript
import React from "react"

import BasicDiv from '../components/basicDiv.js';

export default function Xyzzy({ pageContext }) {
  return (
    <BasicDiv messageToDisplay={pageContext.frontmatter.message} />
  )
}
```

If I'm feeling fancy and prefer to delegate the building of the JSX React element `<div>Hello World</div>` to a different React Component _(for code modularity and reusability)_, I can add an extra file `/src/components/basicDiv.js` to my directory structure, "[import](https://javascript.info/import-export)" it into `xyzzy.js`, and execute it from within `xyzzy.js`'s JSX as <BasicDiv />.

To pass `BasicDiv` a parameter specifying "`Hello World`" as seen in `index.md`, I'll make that information an [attribute](https://katiekodes.com/intro-xml-json-3/#keys--their-values---approach-2-attributes) of the call to `<BasicDiv />`.

---

### `/src/components/basicDiv.js`

Note that I only need this file when using "variation 2" of `/src/templates/xyzzy.js`.

```javascript
import React from "react"

export default function BasicDiv(props) {
  return (
    <div>
	  {props.messageToDisplay}
    </div>
  )
}
```

The `BasicDiv` React component is never used directly by Gatsby in the building of a "page" from data such as the contents of `index.md`, so when defining it as a function, its parameter name should be a more traditional `props` rather than `pageContext`.

Because I know I summoned it elsewhere with a `message` parameter formatted `<BasicDiv message={some-data-here} />`, I can access the contents of `message` as `props.message` _(or, if I'd defined `BasicDiv` as a class, as `this.props.message`)_.

Since `BasicDiv` is never passed any sort of parameter named `pageContext` by Gatsby, the HTML-like JSX code I use to render my `DIV` is, instead, `<div>{props.message}</div>` or `<div>{this.props.message}</div>`.

---

### `/gatsby-node.js`

Finally, I come to the beastly file that teaches Gatsby how to put everything together:  `gatsby-node.js`.

```javascript
const path = require(`path`)
const { createFilePath } = require(`gatsby-source-filesystem`)

exports.onCreateNode = ({ node, getNode, actions }) => {
  const { createNodeField } = actions
  if (node.internal.type === `MarkdownRemark`) {
    const urlSuffixIdea = createFilePath({ node, getNode, basePath: `pages` })
    createNodeField({
      node,
      name: `suggestedURLSuffix`,
      value: urlSuffixIdea,
    })
  }
}

exports.createPages = async ({ graphql, actions }) => {
  const { createPage } = actions
  const queryResult = await graphql(`
	query {
	  allMarkdownRemark {
		  edges {
			node {
			  fields {
				suggestedURLSuffix
			  },
			  frontmatter {
				template,
				message
			  }
			}
		  }
	  }
	}
  `)
  nodes = queryResult.data.allMarkdownRemark.edges
  nodes.forEach(({ node }) => {
    createPage({
	  path: node.fields.suggestedURLSuffix,
	  component: path.resolve(`./src/templates/${node.frontmatter.template}.js`),
	  context: {
	    frontmatter: node.frontmatter,
	  },
    })
  })
};
```

#### Overriding `createPages`

Earlier, I said that I would need to teach Gatsby to pass details from the "front matter" of `index.md` to `xyzzy.js` as a `frontmatter` sub-property of a Gatsby concept called `pageContext`.

> I do this by overriding Gatsby's definition of a Gatsby function called `createPages()` within a file called `gatsby-node.js` that I'll place in the root directory of my folder structure.

The first thing I do is tell Gatsby to make a **GraphQL** query against its entire **self-inventory** of **stuff it knows about** and likes to call "nodes" _(not to be confused with [Node](https://en.wikipedia.org/wiki/Node.js) for which Gatsby is a package)_, filtering to only return the ones that seem to be Markdown-formatted files, and save the resulting JavaScript object into a variable I decided to call `queryResult`.

The part of `queryResult` that I'm interested in is an array of "`node`" objects accessible through `queryResult.data.allMarkdownRemark.edges` -- I'll set that array aside into a variabled called `nodes`.

_(In my case, there's only one object in the `nodes` array:  the one representing the contents of the file `/src/pages/index.md`.)_

For each loop over a `node` in `nodes`, I'll call [a Gatsby function `actions.createPage()`](https://www.gatsbyjs.org/docs/actions/).

1. I'll check what the `node`'s `suggestedURLSuffix` is and tell Gatsby to make the web page it renders available at `https://mysite.com/whatever-is-in-that-url-suffix` by setting `path` in the JavaScript object I pass `createPage()` to `node.fields.suggestedURLSuffix`.
	* More in a minute on where the value of `suggestedURLSuffix` comes from.
2. I'll also look through the front-matter properties of my Markdown-formatted file for one called `template` and concatenate it with other data to indicate a file path in my folder structure where Gatsby can find the definition of the React component that I'd like to use for transforming the Markdown-formatted file into HTML on my actual web site.  In the case of `index.md`, there's a property of `template: xyzzy`, and so setting `component` to `` path.resolve(`./src/templates/$xyzzy.js`) `` will ensure that `index.md` is associated with `xyzzy.js`.
3. Finally, I will say that I'd like the `node.frontmatter` details returned by my GraphQL query to be passed along to `xyzzy.js` as part of `pageContext` by including them in the `context` property of the JavaScript object I pass `createPage()`.  `context` itself takes a JavaScript object as a value, into which I put just one key-value pair:  `frontmatter` as the key, and `node.frontmatter` as the value.

#### Overriding `onCreateNode`

I promised to explain the origin of `suggestedURLSuffix`.

I define `suggestedURLSuffix` by overriding Gatsby's definition of a Gatsby function called `onCreateNode`, also within the `gatsby-node.js` file.

> Basically, I can use `onCreateNode()` to trick GraphQL into thinking that the "nodes" it's querying have properties they don't inherently have -- like `suggestedURLSuffix`.

In my case, I populate the value of `suggestedURLSuffix` with output from a call to the `gatsby-source-filesystem` plugin's `createFilePath()` function.

---

## Output

That's it!  Just 5 files _(or 6, to demonstrate breaking a `BasicDiv` function out of `Xyzzy`)_ and you're up and running with Markdown in Gatsby.

The resulting page has the following HTML:

```html
<!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"/>
        <meta name="generator" content="Gatsby 2.23.3"/>
        <link as="script" rel="preload" href="/component---src-templates-xyzzy-js-61a4d70344455ce4bf22.js"/>
        <link as="script" rel="preload" href="/framework-4d07bacc3808af3f4337.js"/>
        <link as="script" rel="preload" href="/app-3cfcd55108b187700e99.js"/>
        <link as="script" rel="preload" href="/webpack-runtime-2f540f584be2422b9aa4.js"/>
        <link as="fetch" rel="preload" href="/page-data/index/page-data.json" crossorigin="anonymous"/>
        <link as="fetch" rel="preload" href="/page-data/app-data.json" crossorigin="anonymous"/>
    </head>
    <body>
        <div id="___gatsby">
            <div style="outline:none" tabindex="-1" id="gatsby-focus-wrapper">
                <div>Hello World</div>
            </div>
            <div id="gatsby-announcer" style="position:absolute;top:0;width:1px;height:1px;padding:0;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0" aria-live="assertive" aria-atomic="true"></div>
        </div>
        <script id="gatsby-script-loader">/*<![CDATA[*/window.pagePath="/";/*]]>*/</script><script id="gatsby-chunk-mapping">/*<![CDATA[*/window.___chunkMapping={"app":["/app-3cfcd55108b187700e99.js"],"component---src-templates-xyzzy-js":["/component---src-templates-xyzzy-js-61a4d70344455ce4bf22.js"]};/*]]>*/</script><script src="/webpack-runtime-2f540f584be2422b9aa4.js" async=""></script><script src="/app-3cfcd55108b187700e99.js" async=""></script><script src="/framework-4d07bacc3808af3f4337.js" async=""></script><script src="/component---src-templates-xyzzy-js-61a4d70344455ce4bf22.js" async=""></script>
    </body>
</html>
```

---

## Helpful links

* [This codebase on GitHub](https://github.com/kkgthb/web-site-gatsby-02-template), as well as [its "BasicDiv" variant](https://github.com/kkgthb/web-site-gatsby-03-template-and-components)
* [React documentation](https://reactjs.org/docs/hello-world.html) _(the first four pages are solid gold)_
* [Three tips about ES6 JavaScript syntax in case you haven't worked with it](https://gist.github.com/gaearon/683e676101005de0add59e8bb345340c)
* [The JavaScript Language - Export and Import](https://javascript.info/import-export)
* [A dead simple intro to destructuring JavaScript objects](https://wesbos.com/destructuring-objects)
* [Gatsby official tutorial:  Get to Know Gatsby Building Blocks](https://www.gatsbyjs.org/tutorial/part-one)
* [Gatsby official tutorial:  Programmatically create pages from data](https://www.gatsbyjs.org/tutorial/part-seven/)
* [Gotcha:  `gatsby-transfomer-remark` must be activated in gatsby-config.js](https://github.com/gatsbyjs/gatsby/issues/17812#issuecomment-534209206)