问题
So I've written a blog site in Gatsby and Remark. I've structured my posts like this:
Library/
-- category-name/
---- article-name/
------ index.md
This has worked really well and results in me being able to make paths like /category-name/article-name
.
What I also would like to do is to be able to drop an image in there called 'hero.jpg' and for it to be automatically picked up by Gatsby without having to add a frontmatter reference to it.
I've managed to get so far by adding the following to 'gatsby-node.js':
const hero = (fs.existsSync(path.resolve(__dirname, `src/library/pages/${slug}hero.jpg`))) ? `${slug}hero.jpg` : ''
createNodeField({
node,
name: 'hero',
value: hero,
})
This works as far as the graphql data goes and I now see the following:
{
"node": {
"id": "3190922a-2207-5621-a7be-e02be9e8da24",
"fields": {
"hero": "/category-name/article-name/hero.jpg"
},
},
However on the actual page, the image link /category-name/article-name/hero.jpg
doesn't exist so I get a dead image. I know this is because my image path is being transformed by gatsby-transformer-sharp
but I don't know how to work out what it is being transformed to.
I believe I need to do something akin to the answers on this SO question but that seems to expect you to know that the relativePath
is at the time you are writing your query but I won't have that information until after the query has returned the first time.
OnCreateNode hook added for claarity
exports.onCreateNode = ({ node, getNode, actions }) => {
const { createNodeField } = actions
// Add slug to MarkdownRemark node
if (node.internal.type === 'MarkdownRemark') {
const slug = createFilePath({ node, getNode, basePath: 'library' })
const hero = (fs.existsSync(path.resolve(__dirname, `src/library/pages/${slug}hero.jpg`))) ? './hero.jpg' : ''
createNodeField({
node,
name: 'slug',
value: slug,
})
createNodeField({
node,
name: 'hero',
value: hero,
})
}
}
回答1:
I realized my previous answer was incorrect & overly complicated (It relies on node creation order, also there's no need to add fields to imageSharp nodes. Here's the link if someone's interested.). Here's the better answer:
Querying image of hero
name in the same folder with mardown
Since the hero image is always at the same directory as the markdown file, we can simply query it based on its directory.
dir name ext
┌────────────┴────────────┐ ┌─┴─┐ ┌─┴─┐
absolute/path/to/directory/ hero .png
absolute/path/to/directory/ index .md
Graphql query:
file ( dir: { eq: "absolute/path/to/directory" }, name: { "hero" } ) {
childImageSharp {
fixed {
src
}
}
}
The only modification you need to make to your gatsby-node.js
is to add this dir
field to your page's context
so we can use it as a variable.
We can get this dir
by doing path.parse(node.fileAbsolutePath).dir
, or get the dir
field from remark's parent node getNode(node.parent.id).dir
+ const { dir } = getNode(node.parent.id)
createPage({
path: node.fields.slug,
component,
context: {
+ dir,
slug: node.fields.slug,
},
})
And query it like so:
export const pageQuery = graphql`
- query ArticleByPath($slug: String!) {
+ query ArticleByPath($slug: String!, $dir: String!) {
markdownRemark(fields: { slug: { eq: $slug } }) {
id
htmlAst
frontmatter {
title
}
}
+ file (dir: { eq: $dir }, name: { eq: "hero" }) {
+ childImageSharp {
+ fixed {
+ src
+ }
+ }
+ }
}
`
And use it:
export default function Template({ data }) {
const post = data.markdownRemark
+ const hero = data.file ? data.file.childImageSharp : null
return (
<div className="landing-page-container">
<Helmet title={`Your Blog Name - ${post.frontmatter.title}`} />
<div className="blog-post">
+ {hero && <img src={hero.fixed.src} alt={post.frontmatter.title} />}
<h1>{post.frontmatter.title}</h1>
<div className="blog-post-content">{renderAst(post.htmlAst)}</div>
</div>
</div>
)
}
Here's the gist for article.js and gatsby-node.js.
来源:https://stackoverflow.com/questions/54205509/gatsby-getting-image-path-after-graphql-query-has-returned