Gatsy page query fails to work when using named export at the end of the page. Why? - graphql

I have the following page template in Gatsby.
import React from 'react';
import { graphql } from 'gatsby';
import Layout from '../components/layout';
const PageTemplate = props => {
const { wordpressPage: currentPage } = props.data;
return (
<Layout>
<h1 dangerouslySetInnerHTML={{ __html: currentPage.title }} />
<div dangerouslySetInnerHTML={{ __html: currentPage.content }} />
</Layout>
);
};
export const pageQuery = graphql`
query($id: String!) {
wordpressPage(id: { eq: $id }) {
title
content
date(formatString: "MMMM DD, YYYY")
}
site {
id
siteMetadata {
title
}
}
}
`;
export default PageTemplate;
Which works as expected (taken from tutorial), however I tend to prefer to do all my exporting at the end of the page like so:
import React from 'react';
import { graphql } from 'gatsby';
import Layout from '../components/layout';
const PageTemplate = props => {
const { wordpressPage: currentPage } = props.data;
return (
<Layout>
<h1 dangerouslySetInnerHTML={{ __html: currentPage.title }} />
<div dangerouslySetInnerHTML={{ __html: currentPage.content }} />
</Layout>
);
};
const pageQuery = graphql`
query($id: String!) {
wordpressPage(id: { eq: $id }) {
title
content
date(formatString: "MMMM DD, YYYY")
}
site {
id
siteMetadata {
title
}
}
}
`;
export default PageTemplate;
export { pageQuery }
However this fails to work - props.data is undefined. It's a subtle difference but why would this cause the pageQuery to not execute?

I believe pageQuery has to be exported before PageTemplate because it is used by it: that's where it gets its props.data from, which explains why you are getting undefined when exporting it after.

This answer is an additional explanation to #hexangel616 who mentioned the order of exports matters:
I believe pageQuery has to be exported before PageTemplate because it is used by it.
Your exported GraphQL queries have a special role in the gatsby build process. From the docs:
At a high level, what happens during the whole bootstrap and build
process is:
Node objects are sourced from whatever sources you defined in gatsby-config.js with plugins as well as in your gatsby-node.js file
A schema is inferred from the Node objects
Pages are created based off JavaScript components in your site or in installed themes
GraphQL queries are extracted and run to provide data for all pages
Static files are created and bundled in the public directory
TLDR: In order for gatsby to build properly all your graphql exports have to be in order.

Related

Gatsby and GraphQL: query pdf file using <StaticQuery/>

I am very new to graphQL.
Inside src I have a data folder which contains a pdf named my_cv.pdf
Problem: I am unable to either load it in the browser or able to download it. I get an error There's not a page yet at /data.file.publicURL
gatsby.config.js
{
resolve: "gatsby-source-filesystem",
options: {
path: `${__dirname}/src/data/`,
name: "data",
},
},
my hero component
this is inside the render() of the class component.
<Resume href="data.file.publicURL" target="_blank">
Download Resume
</Resume>
this is how I am querying it.
<StaticQuery
query={graphql`
query {
pdf: file(name: { eq: "my_cv.pdf" }) {
name
extension
publicURL
}
</StaticQuery>
The problem is that you are aliasing file as pdf, hence the nesting should be:
<Resume href="data.pdf.publicURL" target="_blank">
Download Resume
</Resume>
If you use StaticQuery I think you may want to use something like:
import React from "react";
import { StaticQuery, graphql } from "gatsby";
export default function Header() {
return (
<StaticQuery
query={graphql`
query {
pdf: file(name: { eq: "my_cv.pdf" }) {
name
extension
publicURL
}
}
`}
render={(data) => (
<Resume href="data.pdf.publicURL" target="_blank">
Download Resume
</Resume>
)}
/>
);
}
If you use useStaticQuery hook you can detach the logic from Resume of the StaticQuery component
import React from "react";
import { useStaticQuery, graphql } from "gatsby";
export default function Header() {
const data = useStaticQuery(graphql`
query {
pdf: file(name: { eq: "my_cv.pdf" }) {
name
extension
publicURL
}
}
`);
return (
<Resume href="data.pdf.publicURL" target="_blank">
Download Resume
</Resume>
);
}
In both cases, be sure that the GraphQL query is returning valid data.

I want to create a category page. I am using Gatsby.js, GraphQL and Strapi

I want to create a category page. I am using Gatsby.js, GraphQL and Strapi.
Probably filter is not working.
But I don't know how to solve it.
{strapiCategory.slug}.js
import * as React from "react";
import { graphql } from "gatsby";
import { Helmet } from "react-helmet";
import Layout from "../../components/Layout";
import PostList from "../../components/PostList";
import *as styles from "./{MicrocmsCategory.slug}.module.css";
const CategoryPage = (props) => {
const categories = props.data.strapiCategory;
const posts = props.data.allStrapiPost.nodes;
return (
<Layout>
<Helmet>
<title>{categories.name}</title>
<meta name="description" content={categories.name} />
</Helmet>
<p className={styles.categoryName}> {categories.name}</p>
<PostList posts={posts} />
</Layout>
);
};
export const query = graphql`
query ($slug: String!){
strapiCategory (slug: { eq: $slug }){
name
slug
}
allStrapiPost(filter:{categories:{slug:{ eq: $slug }}}){
nodes {
slug
title
content
thumbnail
published_at(formatString: "YYYY.MM.DD hh:mm")
categories {
slug
name
}
}
}
}
`;
export default CategoryPage;
error code
ERROR #98123 WEBPACK
Generating development JavaScript bundle failed
/Users/t/WebDevelopment/xxxxxx/src/pages/categories/{xxxx.slug}.js
29:39 error Field "slug" is not defined by type
"StrapiPostCategoriesFilterListInput" graphql/template-strings
✖ 1 problem (1 error, 0 warnings)
failed Re-building development bundle - 0.177s ERROR in
/Users/t/WebDevelopment/xxxx/src/pages/categories/{xxxxxx.slug}.js
29:39 error Field "slug" is not defined by type
"StrapiPostCategoriesFilterListInput"
The link is working fine.
It will be displayed.
const categories = props.data.strapiCategory;
<title>{categories.name}</title>.
This will not be displayed.
const posts = props.data.allStrapiPost.nodes;
<PostList posts={posts} />
Field "slug" is not defined by type
"StrapiPostCategoriesFilterListInput" graphql/template-strings
It's quite self-explanatory. In your case, slug is under categories (collection/nested route in FileSystem API).
Your {xxxxx.slug}.js should become:
{xxxxx.categories.slug}.js
Can you try using where instead of filter in graphql
allStrapiPost(where:{categories:{slug:{ eq: $slug }}}){

How do I use sharp image with Strapi 4 and Gatsby 4

I'm want to use images from my Strapi V4 local backend to my Gatsby 4 using sharp image processing.
I was able to with Strapi 3 + Gatsby 3, but have recently upgraded to Strapi 4 and Gatsby 4 to avoid future deprecation.
This is my gatsby-config.js:
plugins: [
"gatsby-plugin-sass",
"gatsby-plugin-image",
"gatsby-plugin-sharp",
"gatsby-transformer-sharp",
{
resolve: "gatsby-source-graphql",
options: {
// Arbitrary name for the remote schema Query type
typeName: "STRAPI",
// Field under which the remote schema will be accessible. You'll use this in your Gatsby query
fieldName: "strapi",
// Url to query from
url: "http://localhost:1337/graphql",
},
}
]
This is a file (page within my gatsby site) i've been testing on, it doesn't work.
import React from "react";
import { graphql } from "gatsby"
import { GatsbyImage, getImage } from "gatsby-plugin-image"
const Test = ({ data }) => {
const image = getImage(strapi.food.data.attribute.thumbnail.data.attribute)
return (
<div>
<GatsbyImage image={image} alt={"Come on!"} />
</div>
)
}
export const pageQuery = graphql`
query FoodQuery {
strapi {
food(id: "67") {
data {
attributes {
name
thumbnail {
data {
attributes {
childImageSharp {
gatsbyImageData(width: 200)
}
}
}
}
}
}
}
}
}
`
export default Test;
The error I keep getting is.
25:17 error Cannot query field "childImageSharp" on type "STRAPI_UploadFile" graphql/template-strings
I've tried many things. I've checked to see if I can at least pull text and number fields, I can, all of them even attributes in the thumbnails object like createdAt.
I've checked to see if permissions are correct, and they seem fine - find, fineOne are both checked for the content-type and upload.
I've tried to query the uploadFile. And tried to pull food items one at a time and as a array/list of foods.
I've tried changing where I've placed childImageSharp as well as moving brackets around.
Edit: This is my GraphiQl sandbox with everything I can gather.

How to get 'Last Update Date' of a blog post in GATSBY.js

Hello I'm not a dev so may the question will be easy for you guys. I used the advance starter from gatsby site. The blog is working perfect but I need to provide the LAST UPDATED time under my title. Searched for some solutions but none of them worked. Could you Provide some help?
gatsby-node.js
exports.onCreateNode = ({ node, getNode, actions }) => {
const { createNodeField } = actions;
if (node.internal.type !== 'MarkdownRemark') {
return;
}
const fileNode = getNode(node.parent);
createNodeField({
node,
name: 'modifiedTime',
value: fileNode.mtime
});
};
`````````````````````````
PostListing.jsx
class PostListing extends React.Component {
getPostList() {
const postList = [];
this.props.postEdges.forEach(postEdge => {
postList.push({
path: postEdge.node.fields.slug,
tags: postEdge.node.frontmatter.tags,
cover: postEdge.node.frontmatter.cover,
title: postEdge.node.frontmatter.title,
date: postEdge.node.fields.date,
excerpt: postEdge.node.excerpt,
timeToRead: postEdge.node.timeToRead,
modifiedTime:postEdge.node.modifiedTime
});
});
return postList;
}
render() {
const postList = this.getPostList();
return (
<div className='posts'>
{/* Your post list here. */
postList.map(post => (
<Fragment>
<div className='singlePost__date'>
<h4 style={{color:'white'}}> {post.modifiedTime}</h4>
</div>
<div className='singlePost__Title'>
<Link classname='singlePost' to={post.path} key={post.title}>
<h1 className='singlePost__title'>{post.title}</h1>
</Link>
</div>
</Fragment>
))}
</div>
);
}
}
export default PostListing;
I expect something like
TITLE
last updated : 3/2/2019
You can use information stored in Git to get the latest time when a file was modified.
1st approach
Track it manually, but this can be error-prone if you forget to edit the modified time. So I would recommend that as the last option if you can't get others to work.
2nd approach
You can edit your gatsby-node.js to pull information from Git like so:
const { execSync } = require("child_process")
exports.onCreateNode = ({ node, actions }) => {
// ...
if (node.internal.type === "MarkdownRemark") {
const gitAuthorTime = execSync(
`git log -1 --pretty=format:%aI ${node.fileAbsolutePath}`
).toString()
actions.createNodeField({
node,
name: "gitAuthorTime",
value: gitAuthorTime,
})
}
// ...
}
Then, in your template, you can fetch it:
query($slug: String!) {
markdownRemark(fields: { slug: { eq: $slug } }) {
# ...
fields {
gitAuthorTime
}
# ...
}
}
And, finally, use it in JSX like so:
import React from "react"
const BlogPost = (props) => {
const { gitAuthorTime } = props.data.markdownRemark.fields
render(<p>Updated at: ${gitAuthorTime}</p>)
}
export default BlogPost
3rd approach
Similar to the previous one but it uses a plugin gatsby-transformer-info. It does a similar thing as in the 2nd approach, but you need to access the modified time differently this time. Like so:
query($slug: String!) {
markdownRemark(fields: { slug: { eq: $slug } }) {
# ...
parent {
... on File {
fields {
gitLogLatestDate
}
}
}
# ...
}
}
I wrote more about this in my blog post "Add Updated At To Your Gatsby Blog" if you want to check it out.
Edit: The answer below is actually wrong, since File. modifiedTime is the modifiedTime of the markdown file itself & not the modifiedTime for your content. For example, if you deploy your blog on say, Netlify, then the modifiedTime of your files there will be different than in your local environment.
I think the right answer is to track it separately. If you're using a CMS like NetlifyCMS, you can create a field that automatically update the date/time on every edit.
Wherever you're querying for your markdown files, you can use the below field:
query {
allMarkdownRemark {
edges {
node {
frontmatter { /* other stuff */ }
parent {
... on File {
modifiedTime(formatString: "MM/DD/YYYY")
}
}
}
}
}
}
And access it in your via postEdge.node.parent.modifiedTime

ButterCMS: Unknown field on RootQueryType

Hello Im trying to query data into Gatsby from ButterCMS by following the documentation in gatsby-source-buttercms(https://www.gatsbyjs.org/packages/gatsby-source-buttercms/#gatsby-source-buttercms). But got the error "unknown field allButterJob on RootQueryType". I dont know what i did wrong. Someone please take a look at this for me. Here's my gatsby-config.js:
module.exports = {
siteMetadata: {
title: 'Gatsby Default Starter',
},
plugins: [
'gatsby-plugin-react-helmet',
{
resolve: 'gatsby-source-buttercms',
options: {
authToken: '2a926fdcab34e736332a54e24649cedbaf5d0e89',
contentFields: {
keys: [ // Comma delimited list of content field keys.
'job',
'news'
],
test: 0 // Optional. Set to 1 to enable test mode for viewing draft content.
}
}
}
],
}
Here's where i made the query:
import React from 'react'
import Link from 'gatsby-link'
import HeaderlineSection from '../components/headerlineSection'
import FeatureSection from '../components/featureSection'
import TeamSection from '../components/teamSection'
import NewsSection from '../components/newsSection'
import CareerSection from '../components/careerSection'
const IndexPage = ({data}) => (
<div>
<HeaderlineSection />
<FeatureSection />
<TeamSection />
<NewsSection />
<CareerSection />
{console.log(data)}
</div>
)
export default IndexPage
export const query = graphql`
query IndexPageQuery{
allButterJob{
edges{
node{
id
title
}
}
}
}
`
RootQueryType is the top level “item” in your GraphQL schema (Gatsby v1 sets this up). So the relevant part of the error here is “unknown field allButterJob”, which is pretty self explanatory: the field/type you're trying to query doesn't exist at the top level.
It's likely that it's there under a different name. Usually I hop into Graphiql (localhost:8000/___graphql if you're running gatsby develop under the standard port), where you will see something like this in the sidebar (click on the Docs link if it isn't showing):
From here you can click on “Query” to drill down into it. (Note that this screenshot is from a Gatshy v2 app, so instead of RootQueryType it's just listed as Query.) That'll pull up a list of the fields available on Query (or in your case, RootQueryType) that looks something like this:
In this example, allSitePage is a top-level field available to query like this:
query AnythingYouLikeHere {
allSitePage {
edges {
node {
path
}
}
}
}

Resources