Custom Plugins with Gatsby

Jun 15, 2020

A quick tutorial for how to create your own custom, local plugin for your Gatsby project.

** This tutorial assumes a basic knowledge of Gatsby.

Motivation

Recently, I ran into a situation in a project where I needed to wrap the root element in multiple providers (in my case, one for Auth0 and one for Apollo). But how do you do that? Enter custom, local plugins! You can abstract out the necessary logic and simply import your plugin into your gatsby-config file and let Gatsby take care of it all for you.

What exactly do you need to have for a plugin?

  1. Proper naming conventions
  2. a package.json file
  3. Proper implementation of Gatsby's APIs for Node, the browser, and server-side rendering

Naming conventions

There are 5 different options when it comes to naming plugins with Gatsby:

  • gatsby-source-*: a source plugin that connects data from a new data source to your Gatsby site (see the official docs for creating a source plugin)
  • gatsby-transformer-*: a transformer plugin to convert data from one format into a JavaScript object (see the official docs for creating a transformer plugin)
  • gatsby-[plugin-name]-*: if you're creating a plugin that extends another preexisting plugin
  • gatsby-theme-*: for creating a Gatsby theme, a special kind of plugin (see the official docs for creating a Gatsby theme)
  • gatsby-plugin-*: as the most general type of plugin, this naming convention is used if your plugin does not meet the requirements for any of the other types

Required Files

Gatsby will look for some specific files in your plugin. The only absolutely required file is a package.json. For a custom, local plugin, this can simply be an empty object. The key here is that even if the plugin doesn't need any packages or dependencies, YOU MUST HAVE A package.json FILE.

Other optional files include gatsby-browser.js, gatsby-ssr.js, and gatsby-node.js. Whether or not you include these will depend on the functionality of your plugin.

See the official docs here.

Project File Structure

Great, so we know what we need to set up our plugin. But where in our project do we put it? For a local plugin, your project structure should look something like this (assuming your plugin naming conventions follow the gatsby-plugin-* rule):

TEXT
/my-gatsby-site
└── gatsby-config.js
└── /src
└── /plugins
└── /gatsby-plugin-my-plugin
└── package.json

You will have a plugins folder at the root of your project. Within that, you will have another folder that follows the Gatsby plugin naming conventions. All of the files necessary for your plugin will live inside of this folder.

gatsby-config

Now that you have your plugin created and your project properly structured, it's time to import it in your gatsby-config!

gatsby-config.jsJS
module.exports = {
plugins: [`gatsby-plugin-my-plugin`],
}

gatsby-config.js is where you import your third party Gatsby plugins, including your own local plugins. For clarity, the only plugin we have here is our custom plugin. Make sure that the name of the plugin in gatsby-config matches the name you gave your plugin's folder.

And that's it! If you want more guidance or want to dig deeper, check out the official Gatsby docs for creating a plugin.

Example

As an example, let's take the live comments functionality we created in my last blog post and abstract it out into its own local plugin.

In that post, we created an apollo.js utility function that creates our http link and web socket connections and wraps the root element in an ApolloProvider. To integrate with Gatsby, we also created a gatsby-browser.js and a gatsby-ssr.js file in the root of our project. With the root element wrapped in our ApolloProvider for both server-side rendering and the browser, we can access our data in the rest of our application.

What would this look like as a plugin? First, let's create our plugins folder at the root of our project. Inside of /plugins, we need to create another folder that will hold all of the necessary files for our plugin. What should we name it?

This particular plugin is not sourcing data, transforming data, is not a plugin for another plugin, and is not a Gatsby theme. That means we need to use the gatsby-plugin-* naming convention. Let's call our plugin gatsby-plugin-apollo.

Now, what files does our plugin need? We know that no matter what, we need a package.json file. In our case, this will simply have an empty object since we'll be importing all of the dependencies we need in the package.json in the root of our project. We can move our apollo.js utility function into our plugin folder since that is where the functionality for our plugin is coming from. We also know that we'll need gatsby-browser.js and gatsby-ssr.js since our plugin relies on the the root element being wrapped in our ApolloProvider. Both of those files will have the same code:

gatsby-browser.jsJS
// copy this same code into the `gatsby-ssr.js` file
export { wrapRootElement } from "./apollo"

This will take the wrapRootElement being exported from our apollo.js file and use it both in the server-side rendering and in the browser.

All that's left to do is to add our new plugin to our gatsby-config.js file! Using the same name as what we name the folder for our plugin, our gatsby-config will look something like this:

gatsby-config.jsJS
module.exports = {
plugins: [`gatsby-plugin-apollo`],
}

As an overview, let's look at the before and after of our file structure. For clarity, I have excluded any component and page files that were originally in the `src` directory.

Before

TEXT
/my-gatsby-site
└── gatsby-config.js
└── gatsby-browser.js
└── gatsby-ssr.js
└── package.json
└── /src
└── /utils
└── apollo.js

After

TEXT
/my-gatsby-site
└── gatsby-config.js
└── package.json
└── /src
└── /plugins
└── /gatsby-plugin-apollo
└── package.json
└── gatsby-browser.js
└── gatsby-ssr.js
└── apollo.js

Ta-da! All we had to do was move a few files around, add a package.json that has an empty object, and update our gatsby-config in the root of our project. Easy-peasy :)