Essential Gatsby plugins. Part 2, Markdown

Last update: 18 March, 2020
Table of contents

This post is part of a series. I believe you can follow without reading the whole thing, but I suggest following the links to other parts when something is not clear.

Go back to Part 1

3) Markdown

Markdown files are usually used in Gatsby as the posts in WordPress. They are text files where you can specify the formatting of the text (headings, paragraphs, text highlight), include images, videos, and more. Markdown files (.md) are… files (wow), so the first thing we’ll need is the gatsby-source-filesystem plugin—we used previously to parse our images. This plugin parses the images and creates File nodes that’ll be used by other transformer plugins. We install it with:

npm i gatsby-source-filesystem

and configure it in the same fashion in our gatsby-config.js.

* Keep in mind that we can declare the filesystem plugin as many times we want for our different file types (images, markdown, etc). To demonstrate this, I kept the configuration for images. You can omit the image stuff and add only the highlighted part:

gatsby-config.js
// We assume that you place your markdown files at a folder
// named "content" at the root of your project.
module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: "images",
        path: `${__dirname}/src/images/`,
      },
    },
    `gatsby-plugin-sharp`,
    `gatsby-transformer-sharp`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: "posts",
        path: `${__dirname}/content/posts/`,
      },
    },
  ],
};

Right now, the source filesystem plugin has created some File nodes, and we can write a GraphQL query to use them if we want. The official Gatsby starter tutorial does a great job explaining this process in steps. If you haven’t read it already, consider reading it now because it’s worth the time. But now we want to add some more useful fields to those File nodes. For example, it would be nice to transform the content of the markdown files to HTML and display it on our page. So the next plugin we’ll use for that is the gatsby-transformer-remark.

gatsby-transformer-remark

You can consider this plugin the “dad” of all other markdown transformer plugins. If you are an NBA fan, this plugin is the Gregg Popovich (legendary head coach) of markdown transformer plugins, and the others are Mike Budenholzer, Joe Prunty, etc.. (successful assistant coaches). Ok, I admit it, that was a bad analogy. Joe Prunty kinda sucks. You can install it with:

npm i gatsby-transformer-remark

and configure it in your gatsby-config.js:

gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: "posts",
        path: `${__dirname}/content/posts/`,
      },
    },
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [],
      },
    },
  ],
};

The transformer remark plugin enhances our File nodes, and it creates MarkdownRemark nodes that have fields like html, excerpt, heading, and more. If we create two sample posts, with really imaginative names like first-post.md and second-post.md, and place them in our /content/posts/ folder:

content/posts/first-post.md
## First post

**Always first!**

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis nec erat quis augue porta ornare. Maecenas auctor, metus et consectetur fringilla, quam justo iaculis nunc, vel malesuada diam leo at massa. Ut tristique elit eu gravida condimentum. Quisque mi mauris, tristique non diam ut, fermentum laoreet elit. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Pellentesque sem ex, euismod non magna porta, ornare convallis lectus.

Curabitur tempus elementum lorem, at porttitor libero vehicula id. Mauris vel purus euismod, malesuada nunc quis, imperdiet augue. Morbi dapibus quam lacinia, suscipit tellus vel, commodo libero.
content/posts/second-post.md
## Second post

**This is my second post.**

Nullam tempus enim dolor, non dictum magna imperdiet sed. Nullam dignissim vehicula ante, id dictum diam ultricies nec. Curabitur eget augue in nulla porta blandit quis ut mauris. Duis mollis tempor luctus. Nunc porta turpis libero, vel porttitor libero luctus vel. Morbi egestas malesuada purus, vel dapibus odio egestas eget. Aliquam iaculis placerat risus, non maximus risus gravida et. Curabitur tincidunt magna ac tellus blandit, nec ultrices lectus egestas. Vestibulum vitae tempus dui, a porta tellus. Morbi massa orci, rutrum a nisl at, tempus aliquet orci. Nullam pellentesque aliquam lacus sit amet auctor. Donec eget orci at ligula lacinia consequat. Sed fringilla, arcu nec tincidunt pellentesque, sapien tortor viverra libero, in cursus risus eros eleifend quam. Cras eu odio rutrum, interdum nisl a, congue nulla. In sit amet iaculis erat, eget consequat purus. Maecenas in neque est.

We can now write a GraphQL query in our pages, like the following, to view the generated fields:

src/pages/index.js
import React from "react";
import { graphql } from "gatsby";

const IndexPage = ({ data }) => (
  <div>
    <h1>Markdown files info</h1>
    {data.allMarkdownRemark.edges.map(({ node }, index) => (
      <div key={index}>
        <h3>{index}) This post...</h3>
        <p>Takes {node.timeToRead} mins to read</p>
        <p>and has {node.wordCount.words} words</p>
        <p>Post preview: {node.excerpt}</p>
        <div dangerouslySetInnerHTML={{ __html: node.html }} />
      </div>
    ))}
  </div>
);

export const query = graphql`
  query {
    allMarkdownRemark {
      edges {
        node {
          timeToRead
          excerpt(pruneLength: 280)
          wordCount {
            paragraphs
            sentences
            words
          }
          html
        }
      }
    }
  }
`;

export default IndexPage;

You may have noticed that we declared a plugins property when we configured the plugin and left it empty. This is because we can install and declare child plugins for the transformer remark plugin. Child remark plugins enhance the functionality of the “parent” plugin. The first child plugin we’ll see is the gatsby-remark-images.

gatsby-remark-images

It’s usual for markdown files to display images to make your content more interesting. If you want to avoid layout jumps, you want responsive image sizes for different screens, and progressive loading, you can use gatsby-remark-images for that. The remark-images-plugin uses the Sharp plugin that we saw earlier in the images section of the first part of the guide. To install both of them you type:

npm i gatsby-remark-images gatsby-plugin-sharp

and configure them in your gatsby-config.js as shown below:

gatsby-config.js
module.exports = {
  plugins: [
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: "posts",
        path: `${__dirname}/content/posts/`,
      },
    },
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [
          {
            resolve: `gatsby-remark-images`,
            options: {
              
              
              
              maxWidth: 1200,
            },
          },
        ],
      },
    },
  ],
};

To see your images, you’ll have to place them in your /static/ folder or at the same folder as the markdown file. In your markdown you can write:

![alt text](image-name.jpg)

* I want to point out here that images from the gatsby-remark-images plugin are displayed differently compared to the images from the gatsby-image plugin. For example, right now, you can’t lazy load images in markdown with gatsby-remark-images—a thing you can do for regular images with the gatsby-image plugin and the Img component. Keep this in mind, and try to avoid displaying a ton of images in your markdown. We now continue with the next child markdown plugin which is the gatsby-remark-responsive-iframe

gatsby-remark-responsive-iframe

In addition to images, you’d probably also want to display some videos in your markdown. You can do that, out of the box, with the gatsby-transformer-remark. But it would also be nice for the videos to scale depending on the screen size. For that, we need the gatsby-remark-responsive-iframe plugin. This plugin wraps the iframes with a responsive container, and the videos look good on any screen. You can install it with:

npm i gatsby-remark-responsive-iframe

and in your gatsby-config.js:

gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: "posts",
        path: `${__dirname}/content/posts/`,
      },
    },
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [`gatsby-remark-responsive-iframe`],
      },
    },
  ],
};

Keep in mind that the <iframe/> elements won’t be lazy-loaded. In this case, if you have a lot of videos, and you want to avoid draining all the data from your user’s mobile plan, consider using a library like lazysizes. For example, if you want to embed a video from YouTube in your markdown file, you’ll add an iframe in the following format:

<iframe
  title="Lebron James ends Jason Terry's life with an alley oop dunk."
  class="lazyload" type="text/html" width="640" height="360"
  data-src="https://www.youtube.com/watch?v=V-QTiByTKaI"
  frameborder="0" allowfullscreen>
</iframe>

Of course, you also need to install lazysizes and import it in your project. Now let’s move on from displaying images and videos, and let’s talk about how you can style code snippets in markdown with gatsby-remark-prismjs.

gatsby-remark-prismjs

The Prismjs plugin is used for adding style to the code blocks you display in markdown files. For example, in this site, I use Prismjs with the okaida theme to style my code snippets. You can install it with:

npm i gatsby-remark-prismjs prismjs

and configure it in your gatsby-config.js:

gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: "posts",
        path: `${__dirname}/content/posts/`,
      },
    },
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [
          {
            resolve: `gatsby-remark-prismjs`,
            options: {
              classPrefix: "language-",
              inlineCodeMarker: null,
              aliases: {},
            },
          },
        ],
      },
    },
  ],
};

You’ll also need to create a gatsby-brower.js file at the root of your app (at the same level as gatsby-config.js):

gatsby-browser.js
require("prismjs/themes/prism-okaidia.css");

If you want to create a code blog, you can write the following in your markdown:

## Printing stuff in Javascript

You can print **'Hello World'** in the console by writing the following:

```js
console.log("Hello World");
```

There are a lot of configuration options that you can use in the Gatsby documentation for the prism plugin. For example, I use line highlighting which is not supported by default. We continue with styling and making things pretty with the next plugin which is the gatsby-remark-smartypants.

gatsby-remark-smartypants

It took me a while to understand what the smartypants plugin does. In fact, it confused me so much that the initial explanation I gave here was completely wrong. The smartypants plugin transforms some punctuation marks to some other that are preferred. In other words, it makes you typographically correct. More specifically:

  • Converts quotation marks (U+0022) to left (U+201C) and right double quotation marks (U+201D):

    "hey"hey
  • Converts the apostrophe character (U+0027) to the right single quotation mark (U+2019), which is the preferred character to use for an apostrophe:

    it's → its
  • Converts 3 consecutive dots (U+002E)—also known as full stop or period—into an ellipsis character (U+2026). Because the difference is not visible, I suggest you to select both of the left and right part. You’ll notice that the first part is 3 characters and the second is 1 character.

    ... → …
  • Two hyphens (U+002D) to an en dash (U+2013)—with the oldSchool option, see the code block below:

    -- → –
  • Three hyphens to an em dash (U+2014)—with the oldSchool option:

    --- → —

I purposely omitted the option.backticks because it does the same thing as the first two.

npm i gatsby-remark-smartypants

and declare it in your gatsby-config.js:

gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: "posts",
        path: `${__dirname}/content/posts/`,
      },
    },
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [
          {
            resolve: "gatsby-remark-smartypants",
            options: {
              dashes: "oldschool",
            },
          },
        ],
      },
    },
  ],
};

And, you guessed it, you can further customize it by utilizing the extra options. We now leave the styling plugins, and we go to plugins that improve the user experience.

The next plugin we’ll see is the autolink headers plugin. This plugin adds automatically ids in your markdown headings and an anchor element with an SVG icon inside that, when clicked, goes you to the heading area. For example, in the next image, we can see what is generated if we inspect a heading with Chrome’s developer tools:

autolink headers example
autolink headers example

It’s really useful if you want to link to a different section on the same page, link to a specific section on a different page, or create a table of contents. You can install it with:

npm i gatsby-remark-autolink-headers

and add it in your gatsby-config.js:

gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: "posts",
        path: `${__dirname}/content/posts/`,
      },
    },
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: ["gatsby-remark-autolink-headers"],
      },
    },
  ],
};

You can configure it further by changing, for example, the SVG icon. The next plugin we’ll see is one that, like the gatsby-remark-smartypants, baffled me for some time.

gatsby-remark-copy-linked-files

gatsby-remark-copy-linked-files copies the files you link in your markdown and places them in the public folder. This plugin confused me because when I thought of files, my mind went to images. The gatsby-remark-images plugin we saw earlier already does the same thing for images. And that’s why I couldn’t figure out what it does because I tested it for images. So this plugin copies ALL the files types you link in your markdown. So, for example, if you have a markdown file in /content/posts folder:

## Post with a file

Click [here](stuff.txt) to download the file.

and create a stuff.txt file in the same folder, when you click the link, you won’t be able to see that file. To do that, you’ll have to install:

npm i gatsby-remark-copy-linked-files

and configure it in your gatsby-config.js as shown below:

gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: "posts",
        path: `${__dirname}/content/posts/`,
      },
    },
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: ["gatsby-remark-copy-linked-files"],
      },
    },
  ],
};

So now if you click the link, you can view the file. The next two plugins we’ll see are all about links.

The catch-links plugin is simple but really useful at the same time. It prevents your page from reloading when clicking links that link to a different page inside your application. If you only use the gatsby-transformer-remark, the generated links from markdown are regular anchor links. The default behavior is to reload the page, and as a result, it breaks the single-page experience. So as you can see, this plugin is pretty important. Especially for users with low-end mobile phones or bad internet connections because the reloading of the page is expensive. You can install it with:

npm i gatsby-plugin-catch-links

and configure it in the gatsby-config.js:

gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: "posts",
        path: `${__dirname}/content/posts/`,
      },
    },
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        // TODO: wrong
        plugins: ["gatsby-plugin-catch-links"],
      },
    },
  ],
};

The other “markdown link” plugin we’ll see, has to do with external links this time.

We close the markdown section with another useful plugin which is the gatsby-remark-external-links. This plugin adds to your markdown outbound links target and rel attributes. You can use it, for example, to add a target=_blank attribute to discourage the user from leaving your app when he/she clicks an external link. You can install with:

npm i gatsby-remark-external-links

and configure it in your gatsby-config.js:

gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: "posts",
        path: `${__dirname}/content/posts/`,
      },
    },
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [
          {
            resolve: "gatsby-remark-external-links",
            options: {
              target: "_blank",
              rel: "noopener",
            },
          },
        ],
      },
    },
  ],
};

That’s it for the Markdown plugins! In part 3 of this guide, we’ll see how you can transform your application into a Progressive Web App with almost no effort, and style your components. We’ll also see some other useful plugins that don’t fit in the previous categories.

Other things to read

Popular

Previous/Next