I am usingGatsby with GraphQL. Getting unknown field error as follows:
GraphQL Error Encountered 2 error(s):
- Unknown field 'allBlogPost' on type 'Query'. Source: document `homeAymanDesktopFirstSrcPagesIndexJs2258072279` file: `GraphQL request`
GraphQL request:3:3
2 | {
3 | posts: allBlogPost {
| ^
4 | nodes {
- Unknown field 'blogPost' on type 'Query'.
file: /home/ayman/Desktop/first/src/templates/post.js
Here is my post.js template file:
import React from "react"
import { graphql } from "gatsby"
export default ({ data }) => {
console.log(data)
return (
<div>
<h1>{data.post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: data.post.html }} />
</div>
)
}
export const query = graphql`
query($id: String!) {
post: blogPost(id: { eq: $id }) {
title
html
}
}
`
My gatsby-node.js configuration can be found in this pastebin
My GraphiQL:
Update
After adding Asciidoc file in content/posts and content/articles , getting this error:
Cannot query field "slug" on type "BlogPost".
File: gatsby-node.js:89:16
ERROR #11321 PLUGIN
"gatsby-node.js" threw an error while running the createPages lifecycle:
Cannot read property 'posts' of undefined
TypeError: Cannot read property 'posts' of undefined
- gatsby-node.js:99
Your code is breaking in the gatsby-node.js, not in the template (at least for now).
Try using an async/await approach in your createPage API, something like:
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions
const postTemplate = path.resolve(`./src/templates/post.js`)
const postsQuery = await graphql(`
{
posts: allBlogPost {
nodes {
id
slug
}
}
}
`);
if (postsQuery.errors) {
reporter.panicOnBuild(`Error while running GraphQL query.`);
return;
}
postsQuery.data.posts.nodes.forEach( node => {
createPage({
path: node.slug,
component: postTemplate,
context: {
id: node.id,
},
})
})
It seems that you can't create your own schema properly. Ensure that your validations are correct:
if (node.internal.type === `Asciidoc`)
Related
My React Typescript app has a Context Provider DataProvider that is to read a value from a JSON file and provide it in the Context useData(). I am trying to do the read synchronously to avoid having to deal with a isLoading since this is a tiny local JSON file.
Is there a recommended way to read the JSON file synchronously inside a Context Provider?
I tried the following using node-sync, but its giving a Typescript error
Object is possibly 'undefined'.ts(2532)
on data at line
return data.find(...
Tried changing it to
return data?.find(...`
but now the error is
Property 'find' does not exist on type 'never'.ts(2339)
import React, {
createContext,
useContext,
Consumer,
Context,
ReactNode,
useMemo,
} from 'react';
import Sync from 'sync';
export interface DataProviderProps {
children: ReactNode;
}
export interface Data {
secretNumber?: string;
}
// #ts-ignore
const DataContext: Context<Data> = createContext<Data>();
export function DataProvider({ children }: DataProviderProps) {
const secretNumber = useMemo(() => {
// Read from JSON file
const contractFile =
process.env.REACT_APP_WORLD === 'main'
? '../main.json'
: '../test.json';
let data;
Sync(function () {
data = import(contractFile);
});
return data.find( // <=== TS error: Object is possibly 'undefined'. ts(2532)
({ name }: { name: string }) => name === 'elonmusk',
)?.secretNumber;
}, []);
const states = useMemo<Data>(() => {
return {
secretNumber,
};
}, [secretNumber]);
return (
<DataContext.Provider value={states}>
{children}
</DataContext.Provider>
);
}
export function useData(): Data {
return useContext(DataContext);
}
export const DataConsumer: Consumer<Data> = DataContext.Consumer;
array.find() returns undefined If no values satisfy the testing function, from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find, so just add (!) after the array.find()! fxn to ascertain a value would be returned.
sample code stub
data.find(todoCodeStubhere)!
This seems to be a relatively common problem. I am trying to generate blog post pages but am experiencing this error and the pages show a 404 on load. Which means that they are not being generated.
Here is my code for the gatsby.node.js file:
exports.createPages = async ({ graphql, useStaticQuery, actions: { createPage } }) => {
const postQuery = graphql(`
{
gcms {
posts(where: { stage: PUBLISHED }) {
id
slug
}
}
}
`);
const {
gcms: { posts },
} = useStaticQuery(postQuery);
posts.forEach(({ id, slug }) =>
createPage({
path: `/blog/${slug}`,
component: require.resolve(`./src/templates/PostPage.js`),
context: {
id: id,
slug: slug,
},
})
);
};
And my code for the blog post PostPage.js file:
/* eslint-disable react/prop-types */
import React from 'react';
import { graphql } from 'gatsby';
import Layout from "../components/layout";
//import galaxy from "../images/galaxy.jpg";
import SEO from "../components/seo";
export const postPageQuery = graphql`
query PostPageQuery($id: ID!) {
gcms {
post(where: { id: $id }) {
title
slug
excerpt
postContentMarkdown
tags
author {
name
biography
}
seo {
title
description
keywords
}
}
}
}
`;
const PostPage = ({data: {post}}) => {
return (
<Layout>
<SEO
keywords={[
`ui`,
`ux`,
]}
title="Blog" />
{post.slug}
</Layout>
);
};
export default PostPage;
There are a few things that caught my attention and may fix your issue.
The usage of useStaticQuery in your gatsby-node.js. You don't need to fetch postQuery data with the static query hook since you are using the hook outside a component.
The usage of where filter. According to GraphQL documentation, the way to filter data is by using filter filter. In addition, when filtering the filtered criteria are strings, so must be quoted.
When you pass a field via context API to your PostPage, you should avoid filter to all your gcms since your template has the information of that post, is not needed to redo the same previous query again (same than gatsby-node.js), it's not optimal. I will let it there since I don't know how is your data structured but should be refactored.
Applying it to your code should look like this.
gatsby-node.js:
exports.createPages = async ({ graphql, useStaticQuery, actions: { createPage } }) => {
const postQuery = graphql(`
{
gcms {
posts(filter: { stage: "PUBLISHED" }) {
id
slug
}
}
}
`);
let {posts}= postQuery.gcms;
posts.forEach(({ id, slug }) =>
createPage({
path: `/blog/${slug}`,
component: require.resolve(`./src/templates/PostPage.js`),
context: {
id: id,
slug: slug,
},
})
);
};
PostPage.js:
/* eslint-disable react/prop-types */
import React from 'react';
import { graphql } from 'gatsby';
import Layout from "../components/layout";
//import galaxy from "../images/galaxy.jpg";
import SEO from "../components/seo";
export const postPageQuery = graphql`
query PostPageQuery($id: ID!) {
gcms {
post(filter: { id: $id }) {
title
slug
excerpt
postContentMarkdown
tags
author {
name
biography
}
seo {
title
description
keywords
}
}
}
}
`;
const PostPage = ({data: {post}}) => {
return (
<Layout>
<SEO
keywords={[
`ui`,
`ux`,
]}
title="Blog" />
{post.slug}
</Layout>
);
};
export default PostPage;
I ended up fixing this by doing a complete recomposition of my project, with an update to the latest version of Gatsby, this with a bare bones gatsby starter, plugin by plugin. It ended up being plugin conflict issue. I'm not sure which plugin exactly it was, but most likely it was one of these:
gatsby-plugin-eslint, gatsby-plugin-offline, gatsby-plugin-root-import or possibly the prop-types NPM package.
I experienced this same issue after upgrading to the latest version of Gatsby.
Similarly to Tapha's answer, it was a plugin conflict for me. I had yet to upgrade the gatsby-source-strapi plugin. Upgrading that package to its latest available version solved the issue. Whatever your data source happens to be, I would check that it's still playing nice with Gatsby.
So, this warning/error message is very misleading, you can still use an exported query from templates, as detailed in the Gatsby documentation here.
I'm trying to build my new GatsbyJS application.
This application works well when I try in gatsby develop.
But when I tried to build, Builder can't find frontmatter variant.
It seems to be like GraphQL has no problem because I can check markdown's content in log.
What is wrong in my code?
gatsby-config.js
...
plugins: [
{
resolve: "gatsby-source-filesystem",
options: {
path: `${__dirname}/src/articles`,
name: "articles",
},
},
...
src/pages/markdown-template.js
import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/layout"
import CustomCard from "../components/ui/customcard"
import "./markdown-template.css"
export default function Template({ data }) {
console.log(data.markdownRemark)
const frontmatter = data.markdownRemark.frontmatter
const html = data.markdownRemark.html
const tags = frontmatter.tags
return (
<Layout>
<CustomCard>
<div className="article">
<h1>{frontmatter.title}</h1>
<h2>{frontmatter.updated}</h2>
<div className="tags-container">
<div className="tags">
{tags.map(tag => {
return <span className="tag">{tag}</span>
})}
</div>
</div>
<hr />
<div
className="article-body"
dangerouslySetInnerHTML={{ __html: html }}
/>
</div>
</CustomCard>
</Layout>
)
}
export const pageQuery = graphql`
query($path: String!) {
markdownRemark(frontmatter: { path: { eq: $path } }) {
html
frontmatter {
created(formatString: "YYYY-MM-DD")
updated(formatString: "YYYY-MM-DD")
path
title
tags
category
language
}
}
}
`
Console output when I tried to run gatsby build
...
success Building production JavaScript and CSS bundles - 9.682s
success Rewriting compilation hashes - 0.005s
success run queries - 9.978s - 10/10 1.00/s
[ ] 0.001 s 0/7 0% Building static HTML for pages
{
html: '<p>asdf</p>\n<h1>test</h1>',
frontmatter: {
created: '2020-01-10',
updated: '2010-01-10',
path: '/article/hello',
title: 'Hello Gatsby',
tags: [ 'Hello', 'World' ],
category: 'test',
language: 'ko'
}
}
failed Building static HTML for pages - 1.742s
ERROR #95313
Building static HTML failed for path "/markdown-template/"
See our docs page for more info on this error: https://gatsby.dev/debug-html
8 | export default function Template({ data }) {
9 | console.log(data.markdownRemark)
> 10 | const frontmatter = data.markdownRemark.frontmatter
| ^
11 | const html = data.markdownRemark.html
12 | const tags = frontmatter.tags
13 |
WebpackError: TypeError: Cannot read property 'frontmatter' of null
- markdown-template.js:10 Template
src/pages/markdown-template.js:10:43
...
I am using Gatsby to create a documentation site, using .mdx to manage contents. I have configured the gatsby-node.js and created the template. Everything path works fine, however, the index page fails to fetch results from the GraphQL query. I have cleared the cache and rebuilt the project severally. I tried a fix on Github which suggested renaming the index.js to main.js. This worked seamlessly on dev but not in prod.
Here's the gatsby-node.js file:
const {createFilePath} = require(`gatsby-source-filesystem`)
const path = require(`path`)
exports.createPages = ({actions, graphql}) => {
const {createPage} = actions
const blogPostTemplate = path.resolve('src/templates/postTemplate.js')
return(graphql(`
{
allMdx {
nodes {
frontmatter {
title
}
fields {
slug
}
}
}
}
`)).then(result => {
if(result.errors) {
throw result.errors
}
const posts = result.data.allMdx.nodes
posts.forEach(post => {
createPage({
path: post.fields.slug,
component: blogPostTemplate,
context: {
slug: post.fields.slug
}
})
})
})
}
exports.onCreateNode = ({node, actions, getNode}) => {
const { createNodeField } = actions
if(node.internal.type === `Mdx`) {
const value = createFilePath({node, getNode})
createNodeField({
name: `slug`,
node,
value
})
}
}
Here's the postTemplate.js file:
import React from 'react'
import {graphql} from 'gatsby'
import {MDXRenderer} from 'gatsby-plugin-mdx'
import Layout from '../components/Layout/Layout';
export default ({data}) => {
const {body, tableOfContents, fields} = data.mdx
return (
<Layout>
{tableOfContents}
<MDXRenderer>
{body}
</MDXRenderer>
{fields}
</Layout>
)
}
export const query = graphql`
query PostBySlug($slug: String!) {
mdx (fields: {slug: {eq: $slug}}) {
body
tableOfContents
fields {
slug
}
}
}
`
Any suggestions would be highly appreciated.
I found a solution to my issue. I discovered the index (/) page wasn't making use of the postTemplate.js. So my workaround was to copy the content of the postTemplate.js file into the index.js file. I then modified the graphql query to fetch just the / content. I don't know if this is the best solution, but it works fine now.
Use a ternary operator for your createPage path. I'm assuming your index's slug name is "index".
path: post.fields.slug === 'index' ? '/' : `/${post.fields.slug}`
I have no idea why it is happening.
I am listening to subscription postAdded which gets published every time I create a post using mutation.
import React, { Component } from 'react'
import { graphql, gql } from 'react-apollo'
class App extends Component {
componentDidMount() {
this.props.subscribeToNewPosts()
}
render() {
return (
<div>
<h1>Hello world</h1>
{console.log(this.props)}
</div>
)
}
}
const Query = gql`
query Posts {
posts {
id
title
content
author {
firstName
lastName
}
}
}
`
const Subscription = gql`
subscription postAdded {
postAdded {
id
title
content
author {
firstName
lastName
}
}
}
`
App = graphql(Query, {
name: 'posts',
props: props => {
return {
subscribeToNewPosts: () => {
return props.posts.subscribeToMore({
document: Subscription,
updateQuery: (prev, { subscriptionData }) => {
if(!subscriptionData.data) {
return prev
}
const newPost = subscriptionData.data.postAdded
console.log(newPost)
return {
...prev,
posts: [...prev.posts, newPost]
}
}
})
},
posts: props.posts
}
}
})(App)
export default App
The error:
First, this is most likely a server implementation issue. The error is likely being throw by graphql-tools that's your graphql end point.
The exact same thing happened to me while following second part of the Full-stack + GraphQL tutorial on the official blog.
While it is not necessarily the same case, what happened to me was that the tutorial exports the schema object with: export { schema } which is equivalent to export { schema: schema } instead of the usual exports as default, e.g. export default schema
In my graphql server endpoint I import with import schema from './src/schema' which was wrong because schema was exported as a sub object and not the default export. Correct import for my case should have been import { schema } from './src/schema'
TL;DR Check your server code, check your export and import statements. The error message is really misleading but it most likely has to do with module import/ export.
It could have been avoided or giving more explicit information if we were compiling using webpack instead of using babel-node like in the tutorial.