gatsbyjs / gatsby

The best React-based framework with performance, scalability and security built in.
https://www.gatsbyjs.com
MIT License
55.26k stars 10.31k forks source link

gatsby-source-contentful: include fields created by createNodeField in reference field resolution #24205

Closed scnroy closed 4 years ago

scnroy commented 4 years ago

Summary

I'm using createNodeField to add a field, route , to a node type created by gatsby-source-contentful. However, when querying for reference fields, my field isn't available on the resolved reference data.

Is there something I can hook into to make my custom field is available on the reference data or do I just need to query for all entries via useStaticQuery and filter by reference ID?

Right now, we're just using a Contentful UI extension to handle the route-generating logic, but due to a number of issues with that approach, we'd love to bring the logic over into gatsby.

Relevant information

File contents (if changed)

gatsby-config.js: N/A package.json: N/A gatsby-node.js:

exports.onCreateNode = async function({node, actions, getNode}) {
    const {createNodeField} = actions;

    // only log for nodes of type 'ContentfulDocument`
    if (node.internal.type !== 'ContentfulDocument') {
        return;
    }

    // recursive function that stitches together `slug`s of referenced entries.
    const route = concatSlugs(node, getNode);

    createNodeField({
        node,
        name: 'route',
        value: route,
    });
};

components/rich-text.js:

import React from 'react';
import {Link} from 'gatsby';
import {INLINES} from '@contentful/rich-text-types';
import {documentToReactComponents} from '@contentful/rich-text-react-renderer';

function entryHyperlink({data}, children) {
    const {fields} = data.target; // would love `route` to be in there somewhere
    const route = ''; // `route` does not exist on fields, set to empty string for this example.
    return (
        <Link to={route}>
            {children}
        </Link>
    );
}

const RichText = ({body}) => {
    const options = {
        renderNode: {
            [INLINES.ENTRY_HYPERLINK]: entryHyperlink,
        },
    };
    return documentToReactComponents(body.json, options);
};

gatsby-browser.js: N/A gatsby-ssr.js: N/A

vladar commented 4 years ago

Hey @scnroy

Sorry to hear you are running into an issue. Can you please share your GraphQL query? It should be something like:

{
  target {
    fields {
      route
    }
  }
}

If your graphql query looks like this then it should work. If it still doesn't work, please provide a minimal reproduction. Then we can take another look.

Thanks for using Gatsby 💜

scnroy commented 4 years ago

Sure thing! The query is in the component I'm using in my createPages function.

In Contentful, there's an Entry whose Rich Text field contains an Entry Hyperlink that references a different Entry. Both Entries have the node field added to them if queried directly, however, when they appear as a reference (i.e. in Rich Text or as a 'Reference' field type), the node does not contain the field I created.

Happy to make a minimal reproduction, if that'd make things clearer.

// components/document.js

import React from 'react';
import {graphql, Link} from 'gatsby';
import RichText from '../rich-text;

export default function Document({data}) {
    // eslint-disable-next-line camelcase
    const {title, body, contentful_id} = data.contentfulDocument;

    return (
        <div className="container">
            <h1>{title}</h1>
            <RichText body={body} />
        </div>
    );
};

export const query = graphql`
    query Query($id: String) {
        contentfulDocument(id: {eq: $id}) {
            id
            title
            body {
                json
            }
            fields {
                route
            }
            contentful_id
        }
    }
`;
vladar commented 4 years ago

So do you have data.contentfulDocument.fields.route available in the Document component? If so then the issue is about passing arguments to entryHyperlink function through documentToReactComponents and not about Gatsby workings?

I am just trying to understand if we can help you with this on the Gatsby side of things or you should for help in the @contentful/rich-text-react-renderer repo (as I don't know much about it)

scnroy commented 4 years ago

Ok, I think I've figured out how to describe the issue:

I'm wanting the entry-hyperlink that appears in the json field of contentfulDocumentBodyRichTextNode to contain the node field that I generated using gatsby's createNodeField on the corresponding contentfulDocument node.

I was assuming that gatsby-source-contentful was resolving the references in the RichText, but they're just coming down like that from Contentful. As a result, the target of the entry-hyperlink in the body of contentfulDocumentRichTextNode isn't actually linked, in gatsby, to the contentfulDocument node with the same contentful_id.

Because there's no link, any fields that i create on the contentfulDocument node won't show up on the entry-hyperlink.

vladar commented 4 years ago

Should you also create the same field on contentfulDocumentBodyRichTextNode? Anyways, I guess we need a minimal reproduction to be able to help.

danabrit commented 4 years ago

@scnroy I'm closing this issue due to no reproduction within 7 days. If you would like to re-open it with a minimal reproduction, we'd be happy to take a look. Thank you!

scnroy commented 4 years ago

Hi team, here's the minimal reproduction: https://github.com/scnroy/gatsby-24205-rich-text-node-field

Thanks!

vladar commented 4 years ago

Hey @scnroy

I think what you are trying to do is not supported by the current version of the Contentful plugin (2.x.x). The plugin uses original (raw) contentful data when resolving references in RichText fields. Then it simply stores it in the json field of Gatsby node.

So when you pass body.json to documentToReactComponents you pass original contentful entries before they are transformed to gatsby nodes.

There is a work in progress on the next major version of the Contentful plugin with better support for RichText fields. So I suggest you check out the following issues and PRs:

25249 - main PR for the next major (a preview available via gatsby-source-contentful@next)

24905 - part of this PR related to improvements for RichText fields

24221 - the summary issue for RichText improvements

We're marking this issue as answered and closing it for now but please feel free to comment and mention me if you would like to continue this discussion. We hope we managed to help and thank you for using Gatsby! 💜