Skip to content

Commit

Permalink
Refactor Rich Text implementation in gatsby-source-contentful (#25249)
Browse files Browse the repository at this point in the history
* feat(contentful): improve Rich Text field support

* Allow circular references
* Improve performance and reduce RAM footprint
* Query referenced entries and assets via GraphQL

fixes #24221

BREAKING CHANGE:

* Entities references in Rich Text fields are no more automatically resolved
* Use the `raw` subfield instead of `json`
* Use GraphQL to define your referenced data with the new `references` field
* Removes the `resolveFieldLocales` as the new `references` field automatically resolves locales
* To render Rich Text fields unse the new `renderRichText()` function from `gatsby-source-contentful/rich-text`

* perf(gatsby-source-contentful): use getNodesByType to locate Rich Text references

* clean up from rebase

* refactor to use a query for entry references

* simplify and reduce complexity of rich text raw field value injection

* performance: directly inject references into Rich Text field, skipping the extra node type

* remove plugin config for no more existing rich text resolveFieldLocales

* add hint to remove extra traversal of rich text as soon fixIds is gone

* add first test for rich text

* clean up code and use more Maps

* align readme for new rich text changes

* remove workarounds for fixIds

* add typescript types for rich text render function

* add tests for rich text rendering

* Dirty lock file

Co-authored-by: Peter van der Zee <github-public@qfox.nl>
Co-authored-by: gatsbybot <mathews.kyle+gatsbybot@gmail.com>
  • Loading branch information
3 people authored Nov 9, 2020
1 parent 631f3c4 commit a256346
Show file tree
Hide file tree
Showing 15 changed files with 1,968 additions and 629 deletions.
44 changes: 36 additions & 8 deletions packages/gatsby-source-contentful/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,10 +181,6 @@ Number of entries to retrieve from Contentful at a time. Due to some technical l

Number of workers to use when downloading contentful assets. Due to technical limitations, opening too many concurrent requests can cause stalled downloads. If you encounter this issue you can set this param to a lower number than 50, e.g 25.

**`richText.resolveFieldLocales`** [boolean][optional] [default: `false`]

If you want to resolve the locales in fields of assets and entries that are referenced by rich text (e.g., via embedded entries or entry hyperlinks), set this to `true`. Otherwise, fields of referenced assets or entries will be objects keyed by locale.

## Notes on Contentful Content Models

There are currently some things to keep in mind when building your content models at Contentful.
Expand Down Expand Up @@ -364,25 +360,43 @@ It is strongly recommended that you take a look at how data flows in a real Cont

Rich Text feature is supported in this source plugin, you can use the following query to get the json output:

### Query Rich Text content and references

```graphql
{
allContentfulBlogPost {
edges {
node {
bodyRichText {
json
raw
references {
... on ContentfulAsset {
contentful_id
fixed(width: 1600) {
width
height
src
srcSet
}
}
... on ContentfulBlogPost {
contentful_id
title
slug
}
}
}
}
}
}
}
```

To define a way Rich Text document is rendered, you can use `@contentful/rich-text-react-renderer` package:
### Rendering

```jsx
import { BLOCKS, MARKS } from "@contentful/rich-text-types"
import { documentToReactComponents } from "@contentful/rich-text-react-renderer"
import { renderRichText } from "gatsby-source-contentful/rich-text"

const Bold = ({ children }) => <span className="bold">{children}</span>
const Text = ({ children }) => <p className="align-center">{children}</p>
Expand All @@ -393,10 +407,24 @@ const options = {
},
renderNode: {
[BLOCKS.PARAGRAPH]: (node, children) => <Text>{children}</Text>,
[BLOCKS.EMBEDDED_ASSET]: node => {
return (
<>
<h2>Embedded Asset</h2>
<pre>
<code>{JSON.stringify(node, null, 2)}</code>
</pre>
</>
)
},
},
}

documentToReactComponents(node.bodyRichText.json, options)
function BlogPostTemplate({ data, pageContext }) {
const { bodyRichText } = data.contentfulBlogPost

return <div>{bodyRichText && renderRichText(richTextField, options)}</div>
}
```

Check out the examples at [@contentful/rich-text-react-renderer](https://github.com/contentful/rich-text/tree/master/packages/rich-text-react-renderer).
Expand Down
1 change: 1 addition & 0 deletions packages/gatsby-source-contentful/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module "gatsby-source-contentful" {}
4 changes: 3 additions & 1 deletion packages/gatsby-source-contentful/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
},
"dependencies": {
"@babel/runtime": "^7.11.2",
"@contentful/rich-text-react-renderer": "^14.1.1",
"@contentful/rich-text-types": "^14.1.1",
"@hapi/joi": "^15.1.1",
"axios": "^0.21.0",
Expand Down Expand Up @@ -55,5 +56,6 @@
},
"engines": {
"node": ">=10.13.0"
}
},
"types": "index.d.ts"
}
19 changes: 19 additions & 0 deletions packages/gatsby-source-contentful/rich-text.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { ReactNode } from "react"
import { Options } from "@contentful/rich-text-react-renderer"

interface ContentfulRichTextGatsbyReference {
/**
* Either ContentfulAsset for assets or ContentfulYourContentTypeName for content types
*/
__typename: string
contentful_id: string
}

interface RenderRichTextData<T extends ContentfulRichTextGatsbyReference> {
raw: string
references: T[]
}

export function renderRichText<
TReference extends ContentfulRichTextGatsbyReference
>(data: RenderRichTextData<TReference>, options?: Options): ReactNode
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Helper script to generate the test fixtures for the contentfulFetch call

import { writeFileSync } from "fs"
import { resolve } from "path"

import fetch from "gatsby-source-contentful/src/fetch"

let syncToken = ``
const reporter = {
verbose: console.log,
info: console.info,
panic: console.error,
}

const generateFixutures = async () => {
const pluginConfig = new Map([
[`spaceId`, `ahntqop9oi7x`],
[`accessToken`, `JW5Rm2ZoQl6eoqxcTC1b0J_4eUmXoBljtY9aLGRhRYw`],
[`environment`, `master`],
])
pluginConfig.getOriginalPluginOptions = () => {
return {}
}

const result = await fetch({ syncToken, reporter, pluginConfig })

writeFileSync(
resolve(__dirname, `fetch-result.json`),
JSON.stringify(result, null, 2)
)

console.log(`Updated result json`)
}

generateFixutures()
Loading

0 comments on commit a256346

Please sign in to comment.