Netlify-cms: Missing images when using relation widget in file collection

Created on 23 Oct 2019  路  14Comments  路  Source: netlify/netlify-cms

Describe the bug
Brief: When I'm referencing a collection using relation widget(not a file collection, just basic folder collection) I'm getting all data from this relation except images. It just returns null for image field.

More info:
I have case-studies collection and referencing to it through relation widget from both folder and file collections. To access the relation entry I made a node field where I check for the relation string and pass its data to the node. (code below)

In case of relation folder-collection entry -> folder collection all work as expected and I'm getting all 'case-study' data with images.

But in case of relation file-collection entry -> folder collection I'm getting only data from 'case-study' with missed images.

To Reproduce
https://github.com/rusyurchenko/gatsby-netlify-issue

Expected behavior
A relation like 'file-collection entry -> folder collection reference" should return data with resolved images.

*Screenshots / Examples *
Example of file-collection entry -> folder collection reference query.
https://gist.github.com/rusyurchenko/1b58c0df547b30069dd155a1dd25c5c5

Example of relation folder-collection entry -> folder collection
https://gist.github.com/rusyurchenko/289ba43d909355c86cf01c883b860dcf

Applicable Versions:

  • Netlify CMS version: 2.9.7
  • Git provider: BitBucket
  • OS: MacOS Catalina
  • Browser version Chrome 77
  • Node.JS version: 10.16.3

CMS configuration
case-study as the base. marketing' folder collection and loyalty-why-do-need are referenced to the base.
https://gist.github.com/rusyurchenko/cacaaa5fb679e0d79584e514e481e300

onCreateNode: (where queries for collection reference)
https://gist.github.com/rusyurchenko/cff8e95407c7df0b11ca89372313a2e9

gatsby-config.js
https://gist.github.com/rusyurchenko/79396d92bb9340039413787c1ad2452f

Additional context
I think this issue happens because of some issue with image path resolve in file collection.

gatsby

All 14 comments

@rusyurchenko Thank you for opening this issue. Do you mind posting a reproduction scenario? (an example repo would be perfect). It will make it easier to pinpoint the exact location of the problem.

@erezrokah Will try to reproduce this issue with default starter later today, thank you!

@erezrokah Hey, sorry for the delay. I've reproduced this issue on the default blog starter. Example repo: https://github.com/rusyurchenko/gatsby-netlify-issue. Attached query example into readme.

Thanks @rusyurchenko I'll try to reproduce with the repo and update here

Related issues:
https://github.com/gatsbyjs/gatsby/issues/4123
https://github.com/gatsbyjs/gatsby/issues/13322
https://github.com/gatsbyjs/gatsby/issues/13938
https://github.com/gatsbyjs/gatsby/issues/14018

From what I managed to figure out from the Gatsby issues, this happens when Gatsby fails to treat the image as a File (and treats it as a string instead).

I managed to work around the issue by flattening the directory structure for the file collection (https://github.com/rusyurchenko/gatsby-netlify-issue/pull/1).

@erezrokah Yeah, it works but the issue is still open. In our case, Gatsby exactly treats the image file as a File since we're not getting an error such as "image" must not have a selection since type "String" has no subfields. We just got null under resolved image file.

Hey @rusyurchenko, sorry I forgot to mention it. I was getting "previewImage" must not have a selection since type "String" has no subfields when running yarn develop.
The strange thing is that it didn't happen all the time, and sometimes the error lead to the site not loading at all.

  • Failure image (when I get this error the site doesn't load at all):
    image

  • Success image (the site loads but with a null image):
    image

Both images are from running gatsby clean then gatsby develop on the same code which is very strange and hints to a race condition somewhere.

We'll need to take a closer look at Gatsby code to understand the issue better

@erezrokah Exactly! I'm getting the same issue with a broken image resolving time-to-time. But it's another issue related to gatsby build etc.

It still looks like a Gatsby build issue though (maybe not exactly the same one), since the workaround was just to change the folder structure (nothing related to the CMS).

I'll try to look at the Gatsby code to get a better sense of where the frontmatter previewImage field is evaluated. There must be a place there that changes the image string to an object with a publicURL field

Sorry for the delay, but I think I figured it out.
Gatsby evaluate files relative to their parent node.
This is done here: https://github.com/gatsbyjs/gatsby/blob/44f4ec0970545b6633fd90bf25274ed4980729f0/packages/gatsby/src/schema/resolvers.js#L202

In your code you're putting the path to the relation image under the post node. Specifically for the content/pages/test-page/index.md the relation image path is evaluated relatively to that file, while actually it should be evaluated related content/relations.
My original workaround just moved the post one directory up so it caused the evaluation to succeed.

Another issue is that Gatsby uses an internal map (weak map actually) to map root nodes to specific objects of those nodes. This happens here:
https://github.com/gatsbyjs/gatsby/blob/44f4ec0970545b6633fd90bf25274ed4980729f0/packages/gatsby/src/schema/node-model.js#L357

And here:
https://github.com/gatsbyjs/gatsby/blob/44f4ec0970545b6633fd90bf25274ed4980729f0/packages/gatsby/src/schema/node-model.js#L718

Since you linked the exact frontmatter instance the map (which uses reference equality) returned the wrong root node for the relation frontmatter thus again evaluating the path based on the wrong parent node.

This is evident by running these queries:

query OneNode {
  a: markdownRemark(fields: {slug: {eq: "/relations/test-collection/"}}) {
    id
    excerpt
    fields {
      slug
    }
    html
    frontmatter {
      title
      relation
      previewImage {
        publicURL
      }
    }
  }
}
query TwoNodes {
  a: markdownRemark(fields: {slug: {eq: "/relations/test-collection/"}}) {
    id
    excerpt
    fields {
      slug
    }
    html
    frontmatter {
      title
      relation
      previewImage {
        publicURL
      }
    }
  }
  b: markdownRemark(fields: {slug: {eq: "/pages/test-page/"}}) {
    id
    excerpt
    fields {
      slug
    }
    html
    frontmatter {
      title
      relation
      previewImage {
        publicURL
      }
    }
  }
}

The first one always returns a non null previewImage.
The second one inconsistently returns null for the relation previewImage. Inconsistently due to the usage of a weak map and the fact there is no specific order items are inserted into the map.

The solution was to deep clone the relation frontmatter object and also fix the previewImage when creating the node field: https://github.com/rusyurchenko/gatsby-netlify-issue/pull/2

@rusyurchenko do you mind testing my PR locally?

@erezrokah That works, make sense, thank you! Great explanation and clear solution. It can be closed.

However, it looks like a pretty simple solution and at the same time as some hack.

While solving this problem as a workaround I'm adding a node frontmatter relation value data to the page context and query exact relation object from the following page. Probably do you know another way to do the same (map relation node data to the post node) without doing extra work in onCreateNode?

I agree, it does feel like a hack.
Haven't tested it, but I would look into running two queries - one to get the relation field, then using that value to get the relation previewImage.

Closing for now.
Please re-open if you have more questions

I have the same issue!
in my case I have a non requered image, when i try to query it I got the same error
I tried to to add default value it did not worked


here is my code

about.md
image: ''

aboute.js
frontmatter { image { publicURL } }

config.yml
{ label: Image, name: image, widget: image, required: false, default: '/img/default.png', },

Hi @mouhsnimohamed I think https://www.gatsbyjs.org/docs/schema-customization/ is the recommended way to go in your case.

Was this page helpful?
0 / 5 - 0 ratings