Skip to content

Commit

Permalink
feat: Build markdown nodes from CMS RichText fields (#98)
Browse files Browse the repository at this point in the history
* feat: Build markdown nodes for CMS markdown fields

Can be used with MDX

* feat: Add buildMarkdownNodes configuration option

Defaults to false

* style: Linting

* chore(demo): Add MDX dependencies

* chore(demo): Update demo to use MDX

* fix: Remove optional chaining

Eventually transpile with Babel

* docs: Update README to include markdownNode usage

* docs: Add link to demo source

For a full MDX example
  • Loading branch information
Jonathan Steele authored Jul 31, 2020
1 parent f820c81 commit fb77241
Show file tree
Hide file tree
Showing 10 changed files with 1,020 additions and 45 deletions.
8 changes: 7 additions & 1 deletion demo/gatsby-browser.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import React from 'react'
import { MDXProvider } from '@mdx-js/react'

import Layout from './src/components/layout'
import Parargraph from './src/components/paragraph'

import './src/styles/main.css'

const wrapPageElement = ({ element, props }) => {
return <Layout {...props}>{element}</Layout>
}

export { wrapPageElement }
const wrapRootElement = ({ element }) => {
return <MDXProvider components={{ p: Parargraph }}>{element}</MDXProvider>
}

export { wrapPageElement, wrapRootElement }
2 changes: 2 additions & 0 deletions demo/gatsby-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ require('dotenv').config()

module.exports = {
plugins: [
'gatsby-plugin-mdx',
'gatsby-plugin-postcss',
'gatsby-plugin-sharp',
{
resolve: 'gatsby-source-graphcms',
options: {
buildMarkdownNodes: true,
downloadLocalImages: true,
endpoint: process.env.GRAPHCMS_ENDPOINT,
token: process.env.GRAPHCMS_TOKEN,
Expand Down
6 changes: 5 additions & 1 deletion demo/gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ exports.createPages = async ({ actions: { createPage }, graphql }) => {
products: allGraphCmsProduct {
nodes {
description {
text
markdownNode {
childMdx {
body
}
}
}
formattedPrice
id
Expand Down
2 changes: 1 addition & 1 deletion demo/gatsby-ssr.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export { wrapPageElement } from './gatsby-browser'
export { wrapPageElement, wrapRootElement } from './gatsby-browser'
3 changes: 3 additions & 0 deletions demo/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
"dev": "ENABLE_GATSBY_REFRESH_ENDPOINT=true gatsby develop"
},
"dependencies": {
"@mdx-js/mdx": "1.6.16",
"@mdx-js/react": "1.6.16",
"gatsby": "2.23.22",
"gatsby-image": "2.4.13",
"gatsby-plugin-mdx": "1.2.30",
"gatsby-plugin-postcss": "2.3.11",
"gatsby-plugin-sharp": "2.6.19",
"gatsby-source-graphcms": "2.0.0",
Expand Down
7 changes: 7 additions & 0 deletions demo/src/components/paragraph.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react'

function Paragraph(props) {
return <p className="leading-relaxed md:text-xl text-lg" {...props} />
}

export default Paragraph
7 changes: 4 additions & 3 deletions demo/src/templates/product-page.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react'
import { graphql } from 'gatsby'
import Img from 'gatsby-image'
import { MDXRenderer } from 'gatsby-plugin-mdx'

const ProductPage = ({ data: { productImages }, pageContext: { product } }) => {
const [mainImage] = productImages.nodes
Expand All @@ -17,9 +18,9 @@ const ProductPage = ({ data: { productImages }, pageContext: { product } }) => {
{product.description && (
<React.Fragment>
<hr className="my-4" />
<p className="leading-relaxed md:text-xl text-lg">
{product.description.text}
</p>
<MDXRenderer>
{product.description.markdownNode.childMdx.body}
</MDXRenderer>
</React.Fragment>
)}
</div>
Expand Down
52 changes: 52 additions & 0 deletions gatsby-source-graphcms/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ module.exports = {

- Download and cache GraphCMS image assets in your Gatsby project. [Learn more](#downloading-local-image-assets).

- `buldMarkdownNodes` _Boolean_ (default value: `false`)

- Build markdown nodes for all [`RichText`](https://graphcms.com/docs/reference/fields/rich-text) fields in your GraphCMS schema. [Learn more](#using-markdown-nodes).

## Downloading local image assets

This source plugin provides the option to download and cache GraphCMS assets in your Gatsby project. This enables you to use [`gatsby-image`](https://www.gatsbyjs.org/packages/gatsby-image), for image loading optimizations, with your GraphCMS image assets.
Expand Down Expand Up @@ -107,3 +111,51 @@ You can then use the fragments from [`gatsby-transformer-sharp`](https://www.gat
```

For more information on using `gatsby-image`, please see the [documentation](https://www.gatsbyjs.org/packages/gatsby-image/?=#how-to-use).

## Using markdown nodes

This source plugin provides the option to build markdown nodes for all `RichText` fields in your GraphCMS schema, which in turn can be used with [MDX](https://mdxjs.com).

To enable this, add `buildMarkdownNodes: true` to your plugin configuration.

```js
// gatsby-config.js
module.exports = {
plugins: [
{
resolve: 'gatsby-source-graphcms',
options: {
endpoint: process.env.GRAPHCMS_ENDPOINT,
buildMarkdownNodes: true,
},
},
],
}
```

Enabling this option adds a `markdownNode` nested field to all `RichText` fields on the generated Gatsby schema.

### Usage with `gatsby-plugin-mdx`

These newly built nodes can be used with [`gatsby-plugin-mdx`](https://www.gatsbyjs.org/packages/gatsby-plugin-mdx) to render markdown from GraphCMS.

Once installed, you will be able to query for `MDX` fields using a query similar to the one below.

```gql
{
allGraphCmsPost {
nodes {
id
content {
markdownNode {
childMdx {
body
}
}
}
}
}
}
```

Check out the [demo source](https://github.com/GraphCMS/gatsby-source-graphcms/tree/next/demo) for an example of a full MDX implementation.
51 changes: 45 additions & 6 deletions gatsby-source-graphcms/gatsby-node.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const crypto = require('crypto')
const {
wrapQueryExecutorWithQueue,
loadSchema,
Expand Down Expand Up @@ -116,7 +117,7 @@ exports.sourceNodes = async (gatsbyApi, pluginOptions) => {

exports.onCreateNode = async (
{ node, actions: { createNode }, createNodeId, getCache },
{ downloadLocalImages = false }
{ buildMarkdownNodes = false, downloadLocalImages = false }
) => {
if (
downloadLocalImages &&
Expand All @@ -137,16 +138,54 @@ exports.onCreateNode = async (
console.error('gatsby-source-graphcms:', e)
}
}

if (buildMarkdownNodes) {
const fields = Object.entries(node)
.map(([, value]) => value)
.filter(
(value) =>
value && value.remoteTypeName && value.remoteTypeName === 'RichText'
)

if (fields.length) {
fields.forEach((field) => {
const markdownNode = {
id: `MarkdownNode:${createNodeId(node.id)}`,
parent: node.id,
internal: {
type: `GraphCMS_MarkdownNode`,
mediaType: 'text/markdown',
content: field.markdown,
contentDigest: crypto
.createHash(`md5`)
.update(field.markdown)
.digest(`hex`),
},
}

createNode(markdownNode)

field.markdownNode = markdownNode.id
})
}
}
}

exports.createSchemaCustomization = (
{ actions: { createTypes } },
{ downloadLocalImages = false }
{ buildMarkdownNodes = false, downloadLocalImages = false }
) => {
if (downloadLocalImages)
createTypes(`
type GraphCMS_Asset {
localFile: File @link
}
`)
type GraphCMS_Asset {
localFile: File @link
}
`)

if (buildMarkdownNodes)
createTypes(`
type GraphCMS_RichText {
markdownNode: GraphCMS_MarkdownNode @link
}
`)
}
Loading

0 comments on commit fb77241

Please sign in to comment.