Next.js Discord

Discord Forum

Cache images / image flashing / decode async NEXTJS

Answered
Chien Français Tricolore posted this in #help-forum
Open in Discord
Chien Français TricoloreOP
This is driving me CRAZY in nextjs.

Every single image has the cache control header set to "public, max-age=0, must-revalidate" and it seems IMPOSSIBLE to overwrite this nonsense behavior. Every single time my page opens it flashes the image because its the "first time" getting that image. It makes absolutely NO SENSE.

Please, anyone has a workaround for this?
Am I doing something wrong, or is every image in nextjs supposed to be uncacheable??? This is absurd....
Answered by B33fb0n3
now go in production via next build and next start or what ever npm command you have. Some caching stuff is disabled in developement
View full answer

34 Replies

Chien Français TricoloreOP
it does not work
already tried
same response header
and you also looked at x-nextjs-cache and not only on max-age?
Chien Français TricoloreOP
Am i supposed to overwrite that header?
no, but it shows, if it reads the cache status: HIT, MISS or STALE
Chien Français TricoloreOP
I'm sorry, I never heard of that header before and I don't understand anything about it. This is what my response headers look like
and yes, its the same in production
is there any documentation about it?
Chien Français TricoloreOP
well, as you can see the header is not even present
you disabled the browser cache to directly see the response from your server?
Chien Français TricoloreOP
i dont think so, but i will try with another browser then
@Chien Français Tricolore i dont think so, but i will try with another browser then
if you open your dev tools and click on "network" you can checkmark the field with deactivate cache
Chien Français TricoloreOP
i mean, it doesnt even make sense. i already checked other websites and the cache behavior is normal
@Chien Français Tricolore i didnt enable that
do it and your browser cache is disabled
Chien Français TricoloreOP
its unchecked
ah
same response though
status 304 or 200?
Chien Français TricoloreOP
200
pretty much the only difference
now delete the .next folder and restart your server. Then open your dev tools FIRST and then load the page. You should see the requests and the creation of the image in your .next folder
Chien Français TricoloreOP
Yeah, that did happen, but the headers are the same
so the image will still flash
now go in production via next build and next start or what ever npm command you have. Some caching stuff is disabled in developement
Answer
Chien Français TricoloreOP
Thanks, somehow the cache headers are now working. I i think the ttl config was needed, I didn't test it in production before.

The flash continues, but now i understand why. It's because of the decode="async" option that is forced in nextjs in image tags. Omg. Now i guess i will have to rewrite the nextjs code because stuff like that keeps being forced into people
Chien Français TricoloreOP
I chose to override the props of the rendered img tag using cloneElement instead, by modifying the render function, since messing with the framework code is dangerous.

If anyone is interested in the implementation of this madness until they accept the PR of making decode attribute modifiable, here it is:

"use client";
import Image, { ImageProps } from "next/image";
import { Children, ReactNode, cloneElement } from "react";

interface Props extends ImageProps {}

export default function ImageSync(props: Props) {
  // eslint-disable-next-line
  const clonedElement = cloneElement(<Image {...props} />);

  // @ts-ignore
  const oldRender = clonedElement.type.render;

  function newRender(props: any, forwardRef: any) {
    const result = oldRender(props, forwardRef);

    const newChildren: ReactNode[] = [];
    Children.forEach(result.props.children, (child, index) => {
      if (index === 0) {
        const newChild = cloneElement(child, {
          key: index,
          decoding: "sync",
        });
        return newChildren.push(newChild);
      }
      newChildren.push(child);
    });

    const clonedElement = cloneElement(result, { children: newChildren });

    return clonedElement;
  }

  // @ts-ignore
  clonedElement.type.render = newRender;

  return clonedElement;
}
Now i have a clean, instant, without any flashing, image load. As it should be!