gatsbyjs / gatsby

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

Wrong image loads during after hard refresh in production build #35385

Open xavdid opened 2 years ago

xavdid commented 2 years ago

Preliminary Checks

Description

In production builds of my site, on a single, specific blog post, on initial page loads (and after a hard refresh), the wrong image is loaded.

Here's a gif of that in action:

https://cdn.zappy.app/fd4a22f58d16604fb20fe85f8dee011b.gif

On each refresh in the above gif, I wait for the page to fully finish loading. The image replacement happening on initial load is on the part of the browser/gatsby, not me refreshing extra quickly or anything.

There's nothing unusual about that image. It's referenced in a normal way, using standard markdown image references. Most other images in that blog post also work (though a couple exhibit this same issue). All other blog posts on the site don't have this issue at all.

In the produced minified html, the file is referenced correctly:

But in my browser (on initial load or after hard refresh), the html is different:

Something about the page doing its initial load changes what image block is referenced.

Now, here's the spookiest part. Locally, if you run that html page through prettier (which just reformats the html file; it shouldn't have any effect on the actual content), the bug goes away.

I've included my full local public folder here: https://www.dropbox.com/s/8cxgg7abbhwu3fm/public.zip?dl=0. The file in question is public/blog/post/favorite-media-2021/index.html. The formatted version is provided in this gist.

I've tried to reproduce this both in a clean project and even elsewhere on my site or that post without success. I don't think there's anything weird about the setup of the html.


My most probable theory is that remark / mdx has a bug that's building the html in a way that gatsby's image loader doesn't expect. But, given its inconsistent behavior when the cache is cleared, it was a little out of my depth without knowing more about gatsby.

Thank you!

Reproduction Link

https://github.com/xavdid/website

Steps to Reproduce

I apologize in advance for the lack of reproducibility here. Like I said, I haven't been able to isolate it or reproduce it, so I haven't been able to make a reproducible example. It only happens on a single blog post with about 3 images on my site. Instead, I've provided steps to reproduce it using my blog; I'm really sorry.

  1. navigate to this blog post at the It Takes Two header. (or run a production build of the linked repo using yarn build)
  2. Do a hard refresh
  3. The (incorrect) "What the Golf" image loads
  4. Do a normal refresh
  5. Now, the (correct) "It Takes Two" image loads.
  6. After every hard refresh, the wrong image is shown. After every regular refresh, the image is correct.

Expected Result

The "It takes Two" image should load every time

Actual Result

The "What the Golf" image is loaded after a hard refresh (or on initial page load). On subsequent regular refreshes, the correct image ("It Takes Two") is loaded

Environment

System:
    OS: macOS 12.3
    CPU: (10) arm64 Apple M1 Pro
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 16.13.0 - /var/folders/9c/yrfwyg5n6fzdqc70j3n2p_600000gn/T/yarn--1649565608693-0.395189727230022/node
    Yarn: 1.22.17 - /var/folders/9c/yrfwyg5n6fzdqc70j3n2p_600000gn/T/yarn--1649565608693-0.395189727230022/yarn
    npm: 8.1.0 - ~/.nodenv/versions/16/bin/npm
  Languages:
    Python: 3.10.0 - /Users/david/.pyenv/shims/python
  Browsers:
    Chrome: 100.0.4896.75
    Firefox: 98.0.1
    Safari: 15.4
  npmPackages:
    gatsby: ^4.11.2 => 4.11.2 
    gatsby-plugin-feed: ^4.11.1 => 4.11.1 
    gatsby-plugin-goatcounter: 0.4.0 => 0.4.0 
    gatsby-plugin-manifest: ^4.11.1 => 4.11.1 
    gatsby-plugin-mdx: ^3.11.1 => 3.11.1 
    gatsby-plugin-offline: ^5.11.1 => 5.11.1 
    gatsby-plugin-react-helmet: ^5.11.0 => 5.11.0 
    gatsby-plugin-sass: ^5.11.1 => 5.11.1 
    gatsby-plugin-sharp: ^4.11.1 => 4.11.1 
    gatsby-plugin-sitemap: ^5.11.1 => 5.11.1 
    gatsby-remark-autolink-headers: ^5.11.1 => 5.11.1 
    gatsby-remark-copy-linked-files: ^5.11.0 => 5.11.0 
    gatsby-remark-images: ^6.11.1 => 6.11.1 
    gatsby-remark-mermaid: ^2.1.0 => 2.1.0 
    gatsby-remark-prismjs: ^6.11.0 => 6.11.0 
    gatsby-source-filesystem: ^4.11.1 => 4.11.1 
    gatsby-transformer-sharp: ^4.11.0 => 4.11.0

Config Flags

No response

imjoshin commented 2 years ago

Hey @xavdid ! Thanks for reporting this. Some quick thoughts:

We've done some initial digging and have discovered it's related to the service workers / react hydration step. We aren't quite sure why yet, but if you enable "Bypass for network" under Application -> Service Workers, we can always see the incorrect result. If we disable Javascript, everything looks correct. This leads us to believe it's in that layer.

Going to have to dig a bit more... 🤔

xavdid commented 2 years ago

@j0sh77 No problem at all, thanks for digging into it! I almost didn't file it because I had so little clue how to reproduce it; that to know there's something there.

When it's all said and done, I'll be super curious to hear why the HTML formatting has any effect on the output and what's different/special about those images that they show the bug while no others do.

Let me know if there's anything else I can do to help!

dusaniuk commented 2 years ago

@xavdid I've faced the same issue. Was able to fix this by disabling showCaptions option in gatsby-remark-images plugin.

FYI: @j0sh77

RubenNijhuis commented 2 years ago

Any update on this? I seem to be facing the same issue on my site -> https://rubennijhuis.com I also opened an issue that seems to match this one https://github.com/gatsbyjs/gatsby/issues/35592 For some reason it got pushed to a discussion

cs-manughian commented 2 years ago

Any update on this? I'm also facing the same issue, and we don't show captions so that fix won't work for us

divyanshumittal commented 2 years ago

Any update on this? I'm also facing the same issue. Wrong images get loaded for the products on home page. If i go to a different page, and then come back to the home page, I see the correct images.

cultura-saatio commented 1 year ago

We're facing the same issue.

newcc845 commented 1 year ago

Any update for this? I'm also facing the same issue. We can't advise clients to keep refresh to get the correct image.

amrfarid140 commented 6 months ago

For anyone seeing this issue, here's what I've found and how I fixed it.

TL;DR: Store any data you are accessing in useState and perform any mutations on it from a useEffect.

In a React component I had this

const MyComponent = ({ hasRichText,  body}) => {
...
  const richTextRefs: Record<string, unknown> = {};
  if (hasRichText) {
    body.data.references?.forEach((reference) => {
      richTextRefs[reference.contentful_id] = reference.gatsbyImageData;
    });
  }
...
}

Normally this code works. Every time the component renders, we get a new richTextRefs and move on. For some reason, on a specific page we ended with a corrupted richTextRefs object and displayed the wrong image.

To solve, we had to revert to using useState

//Some code above
  const [richTextRefs, setRichTextRefs] = useState<Record<string, unknown>>();
  useEffect(() => {
    setRichTextRefs(
      body.data.references?.reduce((acc, reference) => {
        acc[reference.contentful_id] = reference.gatsbyImageData;
        return acc;
      }, {}),
    );
  }, [hasRichText]);
//Some code below

My guess is somewhere in Gatsby it keeps hold of an old reference to the richTextRefs object so we end up with a corrupted/stale object. Using useState and useEffect guaranteed that we are creating a new object each time the useEffect got executed.

Given my limited understanding of Gatsby internals, would love to hear from others on why this is an issue and why it happens occasionally not all the time.