简体   繁体   English

gatsby.js:“node.frontmatter.image 为空”

[英]gatsby.js: “node.frontmatter.image is null”

LAST EDIT: fixed.最后编辑:固定。 It was a naming convention.这是一个命名约定。 I am currently using this tree structure:我目前正在使用这种树结构:

-pages --posts ---00X-post For pagination/programmatically works fine so far. -pages --posts ---00X-post 到目前为止,分页/以编程方式工作正常。 And inside, md with its correspondent image (used as a thumbnail too).在里面, md 及其对应的图像(也用作缩略图)。 One of those had the naming wrong.其中一个名字有误。 Fixed.固定的。 Now everything is working just fine.现在一切正常。

EDIT and UPDATE:编辑和更新:

Thank you for your quick answer.谢谢你们的快速响应。 I tried that, nothing changed.我试过了,没有任何改变。 I do believe it has to do with all the templates for pagination I am currently using.我相信这与我目前使用的所有分页模板有关。 For example, the one in charge of creating page 2 and so in is this one:例如,负责创建页面 2 等的是这个:

import React from 'react';
import Layout from '../components/layout';
import Post from '../components/Post';
import { graphql } from 'gatsby';
import { Row, Col } from 'reactstrap'; 
import Sidebar from '../components/Sidebar'; 
import PaginationLinks from '../components/PaginationLinks'; 

const postList = (props) => {
    const posts = props.data.allMarkdownRemark.edges
    const { currentPage, numberOfPages } = props.pageContext 

    return (
        <Layout pageTitle>
        <h1 className='titles'>{`page ${currentPage}`}</h1>
            <Row>
                <Col>
                {posts.map(({node}) => (
                    <Post
                        key={node.id}
                        slug={node.fields.slug}
                        title={node.frontmatter.title}
                        author={node.frontmatter.author}
                        date={node.frontmatter.date}
                        body={node.excerpt}
                        tags={node.frontmatter.tags}
                        fluid={node.frontmatter.image.childImageSharp.fluid}
                    />
                ))}
                <PaginationLinks 
                currentPage={currentPage} 
                numberOfPages={numberOfPages} 
                    
                />
                </Col>
                <Col md='4'>
                    <Sidebar>

                    </Sidebar>
                </Col>
            </Row>
        </Layout>
    )

}

export const postListQuery = graphql`
    query postListQuery($skip: Int!, $limit: Int!) {
        allMarkdownRemark(
            sort: { fields: [frontmatter___date], order: DESC}
            limit: $limit
            skip: $skip 
        ) {
            edges {
                node {
                    id 
                    frontmatter {
                        title
                        date
                        author
                        tags
                        image {
                            childImageSharp {
                                fluid(maxWidth: 650, quality: 90) {
                                    ...GatsbyImageSharpFluid
                                }
                            }
                        }
                    }
                    fields {
                        slug
                    }
                    excerpt
                }
            }
        }
    }
`

export default postList

Same error messages appear when creating pages by tags/authors.按标签/作者创建页面时会出现相同的错误消息。 If I delete the image field from the query, everything works.如果我从查询中删除图像字段,一切正常。 This is unusual.这是不寻常的。

While doing a simple blog project with Gatsby I run into either "TypeError: childImageSharp is undefined” or "node.frontmatter.image is null". This error message appears at random. By the time I started writing this, trying to access pages/2 only triggered it.在用 Gatsby 做一个简单的博客项目时,我遇到了“TypeError:childImageSharp is undefined”或“node.frontmatter.image is null”。此错误消息随机出现。当我开始写这篇文章时,试图访问页面/ 2只触发了它。

Here's index.js:这是 index.js:

import React from "react"
import { graphql, StaticQuery } from 'gatsby'; 

import Layout from "../components/layout"
import SEO from "../components/seo"
import Post from '../components/Post'; 
import Sidebar from '../components/Sidebar'; 
import { Row, Col } from 'reactstrap'; 
import PaginationLinks from '../components/PaginationLinks'; 

const IndexPage = () => {

  const postsPerPage = 5; 
  let numberOfPages 

  return (
    <Layout>
    <SEO title="home" keywords={[`procedural`, `gatsby`]}/>
    <h1 className='titles'>procedural</h1>

    <Row>
      <Col>
        <StaticQuery 
        query={indexQuery}
        render={data => {

          numberOfPages = Math.ceil(
          data.allMarkdownRemark.totalCount / postsPerPage
          ); 

          return (
            <div>
              {
                data.allMarkdownRemark.edges.map(({ node }) => (
                  <Post 
                  key={node.id}
                  title={node.frontmatter.title}
                  author={node.frontmatter.author}
                  date={node.frontmatter.date}
                  slug={node.fields.slug}
                  body={node.excerpt}
                  fluid={node.frontmatter.image.childImageSharp.fluid}
                  tags={node.frontmatter.tags}
                  /> 
                ))
              }
              <PaginationLinks currentPage={1} numberOfPages={numberOfPages} />
            </div>
          )
        }}
        />
      </Col>
      <Col md='4'>
        <Sidebar>

        </Sidebar>
      </Col>
    </Row>

    </Layout>
  )
}

const indexQuery = graphql`
query {
  allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC}
    limit: 5
    ) {
    totalCount
    edges {
      node {
        id
        frontmatter {
          title
          date
          author
          tags
          image {
            childImageSharp {
              fluid(quality: 85, maxWidth: 960) {
                ...GatsbyImageSharpFluid
              }
            }
          }
        }
        fields {
          slug
        }
        excerpt
      }
    }
  }
}
`

export default IndexPage

Here's gatsby-node.js:这是 gatsby-node.js:

const path = require('path'); 
const { slugify } = require('./src/utils/utilityFunctions');
const authors = require('./src/utils/authors'); 
const _ = require('lodash'); 

// single post generator
exports.onCreateNode = ({ node, actions }) => {
    const { createNodeField } = actions
    if(node.internal.type === 'MarkdownRemark') {
        const slugFromTitle = slugify(node.frontmatter.title)
        createNodeField({
            node, 
            name: 'slug',
            value: slugFromTitle,
        })
    }
}

exports.createPages = async ({ actions, graphql }) => {
    const { createPage } = actions; 
    
    
    const templates = {
        singlePost: path.resolve('./src/templates/single-post.js'),
        tagsPage: path.resolve('./src/templates/tags-page.js'),
        tagPosts: path.resolve('./src/templates/tag-post.js'),
        postList: path.resolve('./src/templates/post-list.js'),
        authorPosts: path.resolve('./src/templates/author-posts.js'), 
    } 

    const res = await graphql(`
        {
            allMarkdownRemark {
                edges {
                    node {
                        frontmatter{
                            author
                            tags
                        }
                        fields {
                            slug
                        }
                    }
                }
            }
        }
    `)
    
    if(res.errors) return Promise.reject(res.errors)

    const posts = res.data.allMarkdownRemark.edges

    posts.forEach(({node}) => {
        createPage({
            path: node.fields.slug,
            component: templates.singlePost,
            context: {
                // passing slug, PENDING TAGS
                slug: node.fields.slug,
                // finding author imageUrl from authors.js and passing it to the single post template 

            },
        })
    })


            // creating post pages

    const postsPerPage = 5
    const numberOfPages = Math.ceil(posts.length / postsPerPage)

    Array.from({ length: numberOfPages }).forEach((_, index) => {
        const isFirstPage = index === 0
        const currentPage = index + 1

        // skip first page and go to index.js
        if (isFirstPage) return

        createPage({
            path: `/page/${currentPage}`,
            component: templates.postList,
            context: {
                limit: postsPerPage,
                skip: index * postsPerPage,
                numberOfPages: numberOfPages,
                currentPage: currentPage,
            },
            })
        })

        // tags PAGE GENERATOR; getting all tags
        let tags = []
        _.each(posts, edge => {
            if (_.get(edge, 'node.frontmatter.tags')) {
              tags = tags.concat(edge.node.frontmatter.tags)
            }
          })

        // account of tags, we're putting them like this: ['design', 'example', 'luck'] and also {design: X, example: Y, luck: z}
        let tagPostCounts = {}
        tags.forEach(tag => {
            tagPostCounts[tag] = (tagPostCounts[tag] || 0) + 1; 
        })

        tags = _.uniq(tags) //elimninate all duplicate entries 

        // create tags page here 
        createPage({
            path: `/tags`,
            component: templates.tagsPage,
            context: {
                tags,
                tagPostCounts,
            }
        })

        // tag post page creation here: 
        tags.forEach(tag => {
            createPage({
                path: `/tag/${_.kebabCase(tag)}`,
                component: templates.tagPosts,
                context: {
                    tag
                }
            })
        })

        // CREATING PAGES FOR EACH AUTHOR'S POSTS: 
        authors.forEach(author => {
            createPage({
                path: `/author/${slugify(author.name)}`,
                component: templates.authorPosts,
                context: {
                    authorName: author.name,
                    imageUrl: author.imageUrl, 
                }, 
            })
        })
}

here's gatsby-config.js:这是 gatsby-config.js:

  plugins: [
    `gatsby-plugin-sharp`,
    `gatsby-transformer-sharp`,
    `gatsby-plugin-react-helmet`,
    `gatsby-plugin-sass`,
    `gatsby-transformer-remark`,
    `gatsby-plugin-catch-links`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/pages`,
      },
    },
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `procedural`,
        short_name: `procedural`,
        start_url: `/`,
        background_color: `#663399`, // PLACEHOLDER
        theme_color: `#663399`, // PLACEHOLDER
        display: `minimal-ui`, // PLACEHOLDER
        icon: `src/images/logo.png`, // This path is relative to the root of the site.
      },
    },
  ],

And here's my single-post.js:这是我的 single-post.js:

import React from 'react';
import Layout from '../components/layout'; 
import { graphql, Link } from 'gatsby'; 
import SEO from '../components/seo';
import { Badge, Card, CardBody, CardSubtitle } from 'reactstrap'; 
import Img from 'gatsby-image'; 
import { slugify } from '../utils/utilityFunctions'; 

const SinglePost = ({ data, pageContext }) => {
    const post = data.markdownRemark.frontmatter; 

    return (
        <Layout>
            <SEO title={post.title}/>
            <h1 className='postTitles'>{post.title}</h1>

                    <Card>
                        <Img className='card-image-top' fluid={post.image.childImageSharp.fluid}>

                        </Img>
                        <CardBody className='cardBody'>
                            <CardSubtitle>
                                <span className='text-info'>
                                    {post.date}
                                </span> by{' '}
                                <span className='text-info'>
                                    {post.author}
                                </span>
                            </CardSubtitle>
                            <div dangerouslySetInnerHTML={{ __html: data.markdownRemark.html }}>

                            </div>
                            <ul className='post-tags'>
                                {
                                    post.tags.map(tag => (
                                        <li key={tag}>
                                            <Link to={`/tag/${slugify(tag)}`}>
                                                <Badge className='myTags'>{tag}</Badge>
                                            </Link>
                                        </li>
                                    ))
                                }
                            </ul>
                            <br/>
                            <Link
                                to={'/'} 
                                className='myButton float-left'>
                                Go back
                            </Link>
                        </CardBody>

                    </Card>
                    <h3 className='text-center'>
                        Share this post
                    </h3>
                    <div className='text-center social-share-links'>
                        <ul>
                            <li>
                                <a href={'https://www.facebook.com/sharer/sharer.php?u=' + baseUrl + 
                                pageContext.slug}
                                className='facebook' target='_blank'
                                rel='noopener noreferrer'>
                                    <i className="fab fa-facebook-f fa-2x"/>
                                </a>
                            </li>
                            <li>
                                <a href={'https://www.twitter.com/share?url=' + 
                                baseUrl + 
                                pageContext.slug +
                                '&text=' +
                                post.title +
                                '&via' +
                                'twitterHandle'}
                                className='twitter' target='_blank'
                                rel='noopener noreferrer'>
                                    <i className="fab fa-twitter fa-2x"/>
                                </a>
                            </li>
                            <li>
                                <a href={'https://www.plus.google.com/share?url' + 
                                baseUrl + 
                                pageContext.slug
                                }
                                className='google' target='_blank'
                                rel='noopener noreferrer'>
                                    <i className="fab fa-google fa-2x"/>
                                </a>
                            </li>
                            <li>
                                <a href={'https://www.linkedin.com/shareArticle?url=' + 
                                baseUrl + 
                                pageContext.slug
                                }
                                className='linkedin' target='_blank'
                                rel='noopener noreferrer'>
                                    <i className="fab fa-linkedin fa-2x"/>
                                </a>
                            </li>
                        </ul>
                    </div>

        </Layout>
    )

}

export const postQuery = graphql`
    query blogPostBySlug($slug: String!) {
        markdownRemark(fields: { slug: { eq: $slug } }) {
            id
            html
            frontmatter {
                title
                author
                date
                tags
                image {
                    childImageSharp{
                        fluid(quality: 100, maxWidth: 960) {
                            ...GatsbyImageSharpFluid
                        }
                    }
                }

            }
        }

    }
`

export default SinglePost; 

Here's what happens when using gatsby develop:以下是使用 gatsby develop 时发生的情况:

$ gatsby develop
success open and validate gatsby-configs - 0.027s
success load plugins - 0.904s
success onPreInit - 0.031s
success initialize cache - 0.005s
success copy gatsby files - 0.081s
success onPreBootstrap - 0.014s
success createSchemaCustomization - 0.008s
success Checking for changed pages - 0.002s
success source and transform nodes - 0.126s
success building schema - 0.291s
info Total nodes: 110, SitePage nodes: 19 (use --verbose for breakdown)
success createPages - 0.061s
success Checking for changed pages - 0.001s
success createPagesStatefully - 0.087s
success update schema - 0.023s
success write out redirect data - 0.002s
success Build manifest and related icons - 0.103s
success onPostBootstrap - 0.109s
info bootstrap finished - 3.883s
success onPreExtractQueries - 0.002s
success extract queries from components - 0.419s
success write out requires - 0.027s
success run static queries - 0.030s - 2/2 65.79/s
success run page queries - 0.020s - 2/2 100.53/s
⠀
You can now view gatsby-starter-default in the browser.
⠀
  http://localhost:8000/
⠀
View GraphiQL, an in-browser IDE, to explore your site's data and schema
⠀
  http://localhost:8000/___graphql
⠀
Note that the development build is not optimized.
To create a production build, use gatsby build
⠀
success Building development bundle - 4.905s

Here's the error message when running gatsby build:这是运行 gatsby build 时的错误消息:

$ gatsby build
success open and validate gatsby-configs - 0.024s
success load plugins - 0.902s
success onPreInit - 0.047s
success delete html and css files from previous builds - 0.006s
success initialize cache - 0.004s
success copy gatsby files - 0.082s
success onPreBootstrap - 0.012s
success createSchemaCustomization - 0.008s
success Checking for changed pages - 0.001s
success source and transform nodes - 0.126s
success building schema - 0.276s
info Total nodes: 110, SitePage nodes: 19 (use --verbose for breakdown)
success createPages - 0.056s
success Checking for changed pages - 0.001s
success createPagesStatefully - 0.094s
success Cleaning up stale page-data - 0.006s
success update schema - 0.035s
success onPreExtractQueries - 0.003s
success extract queries from components - 0.499s
success write out redirect data - 0.002s
success Build manifest and related icons - 0.102s
success onPostBootstrap - 0.113s
info bootstrap finished - 5.462s
success run static queries - 0.021s - 2/2 96.19/s
success run page queries - 0.013s - 1/1 79.77/s
success write out requires - 0.005s
success Building production JavaScript and CSS bundles - 10.390s
success Rewriting compilation hashes - 0.003s
failed Building static HTML for pages - 2.388s

 ERROR #95313 

Building static HTML failed for path "/page/2"

See our docs page for more info on this error: https://gatsby.dev/debug-html


  26 |                         body={node.excerpt}
  27 |                         tags={node.frontmatter.tags}
> 28 |                         fluid={node.frontmatter.image.childImageSharp.fluid}  
     |                                                       ^
  29 |                     />
  30 |                 ))}
  31 |                 <PaginationLinks


  WebpackError: TypeError: Cannot read property 'childImageSharp' of null

  - post-list.js:28 
    src/templates/post-list.js:28:55

  - post-list.js:19 
    src/templates/post-list.js:19:24

You are using a page query in your IndexPage component, however, you are retrieving the data using a StaticQuery component .您在 IndexPage 组件中使用 页面查询,但是,您正在使用StaticQuery组件检索数据。 Change it to:将其更改为:

import React from "react"
import { graphql, StaticQuery } from 'gatsby'; 

import Layout from "../components/layout"
import SEO from "../components/seo"
import Post from '../components/Post'; 
import Sidebar from '../components/Sidebar'; 
import { Row, Col } from 'reactstrap'; 
import PaginationLinks from '../components/PaginationLinks'; 

const IndexPage = ({data}) => {

  const postsPerPage = 5; 
  let numberOfPages 

  return (
    <Layout>
    <SEO title="home" keywords={[`procedural`, `gatsby`]}/>
    <h1 className='titles'>procedural</h1>

    <Row>
      <Col>
            <div>
              {
                data.allMarkdownRemark.edges.map(({ node }) => (
                 {node.frontmatter.image && <Post 
                  key={node.id}
                  title={node.frontmatter.title}
                  author={node.frontmatter.author}
                  date={node.frontmatter.date}
                  slug={node.fields.slug}
                  body={node.excerpt}
                  fluid={node.frontmatter.image.childImageSharp.fluid}
                  tags={node.frontmatter.tags}
                  /> }
                ))
              }
              <PaginationLinks currentPage={1} numberOfPages={numberOfPages} />
            </div>
      </Col>
      <Col md='4'>
        <Sidebar>

        </Sidebar>
      </Col>
    </Row>

    </Layout>
  )
}

const indexQuery = graphql`
query {
  allMarkdownRemark(sort: { fields: [frontmatter___date], order: DESC}
    limit: 5
    ) {
    totalCount
    edges {
      node {
        id
        frontmatter {
          title
          date
          author
          tags
          image {
            childImageSharp {
              fluid(quality: 85, maxWidth: 960) {
                ...GatsbyImageSharpFluid
              }
            }
          }
        }
        fields {
          slug
        }
        excerpt
      }
    }
  }
}
`

export default IndexPage

The data fetched using pages queries, is stored under props .使用页面查询获取的数据存储在props下。 Since in the snippet above you are destructuring props as data ( ({data}) ), you don't need to trigger another query like you were doing, your data is already stored in data .由于在上面的代码段中,您将props解构为data({data}) ),因此您不需要像之前那样触发另一个查询,您的数据已经存储在data中。 So you can loop it in the same way you were doing.所以你可以像以前一样循环它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM