gatsby-paginate icon indicating copy to clipboard operation
gatsby-paginate copied to clipboard

Using Gatsby-Image with Gatsby-Paginate

Open aaronaustin opened this issue 7 years ago • 4 comments

I managed to get gatsby-paginate working, but when I include

image {
  sizes(maxWidth: 400) {
    ...GatsbyContentfulSizes
  }
}

in my graphql query in gatsby-node.js, my development build fails. I've tried to include a graphql query in my template, but I get this error: GraphQLError: Variable "$id" of required type "String!" was not provided.

Everything works when I remove the image sizes query above. Is there a way to get gatsby-image working with pagination? I've been through the examples, but haven't found one yet.

Here's the relevant gatsby-node section. Thanks.

.then(() => {
        graphql(
          `
            {
              allContentfulSongs(limit: 1000) {
                edges {
                  node {
                    id
                    slug
                    title
                    path
                    image {
                      id
                      #sizes(maxWidth: 200) {
                      #  ...GatsbyContentfulSizes
                      #}
                    }
                  }
                }
              }
            }
          `
        ).then(result => {
          if (result.errors) {
            reject(result.errors)
          }
          const categoryTemplate = path.resolve(`./src/templates/category.js`)
          createPaginatedPages({
            edges: result.data.allContentfulSongs.edges,
            createPage: createPage,
            pageTemplate: categoryTemplate,
            pageLength: 5,
            pathPrefix: "songs",
            buildPath: (index, pathPrefix) => index > 1 ? `${pathPrefix}/${index}` : `/${pathPrefix}`
          })
          _.each(result.data.allContentfulSongs.edges, edge => {
            createPage({
              path: `${edge.node.slug}/`,
              component: slash(categoryTemplate),
              context: {
                id: edge.node.id,
              },
            })
          })

aaronaustin avatar Feb 11 '18 02:02 aaronaustin

I'm having the same issue I guess, where [{"message":"Unknown fragment \"GatsbyContentfulSizes\".","locations":[{"line":9,"column":24}]}] the fragment of GatsbyContentfulSizes is not recognized properly.

I solved it by changing:

image {
                  sizes(maxWidth: 380) {
                    ...GatsbyContentfulSizes
                  }
                }

to

image {
                  sizes(maxWidth: 380) {
                    base64
                    aspectRatio
                    src
                    srcSet
                    sizes
                  }
                }

by just looking up the contents of the fragment. Still, this is not optimal.

danniehakan avatar Feb 13 '18 10:02 danniehakan

@aaronaustin and @danniehakan I know this is an old issue (I was just knocking around this repo)...

Anyways, GraphQL fragments like this are unavailable to queries performed in the gatsby-node context.

The trick is to use the least amount of data in the createPage call and move the image, and other data, retrieval to the template/component that you're passing in. (i.e. categoryTemplate would have a Page Query that uses the data passed in from the pageContext to get what it needs to be built.)

elskwid avatar Jan 03 '19 21:01 elskwid

@elskwid could you explain that in a piece of code please?

rsurjano avatar Mar 26 '19 18:03 rsurjano

@rsurjano What @elskwid is suggesting is to not pass more data than necessary into the template/component through context but rather restrict yourself to identifiers that provide just enough information so that the template/component can then query for the required data itself.

A simple example would be links to the next and previous post at the end of a blog post to keep your site's visitors reading. You shouldn't query for all the data you need about the next and previous post (such as url, title, featured image, excerpt, etc.) in gatsby-node and pass that into context but instead just pass the post slugs or IDs which postTemplate.js can then use to query for all required data. This is how it would look in code:

gatsby-node.js

  posts.edges.forEach(({ node }, index, arr) => {
    const nextSlug = index === 0 ? `` : arr[index - 1].node.frontmatter.slug
    const prevSlug =
      index === arr.length - 1 ? `` : arr[index + 1].node.frontmatter.slug
    const slug = node.frontmatter.slug
    createPage({
      path: `/blog` + slug,
      component: postTemplate,
      context: { slug, nextSlug, prevSlug },
    })
  })
}

postTemplate.js

export const query = graphql`
  fragment postFields on MarkdownRemark {
    frontmatter {
      title
      slug
      date(formatString: "MMM DD, YYYY")
      tags
      ...featuredImage
    }
    timeToRead
    excerpt(pruneLength: 200)
    html
  }
  query($slug: String!, $prevSlug: String!, $nextSlug: String!) {
    post: markdownRemark(frontmatter: { slug: { eq: $slug } }) {
      ...postFields
    }
    next: markdownRemark(frontmatter: { slug: { eq: $nextSlug } }) {
      ...postFields
    }
    prev: markdownRemark(frontmatter: { slug: { eq: $prevSlug } }) {
      ...postFields
    }
  }
`

janosh avatar Mar 26 '19 18:03 janosh