首页 > 解决方案 > 如何在 NetlifyCMS 构建中修复“TypeError:childImageSharp 未定义”?

问题描述

我正在现有的 gatsby 网站上设置一个简单的博客页面,我希望使用 netlify cms 的人能够为博客文章上传缩略图。我已经设法这样做并使用 graphigl 找到它

图形屏幕截图

现在我想将它设置到我的博客文章页面:

import React from "react"
import { Link, graphql, useStaticQuery } from "gatsby"

import Layout from "../components/layout/layout"

const Blog = () => {
  const data = useStaticQuery(graphql`
    query {
      allMarkdownRemark {
        edges {
          node {
            frontmatter {
              title
              date
              thumbnail {
                childImageSharp {
                  fluid(maxWidth: 400) {
                    src
                  }
                }
              }
            }
            fields {
              slug
            }
          }
        }
      }
    }
  `)

  return (
    <>
      <Layout>
        <main className="main">
          <div className="articles">
            <h1 className="articles__title">Articles</h1>
            {data.allMarkdownRemark.edges.map(edge => {
              return (
                <section className="articles__list">
                  <a className="articles__article">
                    <div className="articles__article-artwork">
                      <figure className="articles__article-artwork-wrapper">
                        {edge.node.frontmatter.thumbnail.childSharpImage.fluid.src}
                      </figure>
                    </div>
                    <h2 className="articles__article-title">
                      <Link to={`/blog/${edge.node.fields.slug}`}>
                        {edge.node.frontmatter.title}
                      </Link>
                    </h2>
                    <Link>
                      <p>{edge.node.frontmatter.date}</p>
                    </Link>
                    <div className="articles__article-description">
                      <p></p>
                    </div>
                    <span className="articles__article-more">Read more...</span>
                  </a>
                </section>
              )
            })}
          </div>
        </main>
      </Layout>
    </>
  )
}
export default Blog

然后我在 netlify 上重新部署时收到这些错误。

netlify 构建错误

配置.yml

backend:
  name: github
  branch: development
  repo: (removed for work reasons)

media_folder: static/img
public_folder: img

collections:
  - name: "blog"
    label: "Blog"
    folder: "src/posts"
    create: true
    slug: "{{slug}}"
    fields:
      - {label: "Layout", name: "layout", widget: "hidden", default: "blog"}
      - {label: "Title", name: "title", widget: "string"}
      - {label: "Publish Date", name: "date", widget: "datetime"}
      - {label: "Body", name: "body", widget: "markdown"}
      - {label: "Image", name: "thumbnail", widget: "image"}

盖茨比-node.js

const path = require('path')

module.exports.onCreateNode = ({ node, actions }) => {
    const { createNodeField } = actions

    if (node.internal.type === "MarkdownRemark") {
        const slug = path.basename(node.fileAbsolutePath, '.md')

        createNodeField({
            node,
            name: 'slug',
            value: slug
        })
    }
}

module.exports.createPages = async ({ graphql, actions}) => {
    const { createPage } = actions
    const blogTemplate = path.resolve('./src/templates/blog.js')
    const res = await graphql(`
        query {
            allMarkdownRemark {
                edges {
                    node {
                        fields {
                            slug
                        }
                    }
                }
            }
        }
    `)

    res.data.allMarkdownRemark.edges.forEach((edge) => {
        createPage({
            component: blogTemplate,
            path: `/blog/${edge.node.fields.slug}`,
            context: {
                slug: edge.node.fields.slug
            }
        })
    })
}

盖茨比-config.js

module.exports = {
  siteMetadata: {
    title: `removed for work reasons`,
    description: `removed`,
    author: `removed`,
  },
  plugins: [
    `gatsby-plugin-react-helmet`,
    `gatsby-plugin-sass`,
    `gatsby-plugin-remove-serviceworker`,
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `img`,
        path: `${__dirname}/static/img`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `src`,
        path: `${__dirname}/src`,
      },
    },
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `gatsby-starter-default`,
        short_name: `starter`,
        start_url: `/`,
        background_color: `#663399`,
        theme_color: `#663399`,
        display: `minimal-ui`,
      },
    },
    {
      resolve: 'gatsby-plugin-react-svg',
      options: {
        rule: {
          include: /assets/
        }
      }
    },
    {
      resolve: `gatsby-transformer-remark`,
      options: {
        plugins: [
          {
            resolve: `gatsby-remark-images`,
              options: {
                maxWidth: 590,
              }
          },
          {
            resolve: `gatsby-plugin-netlify-cms-paths`,
            options: {
              cmsConfig: `/static/admin/config.yml`
            }
          }
        ]
      }
    },
    // this (optional) plugin enables Progressive Web App + Offline functionality
    // To learn more, visit: https://gatsby.dev/offline
    // `gatsby-plugin-offline`,
    `gatsby-plugin-netlify-cms`,
    `gatsby-plugin-netlify`,
  ],
}

老实说,我认为使用 netlify cms 将博客页面添加到我现有的 gatsby 站点会轻而易举,但这是我尝试过的最困难的事情之一。

很感谢任何形式的帮助。

谢谢

标签: reactjsgraphqlgatsbynetlifynetlify-cms

解决方案


对我来说有几件事很奇怪。

  • 您的查询不起作用(因此,破坏了代码),因为它找不到您的图像。config.yml将您的媒体路径更改为:

      media_folder: static/img
      public_folder: /img
    

    注意路径中的斜杠 ( /) 。public_folder

    这是因为它是相对路径并且必须以斜杠开头。来自 Netlify 文档(斜线部分加粗):

公共文件夹

此设置是必需的。

public_folder选项指定将访问媒体库上传的文件的文件夹路径,相对于构建站点的基础。对于由 [file] 或 [image] 小部件控制的字段,通过将此路径添加到所选文件的文件名来生成字段的值。默认为 media_folder 的值, 如果尚未包含,则打开/

   public_folder: "/images/uploads"

根据上述设置,如果用户使用名为的图像小部件字段avatar上传并选择名为的图像philosoraptor.png,则该图像将保存到存储库中 /static/img/philosoraptor.png,并且文件的头像字段将设置为/img/philosoraptor.png

media_folder看起来不错。

  • <figure>您在标签内渲染图像的方式。按照您的方法,它将呈现一个带有图像路径的字符串,但是,您正在使用Sharp fromgatsby-image但您没有使用它。在一些试验中,我建议以下:

    <figure>
       <Img fluid={edges.node.frontmatter.thumbnail.childImageSharp.fluid}>
    </figure>
    

    按照该gatsby-image方法,您还应该使用如下查询片段:

       const data = useStaticQuery(graphql`
      query {
        allMarkdownRemark {
          edges {
            node {
              frontmatter {
                title
                date
                thumbnail {
                  childImageSharp {
                    fluid(maxWidth: 400) {
                      ...GatsbyImageSharpFluid
                    }
                  }
                }
              }
              fields {
                slug
              }
            }
          }
        }
      }
    `)
    

    请注意...GatsbyImageSharpFluid片段以获取所有需要使用的数据gatsby-image

  • 您正在使用 astaticQuery但您不需要它,因为您的所有数据都来自 CMS。您应该使用页面/模板查询来提高性能,但这会改变您的页面结构。

    在 Gatsby 中创建动态页面的“标准”方式是gatsby-node.js使用createPageAPI,将所需的数据传递给模板(通常是idor slug)并使用该唯一数据来检索博客/帖子信息。

    您正在传递slugvia 上下文,但您从未使用它:

      context: {
        slug: edge.node.fields.slug
      }
    

    此外,您将再次使用静态查询(allMarkdownRemark)循环浏览所有文章,这没有意义,而且浪费时间和性能。

    您的Blog模板应如下所示:

      import React from 'react'
      import { graphql } from 'gatsby'
    
      const Blog = ({data}) => {
        return (
          <div>
           Blog title is: {data.markdownRemark.frontmatter.title}
         </div>
       )
    }
    
    export const query = graphql`
       query BlogQuery($slug: String!) {
      query {
        markdownRemark(fields: { slug: { eq: $slug }}) {
              html
              frontmatter {
                title
                date
                thumbnail {
                  childImageSharp {
                    fluid(maxWidth: 400) {
                      ...GatsbyImageSharpFluid
                    }
                  }
                }
              }
              fields {
                slug
              }
            }
         }
       }
    `
    
    export default Blog
    

    请注意,您将 slug ( $slug) 作为必需参数 ( String!) 传递,因此对于页面查询,它不能为 null。之后,您将过滤降价节点 ( ) 以获取与您在文件markdownRemark中传递的上下文相匹配的节点。gatsby-node.js换句话说,在这种情况下,您拥有每个帖子的数据。

    另请注意,您可能需要更改查询以匹配您的数据结构,我是在不知道您的字段的情况下从头开始发布的。使用localhost:8000/___graphql(GraphQL playground) 来检查它。您的片段将无法在其中工作,因为它是 GraphQL 的限制,但它可以在您的代码上工作,因此请避免在此处使用它,但将其保留在您的代码中。


推荐阅读