The problem that we faced is that we experience troubles with initial page loading due to too many images attempting to load all at once, even if those images are not yet visible on the page (especially noticeable on devices, with slow internet connection)
🫢 Therefore we are facing a significant performance drop on initial page load, which is unacceptable in modern web:
To achieve faster loading times, developers use modern WebP
images and lazy loading
. This means images only download when they appear on screen.
Our motivation is that developers shouldn't think about trivial performance optimization and focus on more important work.
Therefore we introduced an automated image optimization technique that will produce all the necessary work by itself. The optimizations are performed in a super simple way:
🎉 Developers should use our brand new component API <Image />
. That will perform all the necessary optimizations automatically.
Is that the images that will be loaded on the start screen - must be loaded with high priority
, that means that for such images we need to disable lazy loading, because it makes no sense to load them lazily 🤷♂️, and will produce performance drop.
Familiar API - you can use the component just like basic img
element, all optimizations are handled behind the scenes for you.
// The old way
<img src={photo} alt="Person's photo">
// The new way (lazy loading is turned on implicitly)
<Image src={photo} alt="Person's photo" />
// Explicitly disabled lazy loading
// should be used if an image is on the start screen
<Image src={photo} alt="Person's photo" lazy="false" />
The src prop can accept image of any format - .jpg
, .jpeg
, .png
... Everything will be converted to WebP
behind the scenes.
🔮 In the very end this will produce such result:
<img loading="eager" srcset="/assets/rs-slope-nodejs-BmvHY6ZF-425.webp 425w, /assets/rs-slope-nodejs-BmvHY6ZF-768.webp 768w, /assets/rs-slope-nodejs-BmvHY6ZF.webp 1280w" sizes="(max-width: 425px) 425px, (max-width: 768px) 768px, 1280px" decoding="auto" fetchpriority="high" src="/assets/rs-slope-nodejs-BmvHY6ZF.webp" draggable="false" alt="Node.js">
- Any image of any format will be converted to
WebP
and compressed - If an image is already in
WebP
format it'll be only compressed SVG
are compressed as well, using SVGO- At the build step the 2 more variants of the image will be generated based on
env
variables breakpoints. By default it's768px
image fortablets
and425px
formobile
.
You can also correct the compression value from 1 to 100
- where 1
is the most compressed image and 100
is the most quality respectful.
env
variables in the build
script and in the optimizeImages
script. Because the env
variables are defined for the runtime of each script separately.
{
"build": "tsc && npx cross-env VITE_TABLET=768 VITE_MOBILE=425 vite build && npm run optimizeImages",
"optimizeImages": "npx cross-env VITE_TABLET=768 VITE_MOBILE=425 VITE_COMPRESS_QUALITY=80 node optimizeImages/optimizeImages.js"
}
Also should be mentioned that if an image is very small e.g 90px x 90px
and the env
variables are greater that this image size, no optimization will be performed for such image - therefore will not be created 2 different smaller sizes.
The <Image />
component also knows how to deal in such situation, and if there are no responsive image variants for tablet
and mobile
- it will fallback to basic src
image (in our case image of 90px x 90px
)
⚠️ To check if responsive images are generated - first build the project and then run npm run preview
.
You can check out the links with a deep dive into image optimization on the modern web that were used for our topic: