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

docs: update creating source plugins guide & add example repo #22943

Merged
merged 10 commits into from
Apr 9, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
443 changes: 361 additions & 82 deletions docs/docs/creating-a-source-plugin.md

Large diffs are not rendered by default.

36 changes: 33 additions & 3 deletions docs/docs/creating-a-transformer-plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ Now you have a `File` node to work with:

Now, transform the newly created `File` nodes by hooking into the `onCreateNode` API in `gatsby-node.js`.

#### Convert yaml into JSON for storage in Gatsby nodes

If you're following along in an example project, install the following packages:

```shell
Expand Down Expand Up @@ -158,20 +160,46 @@ function transformObject(obj, id, type) {
...obj,
id,
children: [],
parent: node.id,
parent: null,
internal: {
contentDigest: createContentDigest(obj),
type,
},
}
createNode(yamlNode)
createParentChildLink({ parent: node, child: yamlNode })
}
```

Above, you create a `yamlNode` object with the shape expected by the [`createNode` action](/docs/actions/#createNode).

You then create a link between the parent node (file) and the child node (yaml content).
#### Creating the transformer relationship

You then need to create a link between the parent node (file) and the child node (yaml content) using the `createParentChildLink` function after adding the parent node's id to the `yamlNode`:

```javascript
function transformObject(obj, id, type) {
const yamlNode = {
...obj,
id,
children: [],
parent: node.id, // highlight-line
internal: {
contentDigest: createContentDigest(obj),
type,
},
}
createNode(yamlNode)
createParentChildLink({ parent: node, child: yamlNode }) // highlight-line
}
```

Another example of a transformation relationship is the `gatsby-source-filesystem` plugin used with the `gatsby-transformer-remark` plugin, which transforms a parent `File` node's markdown string into a `MarkdownRemark` node. The Remark transformer plugin adds its newly created child node as a child of the parent node using the action [`createParentChildLink`](/docs/actions/#createParentChildLink). Transformation relationships like this are used when a new node is _completely_ derived from a single parent node. E.g. the markdown node is derived from the parent `File` node and wouldn't ever exist if the parent `File` node hadn't been created.

Because all children nodes are derived from their parent, when a parent node is deleted or changed, Gatsby deletes all of the child nodes (and their child nodes, and so on) with the expectation that they'll be recreated again by transformer plugins. This is done to ensure there are no nodes left over that were derived from older versions of data but shouldn't exist any longer.

_For examples of other plugins creating transformation relationships, you can see the [`gatsby-transformer-remark` plugin](https://github.com/gatsbyjs/gatsby/blob/72077527b4acd3f2109ed5a2fcb780cddefee35a/packages/gatsby-transformer-remark/src/on-node-create.js#L39-L67) (from the above example) or the [`gatsby-transformer-sharp` plugin](https://github.com/gatsbyjs/gatsby/blob/1fb19f9ad16618acdac7eda33d295d8ceba7f393/packages/gatsby-transformer-sharp/src/on-node-create.js#L3-L25)._

#### Created new nodes from the derived data

In your updated `gatsby-node.js`, you'll then iterate through the parsed YAML content, using the helper function to transform each into a new node:

Expand Down Expand Up @@ -227,6 +255,8 @@ async function onCreateNode({
exports.onCreateNode = onCreateNode
```

#### Query for the transformed data

Now you can query for your new nodes containing our transformed YAML data:

```graphql
Expand Down
69 changes: 69 additions & 0 deletions examples/creating-source-plugins/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Typescript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# dotenv environment variable files
.env*

# gatsby files
.cache/
public

# Mac files
.DS_Store

# Yarn
yarn-error.log
.pnp/
.pnp.js
# Yarn Integrity file
.yarn-integrity
4 changes: 4 additions & 0 deletions examples/creating-source-plugins/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.cache
package.json
package-lock.json
public
7 changes: 7 additions & 0 deletions examples/creating-source-plugins/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"endOfLine": "lf",
"semi": false,
"singleQuote": false,
"tabWidth": 2,
"trailingComma": "es5"
}
21 changes: 21 additions & 0 deletions examples/creating-source-plugins/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2018 gatsbyjs

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
73 changes: 73 additions & 0 deletions examples/creating-source-plugins/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Creating First Class Gatsby Source Plugins

Create Gatsby plugins that leverage Gatsby's most impactful native features like remote image optimization, caching, customized GraphQL schemas and node relationships, and more.

This monorepo serves as an example of a site using a first class source plugin to pull in data from a Node.js API. It is meant to show the 3 pieces that work together when building a source plugin, the API, the site, and the source plugin.

## Setup

This monorepo uses yarn workspaces to manage the 3 indivdual projects:

- api: a Node.js API with in-memory data, and a Post and Author type, as well as support for subscriptions when Posts are mutated
- example-site: a barebones Gatsby site that implements the source plugin
- source-plugin: a plugin that uses several Gatsby APIs to source data from the API, create responsive/optimized images from remote locations, and link the nodes in the example site

To install dependencies for all projects run the install command in the root of the yarn workspace (which requires yarn to be installed):

```
yarn install
```

_Note: if you aren't using yarn, you can navigate into each of the 3 folders and run `npm install` instead_

Then you can run the api or example projects with:

```
// runs the api with yarn start at port 4000
yarn workspace api start
// runs the example site with gatsby develop at port 8000
yarn workspace example-site develop
```

Running the example site also runs the plugin because it is included in the site's config. You'll see output in the console for different functionality, and then can open up the browser to localhost:8000 to see the site.

## Developing and Experimenting

You can open up `localhost:4000` when the api is running and test a query like this to see data returned:

```graphql
{
posts {
id
}
}
```

You can also run 3 different mutations: `createPost`, `updatePost`, and `deletePost`. These methods would mimic CRUD operations happening on the API of the data source like a headless CMS.

When you run a mutation on a post, a subscription event is published, which lets the plugin know it should respond and update nodes:

```graphql
mutation {
updatePost(id: "post-id", description: "Some data!") {
id
slug
description
}
}
```

The websites homepage will update to any changes while the source plugin is subscribed to changes, which is when the `preview: true` is provided in the example site's `gatsby-config`.

You can also optionally listen for subscription events with this query in the playground which will display data when a mutatioin is run:

```graphql
subscription {
posts {
id
description
}
}
```

A similar subscription is registered when the plugin is run, so you can also see subscription events logged when the plugin is running.
3 changes: 3 additions & 0 deletions examples/creating-source-plugins/api/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Example API

A small GraphQL server with in-memory data, powered by [graphql-yoga](https://github.com/graphcool/graphql-yoga) 🧘. See the root of the monorepo for details about running this API alongisde the `example-site` and `source-plugin`.
43 changes: 43 additions & 0 deletions examples/creating-source-plugins/api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"name": "api",
"description": "A simple GraphQL server example with in-memory data",
"version": "1.0.0",
"license": "MIT",
"homepage": "https://general-repair.glitch.me",
"author": {
"name": "Risan Bagja Pradana",
"email": "[email protected]",
"url": "https://risan.io"
},
"main": "src/index.js",
"repository": {
"type": "git",
"url": "git+https://github.com/risan/simple-graphql-server-example.git"
},
"bugs": {
"url": "https://github.com/risan/simple-graphql-server-example/issues"
},
"keywords": [
"graphql",
"graphql-server",
"graphql-yoga"
],
"scripts": {
"start": "node src/index.js",
"lint": "eslint *.js src",
"lint-fix": "eslint *.js src --fix"
},
"dependencies": {
"dotenv": "^5.0.1",
"graphql-yoga": "^1.8.2",
"uniqid": "^4.1.1"
},
"devDependencies": {
"eslint": "^4.19.1",
"eslint-config-airbnb-base": "^12.1.0",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-import": "^2.10.0",
"eslint-plugin-prettier": "^2.6.0",
"prettier": "^1.11.1"
}
}
Loading