Gatsby Head API not working in production build - javascript

I am new to Gatsby. I have almost created the entire application sourcing data from my WordPress blog. Everything is working fine except the head API is not outputting any head tag in production. I am using "Add WPGraphQL SEO" plugin to get Yoast SEO data. The query returns an object named fullHead that contains all the page/post's head data.
Here is the post template code -
import React from "react"
import Layout from "../components/layouts/single-post-layout.js"
import { graphql } from "gatsby"
import HTMLReactParser from "html-react-parser"
import SinglePost from "../components/posts/single-post.js"
export const Head = ({ data }) => (
<>{HTMLReactParser(data.wpPost?.seo?.fullHead)}</>
)
const Post = ({ data }) => {
return (
<Layout post={data}>
<SinglePost post={data.wpPost} />
</Layout>
)
}
export const query = graphql`
query($id: String) {
wpPost(id: { eq: $id }) {
id
categories {
nodes {
id
name
uri
}
}
commentCount
content
date
excerpt
featuredImage {
node {
altText
localFile {
childImageSharp {
gatsbyImageData(
placeholder: BLURRED
formats: [AUTO, WEBP, AVIF]
)
}
}
}
}
slug
uri
title
tags {
nodes {
id
name
uri
}
}
author {
node {
avatar {
url
}
name
description
uri
}
}
comments {
nodes {
author {
node {
avatar {
url
}
name
url
}
}
id
content
date
}
}
seo {
fullHead
title
breadcrumbs {
url
text
}
}
}
}
`
export default Post
The above code works fine in the development build but not in the production build. What am I doing wrong here?

Related

How to use gatsby-image with an image url?

This is how the image is shown in index.js and it works . The imgUrl is basically an image url .
import React from 'react';
import { graphql } from 'gatsby';
export const query = graphql`
{
test {
imgUrl
}
}
`;
export default function Home({ data }) {
console.log(data);
return (
<div>
Hello world!
<img src={data.test.imgUrl} />
</div>
);
}
I want to use gatsby image like this :
childImageSharp {
fixed(width: 600) {
...GatsbyImageSharpFixed
}
}
But since it's not stored locally how can I use gatsby image with the url of an image ?
I solved the issue by installing a plugin named gatsby-plugin-remote-images
{
resolve: `gatsby-plugin-remote-images`,
options: {
nodeType: 'Test', // Created Node type name
imagePath: 'imgUrl' // The image url name in test node type
}
}
It downloads the imgUrl url and creates a localImage field on Test node type so we can query it inside gatsby like this in index.js file :
import Img from 'gatsby-image';
export const query = graphql`
{
test {
localImage {
childImageSharp {
fluid {
...GatsbyImageSharpFluid
}
}
}
}
}
`;
export default function Home({ data }) {
return (
<div>
Hello world!
<Img fluid={data.test.localImage.childImageSharp.fluid} />
</div>
);
}

Getting an "Exported queries are only executed for Page components." in Gatsby when trying to generate pages

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.

Gatsby: Index page "/" fails to load when using MDX, other path loads

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}`

How to use GraphQL queries in a container class component

👋
My current GatsbyJS project is a one pager with a carousel and some other content.
Background
The carousel should be filled with information about some products. My goal is to let the carousel build itself by iterating through all markdown files, picking the ones with these three lines at the top of the file:
---
type: product
---
So I've created a CarouselContainer (class component) and a Carousel component (functional component). The Container should load the markdown via GraphQL query and pass the resulting products object to it's nested component. Then the component should map over the object and create the carousel.
But there are also other markdown files for menu lists, text modals and so on. They have the type: page. I thought preparing a few GraphQL queries would be the solution. But it turned out to be more difficult than expected...
The container component is a class component, so I am not able to call the query directly in it (https://github.com/gatsbyjs/gatsby/issues/3991#issuecomment-364939030).
Then I thought putting multiple queries into the pages/index.js could be the solution.
export const indexQuery = graphql`
query IndexQuery {
allMarkdownRemark(filter: {frontmatter: {type: {eq: "page"}}}) {
edges {
node {
frontmatter {
title
text
}
}
}
}
}
`
export const productsQuery = graphql`
query ProductsQuery {
allMarkdownRemark(filter: {frontmatter: {type: {eq: "product"}}}) {
edges {
node {
id
frontmatter {
title
content
}
}
}
}
}
`
Nope again. Using GraphQL fragments should be a solution...
Q Can someone tell me how to prepare fragments for that purpose and/or have another idea how to get the markdown content right into my container?
Thanks for reading.
You're not too far off. GraphQL supports multiple discrete nodes being queried in the same query:
export const query = graphql`
{
products: allMarkdownRemark(
filter: { frontmatter: { type: { eq: "product" } } }
) {
edges {
# ...
}
}
pages: allMarkdownRemark(
filter: { frontmatter: { type: { eq: "pages" } } }
) {
edges {
# ...
}
}
}
`
Note that I've used aliases to fetch the same initial node (allMarkdownRemark) with separate filters in the same GraphQL query. This will result in data.products and data.pages being passed into your default exported React component.
To clean this up, you can use fragments, allowing you to colocate your products query in your Carousel file:
In carousel.js (or whatever file houses your Carousel component):
export const query = graphql`
fragment Products on Query {
products: allMarkdownRemark(
filter: { frontmatter: { type: { eq: "product" } } }
) {
edges {
# ...
}
}
}
`
Then in your page file:
export const query = graphql`
{
pages: allMarkdownRemark(
filter: { frontmatter: { type: { eq: "pages" } } }
) {
edges {
# ...
}
}
...Products
}
`
Note: if you're using Gatsby 1.x you'll need to change the on Query portion of the fragment to on RootQueryType.
Assuming you're using Gatsby v2, you can also use StaticQuery instead of combining the query into one. This is particularly useful if your pages have no bearing on the Carousel of products.
import React from "react";
import { graphql, StaticQuery } from "gatsby";
class Carousel extends React.Component {
// ...
}
export default props => (
<StaticQuery
query={graphql`
products: allMarkdownRemark(
filter: { frontmatter: { type: { eq: "product" } } }
) {
edges {
# ...
}
}
`}
render={({ products }) => <Carousel products={products} {...props} />}
/>
);

Apollo Client subscriptions must provide schema

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.

Categories

Resources