You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If a higher resolution version of an image you are requesting has already been loaded, show that instead.
If a lower resolution version of an image you are requesting exists, use that as a placeholder until the higher resolution has been loaded.
Non-Goals
No response
Background
We're moving to NextJS. Previously we have run React with regular server-side rendering on both Node and even with C# (a story for another time). We build mainly e-commerce sites, so we are very image heavy. The same image often appears in multiple places and in multiple sizes across different pages.
One optimization we've made is to have a client-side cache to keep track of which images have been loaded and should be in the browser cache. This has allowed us to cut down on the amount of requests by complementing the browser cache with a layer that takes priority into account. If it's the same image, but you already have a higher resolution version cached, there is no reason to send another request, just show the higher resolution version. And if there is no higher resolution cached, but you do have a lower resolution version cached - show the lower res version as a placeholder until the higher res version has loaded, making the site appear faster because you're presenting the user with an image instantly.
Proposal
I'm not versed enough in the NextJS codebase to suggest a concrete solution, nor am I aware of which edge cases exist. But after looking at the code for next/image it seems possible for sure. No matter what, this is a feature we will be building into a custom component wrapping the next/image component, but would be pretty cool to see support from next directly too, and also hear what other thoughts/ideas other people have regarding this.
Issues and considerations
There is at least one issue that I have spotted so far, and that's the images that are preloaded on the server. Somehow we'd have to inform the client of which images that was, so that the cache can be initialized with an initial state including even those.
You could prioritize width only, but there could also be situations where you want to take quality or something else into account. Exposing methods to manually invalidate the cache, whitelist/blacklist etc could also be useful when thinking about this problem in a library/framework context.
Basic example
Here's a quick, naive example just to show what I'm talking about, it's for demonstrating the concept only:
importNextImagefrom'next/image';typeCacheEntry={width: number;// highest resolution in cacheloadedSrc: string;};typeCacheResult={src: string;status: 'uncached'|'cached'|'placeholder'}constimageCache=newMap<string,CacheEntry>();functionqueryImageCache(src: string,width: number): CacheResult{// check if image is in cacheconstmaybeCachedImage=imageCache.get(src);if(maybeCachedImage){// cache hitif(maybeCachedImage.width>=width){// image of equal or higher quality is cached, return urlreturn{src: maybeCachedImage.loadedSrc,status: 'cached'};}if(maybeCachedImage.width<width){// image of lower res found, can be used as placeholder while fetching higher resreturn{src: maybeCachedImage.loadedSrc,status: 'placeholder'};}}// cache missreturn{
src,status: 'uncached',}}exportfunctionImageComponent({ src, width }){constcache=queryImageCache(src,width);functionupdateCache(event: React.SyntheticEvent<HTMLImageElement>){constloadedImage=event.currentTarget;imageCache.set(src,{loadedSrc: loadedImage.src, width });}if(cache.status==='uncached'){return<NextImagesrc={src}/>;}elseif(cache.status==='placeholder'){return<NextImagesrc={src}blurDataURL={cache.src}onLoad={updateCache}/>;}else{return<NextImagesrc={cache.src}onLoad={updateCache}/>;}}
Step by step scenario
Let's follow the image cache handling of "Product A" in an e-commerce site purchase flow.
A user visits your site and navigates to a product listing.
Products and their images load, using a preset that loads 400px wide images.
User clicks the product card for Product A and is sent to the product page. Here, the main product image is requested with a preset that wants a 1200px image. Now, since we already have a 400px version of the same product image, the cache will respond with it as a placeholder, allowing us to show it instantly. A request for the 1200px image will start and it will replace the 400px image as soon as it's finished loading. The cache is also updated with the 1200px url.
User adds the product to their cart and clicks the link to the checkout page. Here, the contents of the cart is shown in a list, with thumbnails for each line. Now, the same Product A image will be requested with a 180px preset. Since the highest cached image is 1200px, we will not send a request for a 180px version, but instead just set the URL to the 1200px cached image, letting the browser cache serve it instantly.
An opt-in feature
The value of having this enabled everywhere by default could be discussed if it would be worth it, especially depending on the context you might find yourself in. We have this as an opt-in feature per image component. So if you have visited a bunch of products and looked at the full resolution image, there's no point in rendering 40 3000x4000 images in a listing just because they're cached, at that point you might get a negative result instead. You might even argue that the "use a higher resolution image in place of a lower resolution image" gets ineffective at a certain point and only want to opt-in to the "use the lower resolution, cached image as a placeholder while loading the high resolution one"-behavior.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Goals
Non-Goals
No response
Background
We're moving to NextJS. Previously we have run React with regular server-side rendering on both Node and even with C# (a story for another time). We build mainly e-commerce sites, so we are very image heavy. The same image often appears in multiple places and in multiple sizes across different pages.
One optimization we've made is to have a client-side cache to keep track of which images have been loaded and should be in the browser cache. This has allowed us to cut down on the amount of requests by complementing the browser cache with a layer that takes priority into account. If it's the same image, but you already have a higher resolution version cached, there is no reason to send another request, just show the higher resolution version. And if there is no higher resolution cached, but you do have a lower resolution version cached - show the lower res version as a placeholder until the higher res version has loaded, making the site appear faster because you're presenting the user with an image instantly.
Proposal
I'm not versed enough in the NextJS codebase to suggest a concrete solution, nor am I aware of which edge cases exist. But after looking at the code for
next/image
it seems possible for sure. No matter what, this is a feature we will be building into a custom component wrapping thenext/image
component, but would be pretty cool to see support fromnext
directly too, and also hear what other thoughts/ideas other people have regarding this.Issues and considerations
There is at least one issue that I have spotted so far, and that's the images that are preloaded on the server. Somehow we'd have to inform the client of which images that was, so that the cache can be initialized with an initial state including even those.
You could prioritize width only, but there could also be situations where you want to take quality or something else into account. Exposing methods to manually invalidate the cache, whitelist/blacklist etc could also be useful when thinking about this problem in a library/framework context.
Basic example
Here's a quick, naive example just to show what I'm talking about, it's for demonstrating the concept only:
Step by step scenario
Let's follow the image cache handling of "Product A" in an e-commerce site purchase flow.
Cache status:
Cache status:
An opt-in feature
The value of having this enabled everywhere by default could be discussed if it would be worth it, especially depending on the context you might find yourself in. We have this as an opt-in feature per image component. So if you have visited a bunch of products and looked at the full resolution image, there's no point in rendering 40 3000x4000 images in a listing just because they're cached, at that point you might get a negative result instead. You might even argue that the "use a higher resolution image in place of a lower resolution image" gets ineffective at a certain point and only want to opt-in to the "use the lower resolution, cached image as a placeholder while loading the high resolution one"-behavior.
Beta Was this translation helpful? Give feedback.
All reactions