How do I fix "TypeError: childImageSharp is undefined" on NetlifyCMS build?

How do I fix "TypeError: childImageSharp is undefined" on NetlifyCMS build?

我正在现有的 gatsby 网站上设置一个简单的博客页面,我希望使用 netlify cms 的人能够上传博客的缩略图 post。我设法做到了,并使用 graphigl

找到了它

现在我想把它设置到我的博客post页面:

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 上重新部署时出现这些错误。

config.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 站点会轻而易举,但这是我尝试过的最困难的事情之一。

非常感谢任何帮助。

谢谢

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

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

      media_folder: static/img
      public_folder: /img
    

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

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

Public Folder

This setting is required.

The public_folder option specifies the folder path where the files uploaded by the media library will be accessed, relative to the base of the built site. For fields controlled by [file] or [image] widgets, the value of the field is generated by prepending this path to the filename of the selected file. Defaults to the value of media_folder, with an opening / if one is not already included.

   public_folder: "/images/uploads"

Based on the settings above, if a user used an image widget field called avatar to upload and select an image called philosoraptor.png, the image would be saved to the repository at /static/img/philosoraptor.png, and the avatar field for the file would be set to /img/philosoraptor.png.

你的 media_folder 看起来不错。

  • 您在 <figure> 标签内呈现图像的方式。按照您的方法,它将呈现一个带有图像路径的字符串,但是,您使用的是 gatsby-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

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

    在 Gatsby 中创建动态页面的“标准”方法是,使用 gatsby-node.js 来使用 createPage API,将需要的数据传递给模板(通常是 idslug) 并使用该唯一数据检索 blog/post 信息。

    您正在通过上下文传递 slug 但您从未使用它:

      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!) 传递,因此它不能为页面查询的空值。之后,您过滤降价节点 (markdownRemark) 以获得与您在 gatsby-node.js 文件中传递的上下文相匹配的节点。换句话说,在这种情况下,您拥有每个 post.

    的数据

    另请注意,您可能需要更改查询以匹配您的数据结构,我 post 在不知道您的字段的情况下从头开始编辑它。使用 localhost:8000/___graphql(GraphQL 操场)来检查它。你的片段不会在那里工作,因为它是 GraphQL 的限制,但它会在你的代码上工作,所以避免在那里使用它,但将它保留在你的代码中。