Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Cache-Control response header for /_next/image #19914

Closed
jerrygreen opened this issue Dec 7, 2020 · 113 comments
Closed

Custom Cache-Control response header for /_next/image #19914

jerrygreen opened this issue Dec 7, 2020 · 113 comments
Assignees
Milestone

Comments

@jerrygreen
Copy link
Contributor

jerrygreen commented Dec 7, 2020

Bug report

Describe the bug

When requesting /_next/image(.*), I'm getting this Response header:

Cache-Control: public, max-age=60

And it's fine... What's not fine is that I'm getting the same exact Response headers even when I use custom headers in next.config.js, i.e.:

module.exports = {
  async headers() {
    return [
      {
        // This works, and returns appropriate Response headers:
        source: '/(.*).jpg',
        headers: [
          {
            key: 'Cache-Control',
            value:
              'public, max-age=180, s-maxage=180, stale-while-revalidate=180',
          },
        ],
      },
      {
        // This doesn't work for 'Cache-Control' key (works for others though):
        source: '/_next/image(.*)',
        headers: [
          {
            key: 'Cache-Control',
            // Instead of this value:
            value: 'public, max-age=180, s-maxage=180, stale-while-revalidate=180',
            // Cache-Control response header is `public, max-age=60` in production
            // and `public, max-age=0, must-revalidate` in development
          },
        ],
      },
    ]
  },
}

To Reproduce

Try this next.config.js above, with an image that uses common <img> tag like this:

<img src="/YOUR_IMAGE_IN_PUBLIC_FOLDER.jpg">

And another tag that uses the new next/image component, with the same or whatever image url, for example:

<Image src="/YOUR_IMAGE_IN_PUBLIC_FOLDER.jpg">

And try requesting those images in the browser, and look into Devtools -> Network tab, the Response headers, and see that for common <img> tag it's actually changed, whereas for new <Image> component it is not.

Expected behavior

For /_next/image(.*) urls, I expected to see Headers that I setup, i.e. Cache-Control: public, max-age=180, s-maxage=180, stale-while-revalidate=180.

Screenshots

Common <img>:

image

New <Image>:

image

System information

  • OS: not applicable / any
  • Browser (if applies): not applicable / any
  • Version of Next.js: 10.0.3
  • Version of Node.js: 12.18.0
  • Deployment: both next start on development machine, and actual Vercel deployment (screenshots demonstrate the case with local machine, but I've confirmed that the same is happening on a Vercel deployment)

Additional context

Originally I created an issue using "Feature request" template, and it got translated into "Idea discussion": #19896 (how to delete/close it pls? doesn't seem to be possible), - initially I wasn't sure if it's even possible to setup custom headers, and how that supposed to work, though I just needed that functionality. But later, upon discovering that there's such a functionality already, I figured out that actually /_next/image overrides both custom headers in next.config.js and headers property of Vercel config, i.e. it's not just some idea of a feature that is "not implemented", but it's actual bug.

@jerrygreen jerrygreen added the bug Issue was opened via the bug report template. label Dec 7, 2020
@jerrygreen jerrygreen changed the title Custom response headers for /_next/image Cache-Control response header for /_next/image Dec 7, 2020
@jerrygreen jerrygreen changed the title Cache-Control response header for /_next/image Custom Cache-Control response header for /_next/image Dec 7, 2020
@mehmetpekcan
Copy link

Are there any update here?

@aresrioja10
Copy link

Any updates? Lighthouse is lowering my score because I must serve the images with a more efficient cache policy

@guilehm
Copy link

guilehm commented Dec 30, 2020

I had to rollback to next 10.0.1, since this problem does not happen in that version.
I cannot serve my images with max-age=0.

@Timer Timer added this to the iteration 16 milestone Dec 30, 2020
@Timer Timer added kind: story and removed bug Issue was opened via the bug report template. labels Dec 30, 2020
@PaulSenon
Copy link

PaulSenon commented Dec 31, 2020

Hi, I think I just had the same problem... And I found a solution to it.

TL;DR: just set the cache-control header from your provided images, pointed by the url param in /_next/image?url=....

Context:

  • I'm using Vercel hosting with default CDN, and Next@10.0.4
  • I'm hosting my images on a public S3 bucket
  • I use the nextJs <Image/> component with url pointing on my S3 so it construct the /_next/image?url=... for me
  • The cache-control max-age is always 60 whatever I write in my next.config.js or vercel.json files...

I tried:

  • Setting cache-control header through next.config.js
  • Setting cache-control header through vercel.json
  • Rollbacking to next 10.0.1 as suggested above and testing again the two previous points.

=> But still have the issue. I cannot control the cache of /_next/image (works just well on any other routes)

After diving a bit more into that, I found somewhere in the Vercel documentation where they clearly explain why it behaves like this, and therefore I suppose it is not a bug.

It says:

If no max-age value is provided in a Cache-Control header returned by the image URL/path, a default max-age of 60 seconds is set. In turn, source images will be retrieved again and optimized on incoming requests if more than 60 seconds have passed since the last optimization of that image (in the same Edge Network node).

So I just gave it a try, by setting the cache-control header directly on my files hosted on my S3 bucket. I first seen no changes and I thought "oh well... It is definitively bugged..." but like 20min later, when I was into something else, I just found that it actually worked !!!! it just take time to get the CDN aware of your changes on the original resource. I don't understand why, because the default TTL must be 60sec, but anyway... It works.

So I hope it helps, tell me if your issue wasn't exactly this, but I'm sure it will help someone one day so I posted this here.
It took me half a day to get it to work but I've learned plenty of stuff on browser and CDN caching. Let's say it was worth the cost of the fight :)

@aresrioja10
Copy link

Hi @PaulSenon !

I'm gonna try your solution right now. I'm hosting my images in Wordpress so I've added this code into my .htaccess:

<IfModule mod_headers.c>
  <FilesMatch "\.(jpg|png|svg)">
    Header set Cache-Control "max-age=604800, public"
  </FilesMatch>
</IfModule>

@aresrioja10
Copy link

@PaulSenon It works! 🎉

@PaulSenon
Copy link

@aresrioja10 Cool! Glad it helped!

@jerrygreen as you opened this issue, please give a try to this solution and eventually close the issue if it solves your problem too :)

@alexbrazier
Copy link
Contributor

I don't think this fixes the issue if you are hosting the images locally with next, e.g. the path is <Image src="/images/local.jpg" /> as you can't set the cache control on those. It still seems to be a bug if it is ignoring your next.config.js.

@TheThirdRace
Copy link

Not sure if it applies to your particular case, but here's what I could find out with my own tests.

>>> I don't set any Cache-Control header <<< and host images on Vercel directly

DEV

The cache-control header is always: Cache-Control: public, max-age=0, must-revalidate.

Don't forget to disable the Disable Cache in the Network tab when using Chrome Dev Tools (must be the same with Firefox)

When cache is active, the image is cached correctly (response 304 Not Modified).

When revalidating to know if the cache is ok, it checks the Etag with an If-none-match header. If the resource hasn't changed, it will use the cached version.

Given the cache mechanism used here, there will still be a network call to validate the image hasn't changed, but it's a few bytes instead of the normal KB.

Verdict => It works as expected

PROD

The cache-control header is always: Cache-Control: public, max-age=0, must-revalidate.

Don't forget to disable the Disable Cache in the Network tab when using Chrome Dev Tools (must be the same with Firefox)

When cache is active, the image is cached correctly (response 304 Not Modified).

When revalidating to know if the cache is ok, it checks the Last-Modified with an If-modified-since header. If the resource hasn't changed, it will use the cached version. You can also see the x-vercel-cache: HIT header that shows the Vercel cache was successful.

Given the cache mechanism used here, there will still be a network call to validate the image hasn't changed, but it's a few bytes instead of the normal KB.

Verdict => It works as expected

Branches deployed on commits

I would need to check, but I think the cache is always disabled in this case. Which is kind of expected I guess, you're not supposed to run much on these anyway.

@joshmanders
Copy link

I'm getting forced loadings every page load on Safari, Brave, Chrome and FireFox, multiple people have reported similar to me also.

Caching is not working.

@joshmanders
Copy link

So I was able to figure out that my problem was that .next/cache folder wasn't writeable by the user on the container, so fixing that now caches the image locally in next, but now the first load for an optimized 91.9 kB image that was originally 500+ kB is aCTUALLY slower than just using <img /> directly and letting the browser cache it.

@starburst997
Copy link

starburst997 commented Jan 2, 2021

Not sure if this should be a separate issue but since I've seen it mentioned here I'll comment here.

Basically I'm getting cache-control: public, max-age=0, must-revalidate no matter what, which is curious since it's seems like the minimum is always at least 60. I tried debugging a bit and getMaxAge does return the correct value from my hosted image (which is 31536000). However the resulting header is still max-age=0 (and with must-revalidate that seems like a "dev" header that shouldn't be on a prod server right?).

This is on a private hosted server (not vercel) in prod (not dev). All other routes / pages return the correct header. Only /_next/image return max-age=0. I fixed it on my end by writing a custom rule in my nginx config.

If max-age=0 is indeed the correct behavior might I ask why? For me on ios safari this results with "flashes" since the image isn't grab from cache immediately. I guess when this is hosted on vercel it is a little bit different since there is additional headers sent that might counter this but on a private server this results with poor behaviors.

On vercel (taken from this, I haven't tried hosting my site on vercel yet):

access-control-allow-origin: *
age: 3
cache-control: public, max-age=0, must-revalidate
content-disposition: inline; filename="mountains.jpg"
date: Sat, 02 Jan 2021 18:20:08 GMT
last-modified: Sat, 02 Jan 2021 18:20:04 GMT
server: Vercel
strict-transport-security: max-age=63072000
x-vercel-cache: HIT
x-vercel-id: iad1::sg6c5-1609611608267-147be5c7c5c8

(Edit: After some new tests on Vercel, the source's max-age header is properly honored, still not the case on private server tho)

On my server (next 10.0.4):

cache-control: public, max-age=0, must-revalidate
content-type: image/webp
date: Sat, 02 Jan 2021 18:21:00 GMT
etag: kSVa7RXI9R1Tski31528i1nXHYD8emqPVBhY8exwtFE=
server: nginx

Not sure if I'm missing some config on my server that explains the missing headers but it's a pretty barebone default nginx proxy.

This seems like a bug (for private server at least) and being able to specify the cache-control in the next js config would be great, otherwise it's still possible to fix with a custom rule in nginx but the default behavior seems like a poor experience.

@joshmanders
Copy link

@starburst997 I think the cache isn't for the header and caching locally but for serving cached versions from .next/cache/images

@starburst997
Copy link

starburst997 commented Jan 2, 2021

@starburst997 I think the cache isn't for the header and caching locally but for serving cached versions from .next/cache/images

I see! That would explains it then, still you would think that if they check the Cache-Control header from the source it would be passed down.

Here's an example of the "flashing" that occurs because the Cache-Control isn't set properly. I can only see it on Safari iOS, it seems fine on desktop.

https://mot9t.sse.codesandbox.io/

The first image sends

cache-control: public, max-age=31536000, immutable

The second is hosted on vercel and use the image optimizer

cache-control: public, max-age=0, must-revalidate

(Edit: After some new tests on Vercel, the source's max-age header is properly honored, still not the case on private server tho)

Here's a gif

RPReplay_Final1609621051.mp4

Notice how the second image hosted on vercel with max-age=0 flickers.

It is particularly annoying when going back / forward in the history or with an infinite scroller

Being able to at least override this Cache-Control would be great to prevent this behavior on ios

@joshmanders
Copy link

@starburst997 I agree, there's something wonky about <Image /> on non-vercel hosted apps. I'm probably gonna revert back to standard <img /> until it's resolved.

@TheThirdRace
Copy link

TheThirdRace commented Jan 2, 2021

@starburst997 Just to be sure, is your example has a normal <img> + 1 <NextImage> or is it both <NextImage>?

I ask because <NextImage> is a fully responsive and lazy loaded image.

If your page is static or server rendered, the first paint doesn't include the image because <NextImage> uses lazy loading and it's only when rehydrating takes place that the IntersectionObserver realize the image is within the viewport and retrieve the cached image. This would explain the flash.

Have you tried the eager prop to load the image immediately instead of lazy-loaded?

Have you tried the priority prop to preload the image as fast as possible?

<NextImage> is FAR from perfect, there are plenty of issues with styling them right now and it's entirely possible it only supports Vercel hosting and the 3 official providers: cloudinary, imgix, akamai

@yayvery
Copy link

yayvery commented Jan 2, 2021

@TheThirdRace I can confirm that neither eager nor priority do not solve this issue. The problem is the max-age=0, must-revalidate header. The flash happens even if you open the direct link to the image.

@starburst997
Copy link

starburst997 commented Jan 2, 2021

@TheThirdRace I posted the code source of the example and I though it was clear but I will try to re-explain because I think this is an important issue that needs to fixed:

Image 1 is loaded and has a response header with cache-control: public, max-age=31536000, immutable, image 2 is loaded from Vercel and use the image optimizer (/_next/image?url=...) but the response header has cache-control: public, max-age=0, must-revalidate (this is how the image optimizer and vercel works currently, we can't change that).

(Edit: After some new tests on Vercel, the source's max-age header is properly honored, still not the case on private server tho)

On Safari iOS, you can see how Vercel's image flicker but not the first one.

This has nothing to do with hydrating / lazy loading or the likes.

Edit: Yes in the example I use <img> for both, the issue is not with the next image component itself but the response headers from the image optimizer.

@TheThirdRace
Copy link

@starburst997 Unfortunately, I never found the source code, all I saw was the link to the codesandbox running (https://mot9t.sse.codesandbox.io/), but no code was available...

Given the "new" information from you and @danbeneventano, I can only stand with you guys.

What happens if you configure the must-revalidate on the first image (not on vercel)? Do you get the same behavior as with the image hosted on Vercel?

If you do, then <NextImage> might not be the component you need. NextJs tightly integrated their backend image optimization with the <NextImage> component. They force must-revalidate in cache-control header to allow downloading the new images when using layout='response' or layout='intrinsic'. Without must-revalidate, whenever you resize your browser window, you would get the old cached image instead of a new image according to the sizes prop.

Personally, I think NextJs went too far with their <NextImage> component:

  • They forced their cache control header instead of having a default that you can override
  • The DOM is also a mess, you shouldn't need 2 wrapper <div> tags for an <img> tag... especially when both <div> use style directly on the DOM node, which forces you to use !important to override them. The lack of handles on the wrappers also doesn't help...

They gave us a wonderful solution if used exactly the way they intended, but you're gonna be in trouble if you want to change anything in the tightly integrated process. Which is a big letdown in my opinion... Given there's some time before I release what I'm building with NextJs, I'll wait and see what happens, but I'm also thinking of simply switching back to a plain old <img> tag or use another package if no improvement is made on the numerous issues <NextImage> has.

@starburst997
Copy link

@TheThirdRace I should've posted the link to the editor on the first post but you can get the editor link easily in any codesandbox (https://codesandbox.io/s/editor-XXXXX, replace with "mot9t"), my bad.

" might not be the component you need", things is, it is exactly the component I was looking for, it works perfectly in my use-case, I just want a way to be able to set the cache-control header.

I must admit I didn't look too far into it, but why would the image component absolutely need the must-revalidate to do that? The browser and srcSet takes care of that, I tried it and it works fine even without it. I didn't try the responsive one but I don't have any need for it.

@TheThirdRace
Copy link

I must admit I didn't look too far into it, but why would the image component absolutely need the must-revalidate to do that? The browser and srcSet takes care of that, I tried it and it works fine even without it. I didn't try the responsive one but I don't have any need for it

You mean you put srcSet directly as a prop?

Because if I read the documentation, there's no mention of that prop except that it's supposedly not passed to the image... https://nextjs.org/docs/api-reference/next/image#other-props

I must rectify my statement, it's only layout='responsive' that seem to download new copies while resizing your browser window. If you got images that span large area, you really want to use responsive; it allows to download the smallest acceptable image for the viewport, which can mean a lot of KB savings. You could set your own srcset I guess, but then you have to build it yourself...

I've tested the default layout='intrinsic' and to me it looks completely broken. I got a resized window at 500px and the component still fetch the 960px image even though the sizes props contains many breakpoints between 500px and 960px. The generated srcset simply has the 1x, 2x and 3x versions... Fun times!!!

I'm also banging my head on the wall with the CSS part... Images don't have sizes when using layout='responsive', they're kinda floating (using position: absolute). Ever tried to use overflow: hidden on a container with an image and multiple other stuff? The image doesn't resize, it simply squish itself... Fun times again!!!

I'm currently fighting a lot with the NextImage component, getting pretty tired of it actually. :(

@TheThirdRace
Copy link

@stefanprobst
Actually, even the import optimization method is not really done at build time.

At build time, you can check the static images produced in your .next/static/image/public folder and you're gonna see there's only 1 version for each image. Furthermore, it's the original unoptimized image.

The image optimization really happens at run time:

  • NextJs image optimization service receive a request for an image
  • It checks that static folder to see if the required optimized image is already there
  • If that's the case, then serve that image with cache-control = public, max-age: 1year, immutable
  • If the image is missing, e.g. you needed a webp and it ain't produced yet:
    • NextJs will optimize the image for the required format and size
    • It will write that image to the static folder
    • It will hash the content of that optimized image and use that hash to rename the image appropriately
    • It will serve the image with cache-control = public, max-age: 1year, immutable

For truly static image optimization, NextJs would have to offer a configuration in next.config.js so we can specify the formats and sizes we want. Then at build time, it would to generate all the optimized image in the appropriate folder.

There are downsides to truly static image optimization, such as:

  • Longer build times, especially when you have a lot of images
  • The filename is static, so if you make a mistake...
    • you'll have to rename the original image to bust the cache
    • you'll need to change your code or image url to point to the new one

The current import method don't have these problems because of the hashing feature, which is only possible because it happens at run time.

So long story short, no there isn't any build time image optimization for markdown content. In fact there isn't any build time image optimization at all.

@Amir-Mirkamali
Copy link

@TheThirdRace Thank for reply and thank for precise detail about next.js image optimization system 🙏
But i think you missed the main point that I have mentioned,
Please please please do not modify the cache when it set before!

@TheThirdRace
Copy link

@Amir-Mirkamali
I 100% agree with you, NextJs shouldn't modify the cache-control header if you set it in next.config.js.

While really unintuitive, there is a way to set the cache-control header on your images and NextJs won't change it.

All you need to do is to configure your hosting service to serve images with the cache-control you want. NextJs will then act as a passthrough and let your cache-control alone.

For hosting services like AWS, I think you can set the cache-control on a folder directly. It takes some time for the settings to propagate, but it does work.

@MaximeBernard
Copy link

MaximeBernard commented Jun 28, 2021

Thanks for this explanation @TheThirdRace 👍

  • you'll have to rename the original image to bust the cache

Wouldn't etag be enough?

@TheThirdRace
Copy link

@MaximeBernard
My comment was made in the context of a truly static image, meaning your image has a cache-control of public, max-age: 31536000, immutable.

To be able to use an etag, the browser will need to make a request to the server, which is exactly what we want to avoid by using public, max-age: 31536000, immutable.

But because your image is cached up to a year, then you need to change the filename if you want the clients to update to the new image instantly otherwise the browser will simply serve the image in cache.

@Amir-Mirkamali
Copy link

Still, I think that etag and current cache-control system is useless for us.
It’s good for whom use CDN! Unfortunately, I am not using CDN and I have a media server myself.
This system not gonna work for me and not customizable, Its s very simple: Let me decide myself!

I want to serve my image with one week cache and I want to modify that cache in next.config.js file but it’s not possible now.
Completely disappointed from Next.js Image component so I bypassed the image loader.
I wish that someone hear our voice and correct this part of code.

@styfle
Copy link
Member

styfle commented Jun 30, 2021

Take a look at PR #26739 which will preserve the upstream max-age so the browser can utilize it too.

This will support the first use case (source: '/(.*).jpg') when you want internal jpg images to have a different max-age than other images.

However, we won't be supporting the use case for source: '/_next/image(.*)'. This could lead to de-optimization because it would override all images including static imported images (should remain immutable) and external images (should rely on upstream server cache-control header).

Furthermore, we plan to build stale-while-revalidate behavior into the image optimization server to avoid making any client wait for the server to re-optimize an image again, so this header will not be required.

kodiakhq bot pushed a commit that referenced this issue Jun 30, 2021
This solves the main use case from Issue #19914.

Previously, we would set the `Cache-Control` header to a constant and rely on the server cache. This would mean the browser would always request the image and the server could response with 304 Not Modified to omit the response body.

This PR changes the behavior such that the `max-age` will propagate from the upstream server to the Next.js Image Optimization Server and allow browser caching. ("upstream" meaning external server or just an internal route to an image)

This PR does not change the `max-age` for static imports which will remain `public, max-age=315360000, immutable`.

#### Pros:
- Fewer HTTP requests after initial browser visit
- User configurable `max-age` via the upstream image `Cache-Control` header

#### Cons:
- ~~Might be annoying for `next dev` when modifying a source image~~ (solved: use `max-age=0` for dev)
- Might cause browser to cache longer than expected (up to 2x longer than the server cache if requested in the last second before expiration)

## Bug

- [x] Related issues linked using `fixes #number`
@Faey2222
Copy link

Faey2222 commented Jul 1, 2021

@styfle So how can I prevent my application to always use the file on the server if all my images come from an headless system (directus9)? The headers sent by directus are ignored when I use the next/image component. Therefore when a user revisits my website the load time for images is always unacceptable due to that fact that the images are always reloaded from the server.

Maybe I just missed something?

@TheThirdRace
Copy link

TheThirdRace commented Jul 1, 2021

@styfle

About the PR

Just to clarify, could you confirm the PR will have these effects:

  1. We can now set the cache-control header in next.config.js
  2. We don't need a vercel.json anymore for "local" images as it's taken care of by next.config.js now
  3. External images will still need to set their own cache-control header since next.config.js only applies to "local" images
  4. By "local" images, you're referring to images hosted in our own NextJs repository, i.e. our public folder

Etags

Before this PR, the etag would be omitted from the response headers if:

  1. I used a vercel.json to set the cache-control header
  2. I used static images (import method)

This behavior isn't ideal though as it prevents some fallback situations.

Example

  1. Images are cached for 30 days
  2. On day 31, the client's browser will do a network request to retrieve the image (or revalidate the cache)
  3. Without etag, the browser will check last-modified and expire-at headers and determine the image is expired, which in turn force the browser to re-download the image even if it hasn't changed
  4. Any subsequent request to that image will force the browser to re-download the image as it's "expired" according to the server

With an etag, the server would have returned a 304 Not Modified, which is only a few bytes in comparison.

Even with static images, which use immutable, not all browsers support that value. If by a low chance a client keeps an image in its cache for 1 year, then he would redownload the image on every single request past that. All because there's no etag to compare and the last-modified / expire-at headers combination would compute to be expired.

My point is, there's only benefits to include the etag in the response header.

Cloudinary behavior

I want to point out that Cloudinary will also one-up this etag situation by updating the last-modified or expire-at on the original image once it actually becomes expired.

This has the benefit to reset the last-modified / expire-at combination so any browser that would just want to revalidate its cache could know the cache can be renewed and receive a 304 Not Modified.

If a browser doesn't support etag, the cache is still working.

If a browser does support etag, the request to revalidate the etag will only be made once every 30 days (from the example) before renewing the cache. Thus, avoiding revalidating the cache multiple times within the month, no more unneeded network requests.

@styfle
Copy link
Member

styfle commented Jul 1, 2021

The fix is available in next@11.0.2-canary.4 🎉

Please give it a try and let us know if it solves your problem with a 👍 or 👎

If you leave a 👎 , please explain why it doesn't work for you and provide steps to reproduce the issue. Thanks!

leimonio added a commit to leimonio/next.js that referenced this issue Jul 6, 2021
* [WIP] Add cms notion integration example - index page

* Add cover images for pages

* Add post page

* Remove preview functionality

* Add module.exports to security headers documentation (vercel#26466)

Without `module.exports`, the provided code won't work if just pasted into `next.config.js`

## Documentation / Examples

- [x] Make sure the linting passes

* fix: ignore invalid accept-language header (vercel#26476)



Fixes vercel#22329

## Bug

- [x] Related issues linked using fixes vercel#22329
- [x] Integration tests added

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.

## Documentation / Examples

- [ ] Make sure the linting passes

* chore: Add Alex to lint documentation (vercel#26354)

This Pull Request adds [Alex](https://alexjs.com/) to our documentation. It catches insensitive, inconsiderate writing. 

The original PR (vercel#25821) is too large so I have decided to break it down into smaller PRs. This PR is the first part. Then I will continue to add the rest of the documentation in smaller PRs.

## More Information on Alex:
https://alexjs.com/
https://github.com/get-alex/alex

## Documentation / Examples

- [x] Make sure the linting passes

* Fix domain locales not available on client (vercel#26083)

* bug: Fix domain locales not available on client

* Add test case

* update tests

Co-authored-by: JJ Kasper <jj@jjsweb.site>

* Update to only add image import types when enabled (vercel#26485)

* Update to only add image import types when enabled

* add type check to test

* Update i18n fields in docs (vercel#26492)



Closes: vercel#24991

## Documentation / Examples

- [x] Make sure the linting passes

* v11.0.1-canary.7

* Strongly type `Router.events.on` and `Router.events.off` (vercel#26456)

This strongly types `Router.events.on` and `Router.events.off`. Previously the event type was `string` but now it's `'routeChangeStart' | 'beforeHistoryChange' | 'routeChangeComplete' | 'routeChangeError' | 'hashChangeStart' | 'hashChangeComplete'`


## Bug

- ~[ ] Related issues linked using `fixes #number`~
- [x] Integration tests added

Closes vercel#25679
Closes vercel#23753
Closes vercel#15497

* Update next Link & Image components

* Ensure image-types file is included (vercel#26495)

* Update react & react-dom to v17

* Update tailwind to use jit

* v11.0.1-canary.8

* v11.0.1

* Don't test image domains in test env (vercel#26502)

fixes vercel#21549

Co-authored-by: JJ Kasper <jj@jjsweb.site>

* docs: updated minimum Node.js version (vercel#26528)

## Documentation / Examples

- [x] Make sure the linting passes


According to new requirements in `package.json` minimum Node.js version for now is 12.0

* Update next-env note in docs (vercel#26536)

This ensures we don't recommend editing the `next-env` file since we need to be able to tweak it to accept future types we add in Next.js


## Documentation / Examples

- [x] Make sure the linting passes

Closes: vercel#26533

* [examples] Fix ssr-caching example. (vercel#26540)

Closes vercel#12019 with a better example of proper SSR caching.

* Fix props not updating when changing the locale and keeping hash (vercel#26205)



Currently, there is only a `hashChangeStart` and subsequent `hashChangeComplete` event and no props update (which would be used to get translations, etc.).
Happy for any feedback

fixes vercel#23467

## Bug

- [x] Related issues linked using `fixes #number`
- [x] Integration tests added

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.

## Documentation / Examples

- [ ] Make sure the linting passes

* Add note about adding additional types (vercel#26545)

* Add note about adding additional types

* Update to bold edit also

* Apply suggestions from code review

Co-authored-by: Steven <steven@ceriously.com>

* Allow user to override next-image-loader (vercel#26548)

In PR vercel#26281, we solved one use case but broke another.

This PR will allow the user to [override the built-in loader](vercel#26281 (comment)) via custom webpack config.

* v11.0.2-canary.0

* chore: Enable Alex documentation linting for error pages (vercel#26526)

* Update SWR example to include fetcher function. (vercel#26520)

* Previous example doesn't work

* Apply suggestions from code review

* Update docs/basic-features/data-fetching.md

* lint-fix

Co-authored-by: Lee Robinson <me@leerob.io>
Co-authored-by: JJ Kasper <jj@jjsweb.site>

* tailwind examps upgraded to v2.2 (vercel#26549)



## Documentation / Examples

- [x] Make sure the linting passes

* doc: prettify docs for next script (vercel#26572)



x-ref: vercel#26518 (comment)

## Documentation / Examples

- [x] Make sure the linting passes

* Add logging when a custom babelrc is loaded (vercel#26570)

Partially solves vercel#26539 by adding back the log output when a config file is used



## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.

## Documentation / Examples

- [ ] Make sure the linting passes

* Add comment to not edit in next-env file (vercel#26573)

This adds a comment to the generated `next-env.d.ts` to mention it should not be edited pointing to the documentation which contains an example of adding custom types separately. 

x-ref: vercel#26560

## Documentation / Examples

- [x] Make sure the linting passes

* Separate node polyfill test from basic suite (vercel#26550)

* Separate node polyfill test from basic suite

* update test

* fix with-loading example for next 11 (vercel#26569)

## Documentation / Examples

- [X] Make sure the linting passes

This PR updates the with-loading example to follow the documentation of router events for next 11

* v11.0.2-canary.1

* Add trace url on bootup (vercel#26594)

* Add trace url on bootup

* Update whitelist -> accesslist

* Add name to webpack-invalidated

* v11.0.2-canary.2

* Add check for ObjectExpression when iterating on <link> tags for font optimization (vercel#26608)

Fixes vercel#26547



## Bug

- [x] Related issues linked using `fixes #number`
- [x] Integration tests added

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.

## Documentation / Examples

- [ ] Make sure the linting passes

* Enable Alex documentation linting for docs (vercel#26598)

* Add link to live demo already hosted (vercel#25718)

* Add link to live demo already hosted

To make it easier for people to simply see the live example without having to deploy a whole new project

* update link


Co-authored-by: JJ Kasper <jj@jjsweb.site>

* Update next/image docs for relative parent with layout=fill. (vercel#26615)

vercel#18739 (reply in thread)

* Fix GSP redirect cache error (vercel#26627)

This makes sure we don't attempt flushing cache info to disk for `getStaticProps` `redirect` items with `revalidate`

Fixes: vercel#20816

## Bug

- [x] Related issues linked using `fixes #number`
- [x] Integration tests added

* Correct statusCode when visiting _error directly (vercel#26610)

This fixes non-stop reloading when visiting `_error` directly in development caused by the `statusCode` being 200 unexpectedly while HMR returns the page as `invalid` which triggers `on-demand-entries` to reload the page. 

## Bug

- [x] Related issues linked using `fixes #number`
- [x] Integration tests added

Fixes: vercel#8036
x-ref: vercel#8033

* fix: next dynamic with jest (vercel#26614)



Fixes vercel#19862

Avoid executing `webpack` property on `loadableGenerated` of loadable component compiled from `next/dynamic` when `require.resolveWeak` is unavailable due to jest runtime missing `require.resolveWeak`.

## Bug

- [x] Related issues linked using `fixes #number`
- [x] unit tests added

* Ensure API routes are not available under the locale (vercel#26629)

This ensures API routes are not available under the locale path since API routes don't need to be localized and we don't provide the locale to the API in any way currently so the user wouldn't be aware if the localized API route was visited instead of the non-localized. 

Fixes: vercel#25790

## Bug

- [x] Related issues linked using `fixes #number`
- [x] Integration tests added

* v11.0.2-canary.3

* Fix image content type octet stream 400 (vercel#26705)

Fixes vercel#23523 by adding image content type detection

## Bug

- [x] Related issues linked using `fixes #number`
- [x] Integration tests added

* Update layouts example to persist state across client-side transitions. (vercel#26706)

* Update layouts example

* Update examples/layout-component/components/layout.js

Co-authored-by: JJ Kasper <jj@jjsweb.site>

* Fix typo on "occured" to "occurred" (vercel#26709)

* fix: typo occured -> occurred

* fix: typo occured -> occurred

* fix: typo occured -> occurred

* fix: typo occured -> occurred

* lint-fix


Co-authored-by: JJ Kasper <jj@jjsweb.site>

* [ESLint] Adds --max-warnings flag to `next lint` (vercel#26697)

Adds `--max-warnings` flag to `next lint` to enable setting of a maximum warning threshold.

Fixes vercel#26671

* update with-redux-toolkit-typescript (vercel#26714)



## Bug

- [X] Related issues linked using `fixes vercel#26713 `

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.

## Documentation / Examples

- [X] Make sure the linting passes

## Screenshots

After this small change the warning disappears.
![image](https://user-images.githubusercontent.com/47717492/123749377-fd56fb80-d8d2-11eb-8b70-dbb7f6f16050.png)

* Simplify `next-dev-server` implementation (vercel#26230)

`next-dev-server` having its own implementations of `renderToHTML` and `renderErrorToHTML` has historically made reasoning about streaming hard, as it adds additional places where status codes are explicitly set and the full HTML is blocked on.

Instead, this PR simplifies things considerably by moving the majority of the custom logic for e.g. hot reloading and on-demand compilation to when we're resolving the page to be loaded, rather than upfront when handling the request. It also cleans up a few other details (e.g. default error page rendering) that managed to creep into the base implementation over time.

One unfortunate side effect is that this makes compilation errors slightly more difficult. Previously, we'd render them directly. Now, we have to rethrow them. But since they've already been logged (by the watch pipeline), we have to make sure they don't get logged again.

* Update PR labeler action

* Simplify stats action (vercel#26751)

* Move code shared between server/client to "shared" folder (vercel#26734)

* Move next-server directory files to server directory (vercel#26756)

* Move next-server directory files to server directory

* Update tests

* Update paths in other places

* Support new hydrate API in latest react 18 alpha release (vercel#26664)

* fix: react 18 new hydration API

* support react 18

* compat latest react only, fix resolved version

* fix tests

* Some changes based on reactwg/react-18#5

* fix test

Co-authored-by: Tim Neutkens <timneutkens@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Disable build-output size specific tests (vercel#26769)

* Disable build-output size specific tests

* remove size-limit test

* lint-fix

* Add upstream `max-age` to optimized image (vercel#26739)

This solves the main use case from Issue vercel#19914.

Previously, we would set the `Cache-Control` header to a constant and rely on the server cache. This would mean the browser would always request the image and the server could response with 304 Not Modified to omit the response body.

This PR changes the behavior such that the `max-age` will propagate from the upstream server to the Next.js Image Optimization Server and allow browser caching. ("upstream" meaning external server or just an internal route to an image)

This PR does not change the `max-age` for static imports which will remain `public, max-age=315360000, immutable`.

#### Pros:
- Fewer HTTP requests after initial browser visit
- User configurable `max-age` via the upstream image `Cache-Control` header

#### Cons:
- ~~Might be annoying for `next dev` when modifying a source image~~ (solved: use `max-age=0` for dev)
- Might cause browser to cache longer than expected (up to 2x longer than the server cache if requested in the last second before expiration)

## Bug

- [x] Related issues linked using `fixes #number`

* Fix blurred image position when using objectPosition (vercel#26590)



## Bug

fixes vercel#26309

## Documentation / Examples

see vercel#26309

- [ ] Make sure the linting passes

* Update azure tests (vercel#26779)

* Stabilize relay-analytics test (vercel#26782)

* Leverage blocked page for _error (vercel#26748)



## Enhance

simplify detection for visiting `_error`

x-ref: vercel#26610

* Update codeowners to add new maintainers (vercel#26770)

* examples: fix typo `lunix` → `linux` (vercel#26796)



## Bug

- [ ] ~~Related issues linked using `fixes #number`~~
- [ ] ~~Integration tests added~~

## Feature

- [ ] ~~Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.~~
- [ ] ~~Related issues linked using `fixes #number`~~
- [ ] ~~Integration tests added~~
- [ ] ~~Documentation added~~
- [ ] ~~Telemetry added. In case of a feature if it's used or not.~~

## Documentation / Examples

- [x] Make sure the linting passes

* Update repo scripts to separate folder (vercel#26787)

* fix: detect loop in client error page (vercel#26567)

Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com>
Co-authored-by: Tim Neutkens <tim@timneutkens.nl>

* Update snapshot for font-optimization test (vercel#26823)

This fixes the `font-optimization` test failing from the links/content changing slightly in the snapshot. 

## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [ ] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.

## Documentation / Examples

- [ ] Make sure the linting passes

* Add `onLoadingComplete()` prop to Image component (vercel#26824)

This adds a new prop, `onLoadingComplete()`, to handle the most common use case of `ref`.

I also added docs and a warning when using `ref` so we recommend the new prop instead.
 
- Fixes vercel#18398 
- Fixes vercel#22482

* Add "Vary: Accept" header to /_next/image responses (vercel#26788)

This pull request adds "Vary: Accept" header to responses from the image optimizer (i.e. the /_next/image endpoint).

The image optimizer prefers re-encoding JPG files to WebP, but some browsers (such as Safari 14 on Catalina) do not yet support WebP. In such cases the optimizer uses the Accept header sent by the browser to send out a JPG response. Thus the optimizer's response may depend on the Accept header.

Potential caching proxies can be informed of this fact by adding "Vary: Accept" to the response headers. Otherwise WebP data may be served to browsers that do not support it, for example in the following scenario:
 * A browser that supports WebP requests the JPG. The optimizer re-encodes it to WebP. The proxy caches the WebP data.
 * After this another browser that doesn't support WebP requests the JPG. The proxy sends the WebP data to the browser.

- [x] Integration tests added
- [x] Make sure the linting passes

* Fix using-preact example deps (vercel#26821)

Fix after vercel#26133

* Add additional tests for image type detection (vercel#26832)

Adding additional tests. Follow up to vercel#26705

* Fix immutable header for image with static import & unoptimized (vercel#26836)

Fixes vercel#26587

* Update `publish-canary` script to include checkout (vercel#26840)

* Update `publish-canary` script to include checkout

* Update contrib with publishing section

* v11.0.2-canary.4

* Make sure 404 pages do not get cached by a CDN when using next start (vercel#24983)

Co-authored-by: Jiachi Liu <inbox@huozhi.im>
Co-authored-by: JJ Kasper <jj@jjsweb.site>

* Update to environment-variable.md (vercel#26863)



## Bug

- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added

## Feature

- [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [ ] Related issues linked using `fixes #number`
- [ ] Integration tests added
- [x] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.

## Documentation / Examples

- [ ] Make sure the linting passes

## Why the change
I lost quite a few hours figuring out why my environment variable was `undefined` in the browser.
I read about the built-in support and was like: "Oh nice" and didn't read much further. I missed the part about how you need to prefix your variables with `NEXT_PUBLIC_` in order to expose them to the browser.
I think a hint to this in the anchor link to that section will make it more discoverable as it's then mentioned near the top and will save people who are like me some time and a headache.

* Don't emit duplicate image files (vercel#26843)

fixes vercel#26607

This change makes it so the image loader plugin only emits a file while processing an image import for the client. The final generated image URL was already the same in SSR and CSR anyway, so this change doesn't have any functional impact.

I also changed the name of the static page in the image component tests, since it was causing some conflicts with the static assets folder.

* Add instructions on how to add nextjs.org/docs/messages urls (vercel#26865)

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>

* Rename example folder to with-notion

* Update references of example

* Reorder docs manifest and rename to Script Optimization. (vercel#26874)

So there's _conformance_ between the other docs / optimizations.

* Fix typo on "occured" to "occurred" (vercel#26876)

- Fix typo on "occured" to "occurred"

* Update README

Co-authored-by: Sam Robbins <samrobbinsgb@gmail.com>
Co-authored-by: Jiachi Liu <inbox@huozhi.im>
Co-authored-by: Peter Mekhaeil <4616064+petermekhaeil@users.noreply.github.com>
Co-authored-by: Rob Vermeer <rob@vermeertech.nl>
Co-authored-by: JJ Kasper <jj@jjsweb.site>
Co-authored-by: Brandon Bayer <b@bayer.ws>
Co-authored-by: Alex Castle <atcastle@gmail.com>
Co-authored-by: Vitaly Baev <ping@baev.dev>
Co-authored-by: Lee Robinson <me@leerob.io>
Co-authored-by: destruc7i0n <6181960+destruc7i0n@users.noreply.github.com>
Co-authored-by: Steven <steven@ceriously.com>
Co-authored-by: Joshua Byrd <phocks@gmail.com>
Co-authored-by: Pranav P <pranavkp.me@outlook.com>
Co-authored-by: Tim Neutkens <tim@timneutkens.nl>
Co-authored-by: John <john@rackles.io>
Co-authored-by: Tim Neutkens <timneutkens@me.com>
Co-authored-by: Vadorequest <ambroise.dhenain@gmail.com>
Co-authored-by: hiro <hiro0218@gmail.com>
Co-authored-by: Houssein Djirdeh <houssein@google.com>
Co-authored-by: Soham Shah <47717492+sohamsshah@users.noreply.github.com>
Co-authored-by: Gerald Monaco <gbmonaco@google.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
Co-authored-by: Nils Schönwald <nils@schoen.world>
Co-authored-by: D. Kasi Pavan Kumar <44864604+kasipavankumar@users.noreply.github.com>
Co-authored-by: Tobias Koppers <tobias.koppers@googlemail.com>
Co-authored-by: Joachim Viide <jviide@iki.fi>
Co-authored-by: Artur Sedlukha <sedlukha@icloud.com>
Co-authored-by: Paul van den Dool <paulvddool@msn.com>
Co-authored-by: hiro <hiroyuki.kikuchi@zozo.com>
kodiakhq bot pushed a commit that referenced this issue Jul 15, 2021
- Closes #23328  
- Related to #19914 
- Related to #22319 


## Feature

- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [x] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [x] Errors have helpful link attached, see `contributing.md`
@styfle
Copy link
Member

styfle commented Jul 15, 2021

Looks like we have 4 thumbs up and 0 thumbs down on the latest canary release after 2 weeks so I'm going to close this issue.

See my previous comment for more details.

Also, I created #27208 to track the the stale-while-revalidate feature request. Thanks!

@styfle styfle closed this as completed Jul 15, 2021
kodiakhq bot pushed a commit that referenced this issue Jul 19, 2021
In a previous PR (#27200), we added `minimumCacheTTL` to configure the time-to-live for the cached image. However, this was setting the `max-age` header.

This PR ensures that `minimumCacheTTL` doesn't affect browser caching, only the upstream header can affect browser caching.

This is a bit safer in case the developer accidentally caches something that shouldn't be and the cache needs to be invalidated. Simply delete the `.next/cache/images` directory.

- Related to #19914
- Related to #22319
flybayer pushed a commit to blitz-js/next.js that referenced this issue Aug 19, 2021
This solves the main use case from Issue vercel#19914.

Previously, we would set the `Cache-Control` header to a constant and rely on the server cache. This would mean the browser would always request the image and the server could response with 304 Not Modified to omit the response body.

This PR changes the behavior such that the `max-age` will propagate from the upstream server to the Next.js Image Optimization Server and allow browser caching. ("upstream" meaning external server or just an internal route to an image)

This PR does not change the `max-age` for static imports which will remain `public, max-age=315360000, immutable`.

#### Pros:
- Fewer HTTP requests after initial browser visit
- User configurable `max-age` via the upstream image `Cache-Control` header

#### Cons:
- ~~Might be annoying for `next dev` when modifying a source image~~ (solved: use `max-age=0` for dev)
- Might cause browser to cache longer than expected (up to 2x longer than the server cache if requested in the last second before expiration)

## Bug

- [x] Related issues linked using `fixes #number`
flybayer pushed a commit to blitz-js/next.js that referenced this issue Aug 19, 2021
- Closes vercel#23328  
- Related to vercel#19914 
- Related to vercel#22319 


## Feature

- [x] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR.
- [x] Related issues linked using `fixes #number`
- [x] Integration tests added
- [x] Documentation added
- [ ] Telemetry added. In case of a feature if it's used or not.
- [x] Errors have helpful link attached, see `contributing.md`
flybayer pushed a commit to blitz-js/next.js that referenced this issue Aug 19, 2021
)

In a previous PR (vercel#27200), we added `minimumCacheTTL` to configure the time-to-live for the cached image. However, this was setting the `max-age` header.

This PR ensures that `minimumCacheTTL` doesn't affect browser caching, only the upstream header can affect browser caching.

This is a bit safer in case the developer accidentally caches something that shouldn't be and the cache needs to be invalidated. Simply delete the `.next/cache/images` directory.

- Related to vercel#19914
- Related to vercel#22319
@balazsorban44
Copy link
Member

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@vercel vercel locked as resolved and limited conversation to collaborators Jan 28, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests