Gatsby not generating correct static HTML files

All we need is an easy explanation of the problem, so here it is.

I am working on a Gatsby based website which is so far going well in development. Running into an issue though when building for production whereby we do not get any static html in the various page index files and instead it looks like Gatsby is going to attempt to inject the page from javascript which is contra to our expectation.

I have seen some posts related to the Gatsby offline plugin which I have disabled but this has not resolved the issue. Our pages contain no static html output and the meta content I would expect react-helmet to inject is also not present.

Are there any recommendations on how to debug the build to see what may be resetting the static output and replacing it with dynamically generated Gatsby bootstrap code.

Plugins being used for the site are:

 plugins: [
    `gatsby-plugin-react-helmet`,
    `gatsby-transformer-sharp`,
    `gatsby-plugin-sharp`,
    {
      resolve: `gatsby-plugin-manifest`,
      options: {
        name: `gatsby-starter-default`,
        short_name: `starter`,
        start_url: `/`,
        background_color: `#663399`,
        theme_color: `#663399`,
        display: `minimal-ui`,
        icon: `src/images/favicon.png`, // This path is relative to the root of the site.
      },
    },
    `gatsby-transformer-json`,
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: 'data',
        path: `${__dirname}/src/data/`,
      },
    },
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `images`,
        path: `${__dirname}/src/images`,
      },
    },
    `gatsby-plugin-styled-components`,
    // this (optional) plugin enables Progressive Web App + Offline functionality
    // To learn more, visit: https://gatsby.dev/offline
    //`gatsby-plugin-offline`,
    {
      resolve: 'gatsby-plugin-root-import',
      options: {
        src: path.join(__dirname, 'src'),
        pages: path.join(__dirname, 'src/pages'),
        images: path.join(__dirname, 'src/images'),
      },
    },
    `gatsby-plugin-transition-link`,
    {
      resolve: `gatsby-plugin-google-analytics`,
      options: {
        trackingId: process.env.GOOGLE_ANALYTICS_TRACKING_ID,
        head: true,
      },
    },
  ]

Thanks in advance for any pointers

How to solve :

I know you bored from this bug, So we are here to help you! Take a deep breath and look at the explanation of your problem. We have many solutions to this problem, But we recommend you to use the first method because it is tested & true method that will 100% work for you.

Method 1

Had the same problem.

It appears that PersistGate breaks ssr. Since ssr is done during build time and we don’t need it there, we can check our environment.

Changing wrap-with-provider.js from 1. to 2. did the trick

import React from "react"
import { Provider } from "react-redux"
import { PersistGate } from 'redux-persist/integration/react'

import {store, persistor} from "./src/redux/store"

1:

export default ({ element }) => (
  <Provider store={store}>
    <PersistGate loading={null} persistor={persistor}>
      {element}
    </PersistGate>
  </Provider>
)

2:

export default ({ element }) => {
  if (typeof window === "undefined") {
    return (
      <Provider store={store}>
        {element}
      </Provider>
    )
  }
  return (
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        {element}
      </PersistGate>
    </Provider>
  )
}

Method 2

I managed to track the issue down to a conflict between Redux (redux-persist) and Gatsby SSR – specifically related to the use of a PersistGate element. The following is a pretty common pattern where you have the following in gatsby-browser and gatsby-ssr

export { default as wrapRootElement } from 'src/store/ReduxWrapper';

Which ReduxWrapper would contain the following:

export default ({ element }) => (
  <Provider store={store}>
    <PersistGate loading={<h2>Loading...</h2>} persistor={persistor}>
      {element}
    </PersistGate>
  </Provider>
);

This unfortunately breaks SSR which can be resolved by creating a different ReduxWrapper that does not depend on . Assuming this is called ReduxSSRWrapper then gatsby-ssr will be changed to:

export { default as wrapRootElement } from 'src/store/ReduxSSRWrapper';

and ReduxSSRWrapper will contain the following which is basically a removal of PersistGate:

export default ({ element }) => (
  <Provider store={store}>
    {element}
  </Provider>
);

Note: Use and implement method 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply