I have the following graphQL query I'm trying to get working:
{
allMarkdownRemark(
limit: 1000
) {
edges {
node {
id
parent {
id
}
fields{
slug
hero {
childImageSharp {
fixed {
src
}
}
}
}
frontmatter {
template
}
}
}
}
}
The hero
field currently returns a path to an image using the following code:
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
// Add slug to MarkdownRemark node
if (node.internal.type === 'MarkdownRemark') {
const value = createFilePath({ node, getNode, basePath: 'library' })
const { dir } = getNode(node.parent)
const getHero = (d) => {
let hero = `${__dirname}/src/images/no-hero.gif`
if (fs.existsSync(`${d}/hero.jpg`)) hero = `${d}/hero.jpg`
if (fs.existsSync(`${d}/hero.png`)) hero = `${d}/hero.png`
if (fs.existsSync(`${d}/hero.gif`)) hero = `${d}/hero.gif`
return hero
}
createNodeField({
node,
name: 'slug',
value,
})
createNodeField({
node,
name: 'hero',
value: getHero(dir),
})
}
}
I've seen other people do something similar with an image path in the frontmatter
but I don't want to have to use the frontmatter when it's easy enough to get graphql to see the file path without having to specify it.
However when I try the above I get the following error:
Field \"hero\" must not have a selection since type \"String\" has no subfields.
Is there a way I can get childImageSharp
to recognize this field?
I'm back again to (hopefully) settle this issue once and for all (see our history here).
This time, we'll attach the hero image's
ImageSharp
to theMarkdownRemark
node. Your approach is correct, with 1 caveat: Gatsby seems to only recognize relative paths, i.e path starting with a dot.You can fix this easily in your code:
This should work, though I want to provide an alternative hero search function. We can get a list of files in
dir
withfs.readdir
, then find a file with the name 'hero':This way we don't care what the hero image's extension is, as long as it exists. I use
String.prototype.includes
, but you might want to use regex to pass in a list of allowed extensions, to be safe, like/hero.(png|jpg|gif|svg)/
. (I think your solution is more readable, but I prefer to access the file system only once per node.)You can also use
path.relative
to find the relative path to a default hero image.Now, this graphql query works:
A (Minor) Problem
However, there's a minor problem with this approach: it breaks graphql filter type! When I try to query and filter based on
hero
, I get this error:Perhaps Gatsby forgot to re-infer the type of
hero
, so instead of being aFile
, it is still aString
. This is annoying if you need the filter to work.Here's a workaround: Instead of asking Gatsby to link the file, we'll do it ourselves.
And now we can filter the
hero
field again:If you don't need to filter content by hero image though, letting gatsby handle node type is much preferable.
Let me know if you run into issues trying this.