Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(docs): New "Creating a Source Plugin" tutorial #37538

Merged
merged 49 commits into from
Apr 17, 2023
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
d8b0ee6
creating boilerplate dirs and files
LekoArts Jan 27, 2023
aa8ca7e
part 0
LekoArts Feb 7, 2023
2adda9e
misc changes
LekoArts Feb 7, 2023
fa7f06d
wip
LekoArts Feb 7, 2023
d3d0466
moar
LekoArts Feb 9, 2023
96a4f0d
more wip stuff
LekoArts Feb 15, 2023
fd5d69c
wip more
LekoArts Feb 16, 2023
918eff3
wip
LekoArts Feb 16, 2023
8a44d92
wip
LekoArts Feb 16, 2023
bb011de
part 2 nearly done
LekoArts Feb 16, 2023
5fc8c19
part 2 updates
LekoArts Feb 17, 2023
5625f3e
add diagram
LekoArts Feb 17, 2023
e2d34a3
part 3 wip
LekoArts Feb 21, 2023
2221703
part 3 progress
LekoArts Feb 22, 2023
9c083c8
part 3 done
LekoArts Feb 23, 2023
0c636f8
some review comments
LekoArts Feb 24, 2023
736ab39
wip
LekoArts Feb 27, 2023
1530178
part 4 lot of progress
LekoArts Feb 28, 2023
f49978a
sourcingTimer update
LekoArts Feb 28, 2023
14e3c0e
fix indendation
LekoArts Feb 28, 2023
bf1d799
fix typo
LekoArts Feb 28, 2023
5e9a8e0
update
LekoArts Mar 1, 2023
004c669
finish part4
LekoArts Mar 6, 2023
bf9bd68
part 5 start
LekoArts Mar 7, 2023
5595813
finish part 5
LekoArts Mar 8, 2023
1bedd5e
part 5 and 6
LekoArts Mar 8, 2023
bf44d9b
part 6 wip
LekoArts Mar 9, 2023
0bc3b31
finish part6
LekoArts Mar 13, 2023
4e7675b
part 7 wip
LekoArts Mar 14, 2023
69e6282
part 7
LekoArts Mar 14, 2023
d0e305c
finish all in draft state yey
LekoArts Mar 15, 2023
ce08d0a
Review comments from Tyler
LekoArts Mar 20, 2023
700409a
fix indendation
LekoArts Mar 20, 2023
3e36776
Alex review comments no1
LekoArts Mar 20, 2023
a8e7d72
Alex review comments no2
LekoArts Mar 20, 2023
15bdce3
michal comments no1
LekoArts Mar 21, 2023
d1900c4
Update docs/docs/tutorial/creating-a-source-plugin/part-1/index.mdx
LekoArts Mar 21, 2023
7ee49aa
Apply suggestions from code review
LekoArts Mar 21, 2023
b1933e3
alex review comments no3
LekoArts Mar 21, 2023
bd6d99d
Apply suggestions from code review
LekoArts Mar 23, 2023
e2adaa5
review comments
LekoArts Mar 23, 2023
f115392
Apply suggestions from code review
LekoArts Mar 23, 2023
85f1989
Apply suggestions from code review
LekoArts Mar 28, 2023
87fb180
more review comments from Stephanie
LekoArts Mar 30, 2023
a981034
Apply suggestions from code review
LekoArts Mar 30, 2023
84210ec
Apply suggestions from code review
LekoArts Apr 3, 2023
6d36693
address michal's review comments
LekoArts Apr 4, 2023
32ab7c4
Merge branch 'master' into docs/new-sourcing-docs
LekoArts Apr 6, 2023
f665745
remove old tutorial
LekoArts Apr 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions docs/docs/reference/config-files/node-api-helpers.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ showTopLevelSignatures: true

The first argument passed to each of [Gatsby’s Node APIs](/docs/reference/config-files/gatsby-node/) is an object containing a set of helpers. Helpers shared by all Gatsby’s Node APIs are documented in [Shared helpers](#apis) section.

```javascript
// in gatsby-node.js
```js:title=gatsby-node.js
exports.createPages = gatsbyNodeHelpers => {
const { actions, reporter } = gatsbyNodeHelpers
// use helpers
Expand All @@ -19,13 +18,14 @@ exports.createPages = gatsbyNodeHelpers => {

Common convention is to destructure helpers right in argument list:

```javascript
// in gatsby-node.js
```js:title=gatsby-node.js
exports.createPages = ({ actions, reporter }) => {
// use helpers
}
```

The [Creating a Source Plugin tutorial](/docs/tutorial/creating-a-source-plugin/part-4/) explains some of the [Shared helpers](#apis) in more detail.

## Note

Some APIs provide additional helpers. For example `createPages` provides `graphql` function. Check documentation of specific APIs in [Gatsby Node APIs](/docs/reference/config-files/gatsby-node/) for details.
116 changes: 116 additions & 0 deletions docs/docs/tutorial/creating-a-source-plugin/part-0/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
title: "Part 0: Introduction and Prerequisites"
---

import { LinkButton } from "gatsby-interface"
import { MdArrowForward } from "react-icons/md"

## Introduction

Welcome to the "Creating a Gatsby source plugin" tutorial. We're excited you're here!

In this tutorial you'll learn how to create a Gatsby source plugin that is following best practices, using Gatsby's latest features, and ultimately is how the Gatsby team wants you to build source plugins. By following our instructions your plugin will have great developer experience for you, and great reliability and usability for your users.
LekoArts marked this conversation as resolved.
Show resolved Hide resolved

Source plugins are an integral part to Gatsby's [GraphQL data layer](/docs/reference/graphql-data-layer/) as they are responsible for bringing data into that layer. They play a key role in hiding complex pieces of software (e.g. fetching and normalizing data from a remote API) behind an easy-to-use plugin. This also means that they have to be reliable, performant, and use best practices behind the scenes.

There is already a wealth of [existing source plugins](/plugins?=gatsby-source) in the Gatsby ecosystem you can use, but there may come a time when you want to create your own source plugin that doesn't already exist. If that sounds like a situation you've found yourself in, this tutorial is for you! Otherwise if you're curious to learn more about how Gatsby's source plugins work, you'll also find useful information here.

<Announcement>

This tutorial is indended to be an **additive guide**. Each part builds up on each other so we recommend you going through it from start to finish. However, if you want to revisit a specific topic each part should have all the necessary information on its own to be informative.
LekoArts marked this conversation as resolved.
Show resolved Hide resolved

You'll have a functioning source plugin at the end of part 2. The later parts are improving the plugin, adding functionalities, and explaining advanced topics. So while you can already publish what you have after part 2, we highly recommend going through all parts to learn how you can further improve your plugin.

</Announcement>

By the end of this part of the tutorial, you will:

- Know what background knowledge is assumed throughout the tutorial
LekoArts marked this conversation as resolved.
Show resolved Hide resolved
- Understand what a source plugin is and why you would want to create one
LekoArts marked this conversation as resolved.
Show resolved Hide resolved
- Install the necessary software

## Background knowledge

This tutorial assumes a basic understanding of Gatsby, [GraphQL](https://graphql.org/), [Node.js](https://nodejs.org/en/), and [TypeScript](https://www.typescriptlang.org/).

<Announcement>

Don't worry, you don't need to be an expert with these! A high-level understanding of the basics should be enough. You'll pick up a lot through the course of the tutorial.

</Announcement>

In terms of Gatsby-related knowledge, you should first complete the [Getting Started Tutorial](/docs/tutorial/getting-started/) since this guide builds on the knowledge established there.

In terms of the other technologies, you should be comfortable writing GraphQL queries, importing/exporting JavaScript modules, and making use of TypeScript types.

## What is a source plugin?

A plugin that adds additional data sources (content and data backends, e.g. CMSs like Contentful, WordPress, Drupal) to Gatsby that can then be queried by your pages and components. You can access these created nodes via Gatsby's universal GraphQL data layer.
LekoArts marked this conversation as resolved.
Show resolved Hide resolved
LekoArts marked this conversation as resolved.
Show resolved Hide resolved

At a high-level, a source plugin is:
LekoArts marked this conversation as resolved.
Show resolved Hide resolved

- Sourcing data from an external API in the best possible way
- Creating new nodes and establishing relationships between them
- Capable of customizing your site's GraphQL schema
- Improving the functionality of your external API by e.g. enabling advanced image manipulations through [Image CDN](/docs/how-to/images-and-media/using-gatsby-plugin-image/#gatsby-cloud-image-cdn)

In terms of code, a source plugin is the same as other plugins in that it must include:

- A `package.json` file with an entrypoint
- One or more Gatsby API files (usually a [`gatsby-node`](/docs/reference/config-files/gatsby-node/) file)

The difference is that source plugins should care only about sourcing data, while other plugins such as [transformer plugins](/docs/how-to/plugins-and-themes/creating-a-transformer-plugin/) or styling plugins may have other functionality that don't involve sourcing. Separating these concerns makes each plugin more reusable.

## Why create a source plugin?

The most common reason why you might want to create a new source plugin is that it may not exist yet in Gatsby's [plugin library](/plugins/?=gatsby-source).

Source plugins are a powerful concept. In a Gatsby site you can combine many data sources together via source plugins, like commerce data from Shopify, or content from one or more content management systems (like Contentful, WordPress, etc.), all in a single unified graph. Gatsby then leverages this graph to offer exciting features like [incremental builds](/blog/2020-04-22-announcing-incremental-builds/) and [Image CDN](/docs/how-to/images-and-media/using-gatsby-plugin-image/#gatsby-cloud-image-cdn).

Both of these topics will be covered in later parts of this tutorial, so stay tuned!

<Announcement>

**Please note:** If your data is local, e.g. on your filesystem or part of your site's repo then you generally **don't** want to create a new source plugin. Instead, use [`gatsby-source-filesystem`](/plugins/gatsby-source-filesystem/) as it already handles reading and watching files for you. You then can combine it with a [transformer plugin](/docs/how-to/plugins-and-themes/creating-a-transformer-plugin/#what-do-transformer-plugins-do), e.g. [`gatsby-transformer-remark`](/plugins/gatsby-transformer-remark) to transform markdown files.

</Announcement>

## When to create a source plugin?

Gatsby plugins are most often thought of as modules that are published to [npm](https://www.npmjs.com/) so that they can be shared and installed by others, but they can also be [local plugins](/docs/creating-a-local-plugin/) that exist only in a single site.

This same logic applies to source plugins. If you create a source plugin that you think others might make use of and you care to maintain it, please do publish it and [submit to the Gatsby plugin library](/docs/how-to/plugins-and-themes/submit-to-plugin-library/)! However, there is certainly no obligation to publish your plugin. If it serves its purpose for your use case just fine, keep it a local plugin.

The later parts of this tutorial will teach you how to go about developing a plugin in a way that makes it easy to publish later.
LekoArts marked this conversation as resolved.
Show resolved Hide resolved

## Development environment

The development environment is identical to the [Getting Started tutorial](/docs/tutorial/getting-started/), with the addition of [yarn](https://yarnpkg.com/), a package manager like [npm](https://npmjs.com). Refer to the [installation guide](/docs/tutorial/getting-started/part-0/#installation-guide) for setup instructions, as well as the [yarn installation instructions](https://yarnpkg.com/getting-started/install).

This tutorial uses [yarn workspaces](https://yarnpkg.com/features/workspaces) to develop the plugin and its companion example site in a monorepo. After going through this guide feel free to use any monorepo tooling you'd like (e.g. pnpm, NX, Turborepo, etc.) as it's not relevant for the Gatsby plugin itself.

## Summary

Now that you know the basics about Gatsby source plugins and have your computer set up, you're ready for the tutorial!

<Announcement>

**Share Your Feedback!**

Our goal is for this tutorial to be helpful and easy to follow. We'd love to hear your feedback about what you liked or didn't like about this part of the tutorial.

Use the "Was this doc helpful to you?" form at the bottom of this page to let us know what worked well and what we can improve.

</Announcement>

### What's coming next?

In Part 1 of the tutorial, you'll set up your project and learn how the project is structured.

<LinkButton
to="/docs/tutorial/creating-a-source-plugin/part-1/"
rightIcon={<MdArrowForward />}
variant="SECONDARY"
>
Continue to Part 1
</LinkButton>
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
170 changes: 170 additions & 0 deletions docs/docs/tutorial/creating-a-source-plugin/part-1/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
---
title: "Part 1: Set up the Project"
---

import { LinkButton } from "gatsby-interface"
import Collapsible from "@components/collapsible"
import { MdArrowForward } from "react-icons/md"

## Introduction

Now that you have the necessary background knowledge and your development environment set up, you can get your local project running!

There are many ways to author a Gatsby plugin or more generally speaking an npm package. Since we don't want you to be stuck in decision fatique on how to do things, you'll learn how to build a Gatsby source plugin in TypeScript with just `tsc` (that is the TypeScript compiler). Later you can decide to use other tooling if you wish. The repository you'll clone will also show how to test your plugin in a Gatsby site.
LekoArts marked this conversation as resolved.
Show resolved Hide resolved

By the end of this part of the tutorial, you will have:

- Cloned the companion repository to your local machine
- Explored the project structure
- Installed all required dependencies and built all packages
- Spun up the local development server

## Clone the repository

Clone the [companion repository](https://github.com/gatsbyjs/creating-source-plugin-tutorial) from GitHub to your desired location. The repository's `main` branch shows the finished state after following this tutorial. You can reference its code as an additional resource while going through this guide.

<Collapsible
summary={<em>GitHub cloning instructions</em>}
>

HTTPS snippet:

```shell
git clone https://github.com/gatsbyjs/creating-source-plugin-tutorial.git
```

SSH snippet:

```shell
git clone git@github.com:gatsbyjs/creating-source-plugin-tutorial.git
```

Also be sure to check out [GitHub's documentation for how to clone a repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository).

</Collapsible>

After successfully cloning the repository, navigate to its folder and switch to the `start` branch to have a clean boilerplate:

```shell
git checkout start
```

Open the repository in your favorite editor as it'll make the next step easier.

## Project structure

The `creating-source-plugin-tutorial` project includes three directories:

- `api`: This is the example backend API
- `plugin`: The source plugin
- `site`: An example Gatsby site

So the `site` uses the `plugin` which sources its data from `api`. As mentioned in [Part 0](/docs/tutorial/creating-a-source-plugin/part-0/#development-environment) this project uses yarn workspaces to make this setup work.
LekoArts marked this conversation as resolved.
Show resolved Hide resolved

By having the plugin and an example site that uses the plugin in the same repository, you can more easily test your plugin.

<Announcement>

You can ignore the `api` folder unless you're curious how a [GraphQL Yoga server](https://github.com/dotansimha/graphql-yoga) is set up. For the purpose of this tutorial the example backend API was included so that this tutorial doesn't rely on outside resources. This way you can run everything locally.

</Announcement>

The `plugin` itself has a structure we'd also recommend following:

- A `package.json` file that sets `gatsby` and `gatsby-plugin` as its `"keywords"` so that Gatsby's plugin search can pick it up
- A root `gatsby-node.js` that requires `./dist/gatsby-node` (the compiled TypeScript file). At the moment Gatsby looks for a root `gatsby-node.js` file as its entry file.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed some of the list items here end with a '.' and some don't. Is it if there are more than one sentence, then a period is required? Just wondering what approach the Gatsby docs use!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've looked it up in our style guide and we actually don't have rules for it 😅
But yes, I tend to do it like you described

- A well-written `README` that explains the user in concise steps how to install, use, and configure your plugin (also see [How to write a plugin README](/contributing/docs-contributions/how-to-write-a-plugin-readme/))
LekoArts marked this conversation as resolved.
Show resolved Hide resolved
- A `src` folder with the plugin's source code
- A root `gatsby-node.ts` file that exports [Gatsby Node APIs](/docs/reference/config-files/gatsby-node/) from individual files
- Individual files that only contain the specific Node API (in [kebab case](https://en.wikipedia.org/wiki/Letter_case#Kebab_case)), e.g. `onPluginInit` becomes `on-plugin-init.ts`. This will also make unit testing your plugin easier.

How you organize your `src` folder is of course up to you, we'd recommend keeping things consistent and files lowercase.
LekoArts marked this conversation as resolved.
Show resolved Hide resolved

<Collapsible
summary={<em>Wondering about a source plugin template for new projects?</em>}
>

Above we said that you can ignore the `api` folder. This is because for your real-world project you'll most probably source the data from an external API, not an API locally in your repository.
LekoArts marked this conversation as resolved.
Show resolved Hide resolved

The companion repository not only has a `start` branch but also a `template` branch without the `api` folder. You'll learn more about this at the end in the [What's next?](/docs/tutorial/creating-a-source-plugin/whats-next/) part. For now, go through the tutorial and at the end you'll know how to leverage the repository as a template for your new projects!

</Collapsible>

## Start the project

Ready to see something happen in your browser? Then let's go!

First, install the necessary dependencies to run everything:

```shell
yarn
```

Afterwards, open a new window in your terminal (you should have two now).

In the first window, run `develop:deps` to start watching the `api` and `plugin` directories. If you change something inside `api`, the GraphQL server will be restarted, if you change something in `plugin` the TypeScript compiler will output updated files.
LekoArts marked this conversation as resolved.
Show resolved Hide resolved

```shell
yarn develop:deps
```

You should see something like this in your terminal:
LekoArts marked this conversation as resolved.
Show resolved Hide resolved

```shell
[develop:api ] 14:48:03 - Starting compilation in watch mode...
[develop:api ]
[develop:plugin] 14:48:03 - Starting compilation in watch mode...
[develop:plugin]
[develop:api ] Server is running at http://localhost:4000/graphql
[develop:api ]
[develop:api ] 14:48:04 - Found 0 errors. Watching for file changes.
[develop:plugin]
[develop:plugin] 14:48:04 - Found 0 errors. Watching for file changes.
[develop:api ] Server is running at http://localhost:4000/graphql
```

Now, in your second terminal window, run `develop:site`. This runs `gatsby develop` for the example site:
LekoArts marked this conversation as resolved.
Show resolved Hide resolved

```shell
yarn develop:site
```

While `gatsby develop` is running you should also see the `info Example plugin loaded...` log. This shows that the plugin was successfully loaded for this initial demo. Yey 🎉
LekoArts marked this conversation as resolved.
Show resolved Hide resolved

<Announcement>

You're running `develop:site` in a separate window so that you can restart the process independently of the `develop:deps` script. If you make a change to your `plugin` you'll need to restart the example site.

</Announcement>

Once the development server is ready, go to `http://localhost:8000`, and be greeted by a minimalistic index page.

![A screenshot of "localhost:8000" in a web browser. There's a heading that says, "All posts" and a paragraph that says, "Posts will go here"](./01-clean-index-page.png)

### Key takeaways

- It's good practice to develop your source plugin alongside an example site to be able to test it
- You can keep your code organized by placing each Gatsby Node API in its own file
- When making changes to your plugin, you'll need to restart `gatsby develop` to see your changes applied

<Announcement>

**Share Your Feedback!**

Our goal is for this tutorial to be helpful and easy to follow. We'd love to hear your feedback about what you liked or didn't like about this part of the tutorial.

Use the "Was this doc helpful to you?" form at the bottom of this page to let us know what worked well and what we can improve.

</Announcement>

### What's coming next?

In Part 2 you'll learn how to do the most important part of a Gatsby source plugin: Sourcing data and displaying it on your site.
LekoArts marked this conversation as resolved.
Show resolved Hide resolved

<LinkButton
to="/docs/tutorial/creating-a-source-plugin/part-2/"
rightIcon={<MdArrowForward />}
variant="SECONDARY"
>
Continue to Part 2
</LinkButton>
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.