question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

gatsby-transformer-contentful-richtext should provide a documentToJSX method

See original GitHub issue

gatsby-transformer-contentful-richtext being React based should support converting the document output to JSX(very common with Gatsby afaik?).

@sarahbethfederman has been so kind as to write up a version here.


If done, and since this should involve updating the Gatsby plugin docs, it’d be good to show an example of a custom renderNode option that also has inner content like a link, and a common question that’ll probably be sought after, how to use the Gatsby <Link /> element for internal links.:

(Note this is pseudo-code, I don’t think the node side tends to like js files with import statements instead of require statements?)

// `./components/link.js`
import React from 'react'
import {INLINES, BLOCKS, MARKS} from '@contentful/rich-text-types';
import {Link as GatsbyLink} from "gatsby"

// Taken from: https://www.gatsbyjs.org/docs/gatsby-link/
// If given link begins with a single `/`, treat as internal Gatsby Link
const Link = ({children, to, activeClassName, ...other}) => {
  const internal = /^\/(?!\/)/.test(to);

  // Use Gatsby Link for internal links, and <a> for others
  if (internal) {
    return (
      <GatsbyLink to={to} activeClassName={activeClassName} {...other}>
        {children}
      </GatsbyLink>
    )
  }
  return (
    <a href={to} {...other}>
      {children}
    </a>
  )
}

const Options = {
  renderOptions: {
    renderNode: {
      [INLINES.HYPERLINK]: (node, next) => <Link to="${node.data.uri}">${next(node.content)}</Link>
    }
  }
}

export default Options


// `./gatsby-config.js`
const renderOptions = require("./components/link");

module.exports = {
  // ..other config
  plugins: [
    {
      resolve: "gatsby-source-contentful",
      options: {
        spaceId,
        accessToken
      }
    }, {
      resolve: '@contentful/gatsby-transformer-contentful-richtext',
      options: renderOptions
    },
    // ..other plugins
  ]
}

I noticed the docs mention a custom html element like this:

[MARKS.BOLD]: text => `<custom-bold>${text}<custom-bold>`,

No closing back slash on the tag? The naming convention doesn’t suggest that it’s a React/JSX styled custom element/component, so I assume that’s not related to Gatsby/React?

I assume we’re meant to be able to at the very least integrate the Link component from Gatsby. Presently I am doing this with react-jsx-parser on the provided html string. I also have the renderOption for the plugin to create a <Link/> element for internal links.

This isn’t full proof though, I assume parsing html elements like hr or img which JSX requires having closing back slashes might break it(if a documentToJSX method is made available, others elements like img might need to be catered for).

// `./gatsby-config.js`
const { BLOCKS, MARKS, INLINES } = require('@contentful/rich-text-types')

const renderOptions = {
  renderOptions: {
    renderNode: {
      [INLINES.HYPERLINK]: (node, next) => {
        // If given link begins with a single `/`, treat as internal Gatsby Link
        return /^\/(?!\/)/.test(node.data.uri)
        ? `<Link to="${node.data.uri}">${next(node.content)}</Link>`
        : `<a href="${node.data.uri}">${next(node.content)}</a>`
      }
    },
  },
}

module.exports = {
  // ..other config
  plugins: [
    {
      resolve: "gatsby-source-contentful",
      options: {
        spaceId,
        accessToken
      }
    }, {
      resolve: '@contentful/gatsby-transformer-contentful-richtext',
      options: renderOptions
    },
    // ..other plugins
  ]
}
// ./some-component.js
import React from 'react'

import JsxParser from 'react-jsx-parser'
import { Link } from 'gatsby'

const RichText = (props) => (
  <JsxParser
    components={{ Link }}
    jsx={props.content}
  />
)

Usage with example query on docs:

<RichText content={html} />

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:8 (5 by maintainers)

github_iconTop GitHub Comments

3reactions
mgmolisanicommented, Jan 11, 2019

So please forgive me as this will not only be the first github comment I’ve ever made but also the first code I will be attempting to collab on. Very nervous and not sure what proper etiquette is for working on things but I had taken a stab at this before looking at the open issues. I have been sourcing headless CMS for a family small business project and came across Contentful but also saw this need for a React transform since dangerouslySetInnerHTML limited flexibility with CSS in JS.

I looked at the code @sarahbethfederman provided but the key setting seems dangerous as it does not validate that a proper React element was passed before attempting to append the key in. This would cause text nodes to break in cases where the developer might write [MARKS.UNDERLINE]: text => text which would then spread your text string across your object letter by letter and add a key which would not be great. Since this is rich text, maybe a better approach is turning off underline in the CMS to avoid this but it is currently a valid callback.

I also considered the case where someone might want to pass a key manually on something like the embedded asset id. I can’t think of a strong use case for this since this is again rich text and the idea is to pretty much mimic the text in the component, but it could in some crazy way be used to preserve state on a key that isn’t relying on index.

I used the built in React functions to resolve both those issues (I think) and doesn’t feel as hacky. See below:

import React, {isValidElement, cloneElement} from 'react';

const appendKeyToValidElement = (element, key) => {
  if (element && isValidElement(element) && element.key === null) {
    return cloneElement(element, {key});
  }
  return element;
};

I also reworked some of the other code to be a little more straightforward not involving the next callback (which may not be preferable in the end as it is not consistent with the other renderers, but this did however start as a personal solution to the problem). I really appreciate any feedback, especially since this is very new to me. Very excited to try to help regardless of reception. Feedback appreciated. Thanks.

index.js full repo with tests reworked from html-renderer and some changes to test React specific renders

P.S. I have never written a React test so this was a challenge and I still don’t feel like I did it right since there is so much setup involved but I ended up with snapshots that were all what I expected so hopefully that is something.

EDIT: Also worth noting that there is no need to escape the html as React does this by default hence the dangerously in ‘dangerouslySetInnerHtml’ for getting around it.

1reaction
mgmolisanicommented, Feb 12, 2019

@ColeTownsend See my response and comments below on issue #46 here . Hope this helps.

Read more comments on GitHub >

github_iconTop Results From Across the Web

gatsby-transformer-contentful-richtext
gatsby -transformer-contentful-richtext · Install · How to use · Query · Advanced configuration · Open Source · Gatsby Cloud · Features · Community....
Read more >
Using Rich Text with the Contentful Source plugin
How to render and apply Rich Text fields with Gatsby and Contentful | Guide to querying Rich Text content with GraphQL.
Read more >
reactjs - Convert Markdown to HTML from within a Rich-Text ...
The most appropriate way to do this inside of Gatsby would be to create child nodes inside of the Gatsby onCreateNode lifecycle hook....
Read more >
Gatsby Changelog | 5.3.0
Install gatsby@next and let us know if you have any issues. ... temporary file and then the main process can playback any messages...
Read more >
@contentful/gatsby-transformer-contentful-richtext - npm
Parses Contentful Rich Text document. Latest version: 13.1.0, last published: 4 years ago.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found