gatsbyjs / gatsby

The best React-based framework with performance, scalability and security built in.
https://www.gatsbyjs.com
MIT License
55.29k stars 10.31k forks source link

[gatsby-source-wordpress] [gatsby-plugin-sharp] Race condition where Gatsby tries to query image before image has finished processing #7479

Closed lesliecdubs closed 6 years ago

lesliecdubs commented 6 years ago

Description

It seems that there may be a race condition where Gatsby tries to query images coming in from WordPress before the images have finished processing (using gatsby-plugin-sharp and gatsby-image). Have confirmed that the image(s) in question exist in the Wordpress admin.

The build succeeds, but then we get the in-browser error: Uncaught TypeError: Cannot read property 'childImageSharp' of null.

Steps to reproduce

  1. Upload media file to hero field in WordPress
  2. Query the hero using GatsbyImageSharpSizes with the fragment:
export const HeroFragment = graphql`
  fragment HeroFragment on wordpress__wp_hero {
    wordpress_id
    image {
      guid {
        alt_text
        localFile {
          childImageSharp {
            hero: sizes(maxWidth: 2880) {
              ...GatsbyImageSharpSizes
            }
          }
        }
      }
    }
  }
`
  1. Normalize the hero data by running the query result through this function:
export const normalizeHero = hero => ({
  image: hero.guid.localFile.childImageSharp.hero,
  imageAlt: hero.image.guid.alt_text
})
  1. Try to read from the normalized data in a view, but get error in the browser: Uncaught TypeError: Cannot read property 'childImageSharp' of null. The error traces back to the guid line in the HeroFragment query. Printing out the value of hero.guid.localFile.childImageSharp.hero returns null.

Expected result

The query hero.guid.localFile.childImageSharp.hero should return the image object instead of null.

Actual result

Receive this error in the browser: Uncaught TypeError: Cannot read property 'childImageSharp' of null. Error traces back to the guid line in the HeroFragment query.

Bandaid fix

To fix, we added a line to the query to capture the image source_url, then imported get from lodash and updated the image var in our normalize function as follows:

image: get(hero.image, 'guid.localFile.childImageSharp.hero', defaultImg(hero.image.guid.source_url))

It will now grab the source_url of the image if the guid object returns null, which is not the desired behavior but does stop the build from erroring in the browser.

Environment

System: OS: macOS High Sierra 10.13.6 CPU: x64 Intel(R) Core(TM) i5-5257U CPU @ 2.70GHz Shell: 3.2.57 - /bin/bash Binaries: Node: 8.9.1 - /usr/local/bin/node Yarn: 1.3.2 - /usr/local/bin/yarn npm: 5.5.1 - /usr/local/bin/npm Browsers: Chrome: 68.0.3440.106 Firefox: 61.0.1 Safari: 11.1.2 npmPackages: gatsby: ^1.9.270 => 1.9.277 gatsby-image: ^1.0.54 => 1.0.54 gatsby-link: ^1.6.39 => 1.6.46 gatsby-plugin-emotion: ^1.1.17 => 1.1.17 gatsby-plugin-netlify: ^1.0.21 => 1.0.21 gatsby-plugin-node-fields: ^1.0.0 => 0.0.6 gatsby-plugin-react-helmet: ^2.0.10 => 2.0.11 gatsby-plugin-react-svg: ^1.1.1 => 1.1.1 gatsby-plugin-sharp: ^1.6.48 => 1.6.48 gatsby-source-filesystem: ^1.5.39 => 1.5.39 gatsby-source-wordpress: ^2.0.93 => 2.0.93 gatsby-transformer-sharp: ^1.6.27 => 1.6.27 npmGlobalPackages: gatsby-cli: 1.1.50 gatsby: 0.12.28

File contents (if changed)

gatsby-config.js:

const toArray = value => Array.isArray(value) ? value : [value]
const boolToArray = value => Array.isArray(value) ? value : []

const locationField = [
  {
    name: 'locations',
    transformer: boolToArray
  }
]

const articleFields = [
  {
    name: 'sections',
    transformer: toArray
  }, {
    name: 'services',
    transformer: boolToArray
  }, {
    name: 'featured',
    transformer: value => value === '1'
  }
]

module.exports = {
  siteMetadata: {
    title: 'HKS',
  },
  plugins: [
    {
      resolve: "gatsby-source-wordpress",
      options: {
        baseUrl: "CLIENT-URL.wpengine.com",
        protocol: "http",
        hostingWPCOM: false,
        useACF: true,
        auth: {},
        verboseOutput: true,
        perPage: 100,
        concurrentRequests: 50,
        excludedRoutes: ["/*/*/comments", "/yoast/**"]
      },
    }, {
      resolve: `gatsby-source-filesystem`,
      options: {
        name: `img`,
        path: `${__dirname}/src/assets/images/`
      }
    }, {
      resolve: `gatsby-plugin-emotion`,
      options: {}
    }, {
      resolve: 'gatsby-plugin-react-svg',
      options: {
        include: /assets\/images\/inline-svgs/
      }
    },
    'gatsby-plugin-react-helmet',
    'gatsby-plugin-sharp',
    'gatsby-transformer-sharp',
    {
      resolve: `gatsby-plugin-netlify`,
      options: {
        headers: {
          "/sw.js": [
            "Cache-Control: no-cache",
          ]
        },
        mergeLinkHeaders: false,
        mergeCachingHeaders: false
      },
    },
    {
      resolve: 'gatsby-plugin-node-fields',
      options: {
        descriptors: [
          {
            predicate: node => node.type === 'hero',
            fields: [
              {
                name: 'video',
                transformer: value => value || {guid: {}}
              }
            ]
          }, {
            predicate: ({type}) => type === 'people',
            fields: locationField
          }, {
            predicate: ({type}) => type === 'article' || type === 'research' || type === 'external_link' || type === 'people',
            fields: articleFields
          }, {
            predicate: node => node.type === 'case_study',
            fields: [
              ...articleFields,
              {
                name: 'related_content',
                transformer: value => toArray(value || undefined)
              }
            ]
          }, {
            predicate: node => node.type === 'panel',
            fields: [
              {
                name: 'acf',
                transformer: value => ({
                  text: value.text || '',
                  subhead: value.subhead || '',
                  video: value.video || '',
                  image: value.image || '',
                  image_caption: value.image_caption || '',
                  pull_quote: value.pull_quote || '',
                  curated_content: value.curated_content || []
                })
              }
            ]
          }
        ]
      }
    }
  ]
}

package.json:

{
  "dependencies": {
    "babel-polyfill": "^6.26.0",
    "core-js": "^2.5.7",
    "emotion": "^9.2.4",
    "emotion-normalize": "^7.0.1",
    "emotion-server": "^9.2.4",
    "focus-visible": "^4.1.4",
    "gatsby": "^1.9.270",
    "gatsby-image": "^1.0.54",
    "gatsby-link": "^1.6.39",
    "gatsby-plugin-emotion": "^1.1.17",
    "gatsby-plugin-netlify": "^1.0.21",
    "gatsby-plugin-node-fields": "^1.0.0",
    "gatsby-plugin-react-helmet": "^2.0.10",
    "gatsby-plugin-react-svg": "^1.1.1",
    "gatsby-plugin-sharp": "^1.6.48",
    "gatsby-source-wordpress": "^2.0.93",
    "gatsby-transformer-sharp": "^1.6.27",
    "imagesloaded": "^4.1.4",
    "intersection-observer": "^0.5.0",
    "jest-emotion": "9.2.6",
    "lodash": "^4.17.10",
    "object-fit-images": "^3.2.3",
    "prop-types": "^15.6.2",
    "react-emotion": "^9.2.4",
    "react-helmet": "^5.2.0",
    "react-required-if": "^1.0.3",
    "react-scrollchor": "^6.0.0",
    "react-sticky": "5.0.8",
    "savnac-breakpoint": "^2.0.11",
    "ua-parser-js": "^0.7.18"
  },
  "keywords": [
    "gatsby"
  ],
  "license": "MIT",
  "scripts": {
    "build": "gatsby build",
    "start": "gatsby develop",
    "format": "prettier --write 'src/**/*.js'",
    "test": "jest"
  },
  "devDependencies": {
    "babel-core": "^6.26.3",
    "babel-preset-stage-0": "^6.24.1",
    "enzyme": "^3.3.0",
    "enzyme-adapter-react-15": "^1.0.5",
    "gatsby-source-filesystem": "^1.5.39",
    "jest": "^23.2.0",
    "prettier": "^1.12.0",
    "react-test-renderer": "^15.6.2"
  },
  "repository": {
    "type": "git",
  },
  "jest": {
    "setupTestFrameworkScriptFile": "<rootDir>/config/jest/setup.js",
    "setupFiles": [
      "<rootDir>/config/jest/globals.js"
    ],
    "testMatch": [
      "<rootDir>/src/**/?(*.)(spec|test).{js,jsx,mjs}"
    ],
    "moduleNameMapper": {
      "^.*\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/__mocks__/fileMock.js",
      "^.*\\.scss$": "<rootDir>/__mocks__/styleMock.js"
    }
  },
  "babel": {
    "presets": [
      "env",
      "react",
      "stage-0"
    ],
    "plugins": [
      "emotion"
    ]
  }
}
thebigredgeek commented 6 years ago

Hey @lesliecdubs , thanks for the issue writeup! Is there any way you could throw together a quick-n-dirty reproduction repo and paste a link here?

kakadiadarpan commented 6 years ago

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub issues, we have to clean some of the old issues as many of them have already been resolved with the latest updates.

Please make sure to update to the latest Gatsby version and check if that solves the issue. Let us know if that works for you by adding a comment 👍

thedistricts commented 6 years ago

I encountered a similar issue when pulling and transforming relatively large files from Wordpress. Small files would appear as expected, larger files would return null. Upgrading to v1.9.277 resolved the issue

kakadiadarpan commented 6 years ago

Hi @lesliecdubs, can you try upgrading to v1.9.277 as @thedistricts suggested? That should fix the issue for you.

(If you disagree, feel free to re-open 😄 and we can look further)

lesliecdubs commented 6 years ago

Hi everyone, thanks for chiming in. I upgraded to v1.9.277 but the errors from the original post were still coming through.

Our "bandaid fix" has been working consistently and I know efforts are focused on v2 right now, so I'm fine leaving this issue closed. If I run into similar problems in v2 I'll be sure to report. Thanks!!

kakadiadarpan commented 6 years ago

Thanks for the update @lesliecdubs!

Feel free to open a new one if you still experience this problem in v2👍

iaindurie commented 6 years ago

I've been getting this error frequently when querying ACF images from Wordpress. It happens suddenly with images that were loading fine previously. Seems to happen randomly after editing an arbitary piece of content in Wordpress. After rebuilding the error happens. Experienced in v1 and now v2.

kakadiadarpan commented 6 years ago

@iaindurie can you open a new issue and provide relevant environment information and a reproduction repo?

iaindurie commented 6 years ago

@kakadiadarpan The Wordpress site I'm querying from isn't a publicly accessible site. I haven't seen this issue in a while, since clearing the cache folder and rebuidling. However If I stumble across it again, I'll create a new issue/repo and see if I can get my Wordpress site accessible too. Thanks.