Closed denis-sokolov closed 5 years ago
Hi @denis-sokolov Thank you for your issue and suggestion! I like the idea and think it would fit well into this plugin. But I have to research a bit first, how this would be possible with webpack. I'll update you as soon as I found something or even implemented it :)
In the last days I have put in quite a bit of effort to make responsive-loader work with my Next.js app, but now that it does it works mostly great, although I do miss out on some of the features of next-optimized-images.
Thanks for the link, I didn't know this loader yet. I think it can be supported and combined with the other parts of next-optimized-images, I'll try it out in the next days!
Hello @denis-sokolov How did you manage to integrate responsive-loader? I tried but the outputPath and publicPath don't seem to work correctly. I am looking forward to this integration.
// next.config.js
module.exports = {
webpack: (config, {}) => {
config.module.rules.push({
test: /\.(jpe?g|png)$/i,
loader: 'responsive-loader',
options: {
adapter: require('responsive-loader/sharp'),
placeholder: true,
placeholderSize: 50,
outputPath: 'static/images/',
publicPath: '_next/static/images/'
}
})
return config
}
}
I got the responsive-loader to work with hacks I don’t understand. There is something with the interaction between /_next
, /static
, and __webpack_public_path__
. Still, the following worked for me.
// Webpack config:
config.module.rules.push({
test: /\.(jpg)$/,
use: [
{ loader: __dirname + "/lib/Images/image-fixing-loader" },
{
loader: "responsive-loader",
options: {
adapter: require("responsive-loader/sharp"),
// Warning, dark magic here and in image-fixing-loader
name: "static/[name]-[hash].[ext]",
sizes: [210, 420, 700, 1200, 2000],
placeholder: true,
placeholderSize: 50
}
}
]
});
// image-fixing-loader:
module.exports = function loader(content) {
return content.replace(/__webpack_public_path__/g, JSON.stringify("/_next/"));
};
Are you able to use responsive-loader with next-optimized-images? I'm looking for a solution that combines image resizing and compression.
I’m not using them together, but the responsive-loader already does resizing for you! See the sizes
option. The images as included on the page will be loaded just the right size. If you also want to allow the user to click on an image to open the full version, you can link to any of the resized versions at your will, since the imported image in your code has a .images
property, which is an array of all the resized versions.
A short update from my side: I was able to add support for the responsive-loader to next-optimized-images yesterday. I'm now just waiting for responsive-loader to publish the newest version to npm (which doesn't require the __webpack_public_path__
-hack anymore). If that doesn't happen until the end of the weekend, I can maybe also publish a canary version of next-optimized-images with this hack, but I'd like to do it the clean way in the "real" (or production ready) version :)
But it won't take long until it is supported out of the box ;)
That's great to hear! As I understand it, responsive-loader resizes images and provides a srcset value, but it does not compress/optimize images, so that's why it'd be ideal to combine it with next-optimized-images. Is that right?
Version v2.2.0 has just been published which now supports image resizing.
If you had responsive-loader previously installed, make sure to also update it to v1.2.0 (earlier versions won't work correctly). Also, responsive-loader requires you to either install jimp
(node implementation, slower) or sharp
(binary, faster).
After adding the ?resize
query param, you can pass in any other available param of the responsive-loader to resize your image.
Example:
const oneSize = require('./images/my-image.jpg?resize&size=300');
const multipleSizes = require('./images/my-image.jpg?resize&sizes[]=300&sizes[]=600&sizes[]=1000');
export default () => (
<div>
{/* Single image: */}
<img src={oneSize.src} />
{/* Source set with multiple sizes: */}
<img srcSet={multipleSizes.srcSet} src={multipleSizes.src} />
</div>
);
I hope that it works as you have expected, otherwise please tell me :)
That's great to hear! As I understand it, responsive-loader resizes images and provides a srcset value, but it does not compress/optimize images, so that's why it'd be ideal to combine it with next-optimized-images. Is that right?
responsive-loader
actually already compresses images (not with imagemin but with either jimp or sharp) on its own when resizing them (you can specify a quality in the options). So if you want to resize all your images, you can also just use responsive-loader without next-optimized-images (although it is probably easier to add to a next.js project).
The main reason I added support for it is that you now can have both, next-optimized-images and responsive-loader. Without this support, you wouldn't be able to use both in your projects as both register loaders for .jpg and .png files.
So as of now, you can resize some of your images (with the ?resize
query param and responsive-loader) and still use all other features of next-optimized-images (optimizing, gif, svg and webp support, lqip, dominant colors, etc..) in your project for other images. This gives you maximum flexibility and available features.
Just a small note about compressing of resized images: responsive-loader provides a quality option but it looks like it only gets applied to jpeg images and not png. There is maybe a way to also optimize png images (and also other formats which responsive-loader doesn't support, like webp) with a custom adapter. But I currently don't have much time (end of the year, also end of the semester so exams start soon), but I'll explore this option in the semester break. Until then, you have the same features as you would have when just using responsive-loader out of the box.
I’ve tried it out and it works exactly as it should.
Small not, but while I have to manually add ?resize
to every single require
, this is really unappealing. Do you think it would make sense to add a configuration option to enable resize feature for all images by default? More generally, I’d love to set a “default query string” for all require calls.
Hi @denis-sokolov, thank you for trying it out! I don't know if a default query string for all imports would be possible and if it really makes sense because next-optimized-images would then have to do all work which webpack normally does. But yes, I think your other proposal should be possible (to use the responsive-loader per default for all jpg & png files). I'll try this out.
To understand your use-case better, do you use mostly the same sizes (so you define them in the loader options and then only add ?resize
to all your images) or do most of your images have a different size and you mostly define them in the resource query (?resize&size=300
)?
Sorry for misleading. Yeah, I meant a default query for images only. In my use-case I use the same sizes, but lots of pictures. I configure the sizes once and require pictures everywhere:
loader: "responsive-loader",
options: {
adapter: require("responsive-loader/sharp"),
sizes: [210, 420, 700, 1200, 2000],
}
<MyBlock image={require("./images/4.jpg")} />
<MyBlock image={require("./images/5.jpg")} />
<MyBlock image={require("./images/6.jpg")} />
I would like to be bold and say this is the most popular use-case. At the end of the day, the sizes
is an implementation detail. What I want displayed in my UI is a particular image. Some browsers will load a smaller version of the image, but this is not a concern of my design, it’s a technological performance detail.
For our use case, we don't use the same sizes for all images. We'd size them based off the resource query.
So, I think that I found an improvement for both use cases.
When you want to resize single images with the query param (e.g. my-image.jpg?size=300
or my-image.jpg?sizes[]=300&sizes[]=500
), you don't need the ?resize
prefix anymore (but it still works if you want it). Although if you need any other query of responsive-loader, you still need the resize prefix.
If you want all images to be resized with a global config (as of your use case @denis-sokolov), you can now overwrite the default loader with the defaultImageLoader
option.
All JPEG and PNG images will then directly be forwarded to the responsive-loader. But as this loader is more restrictive, the query params of next-optimized-images won't work anymore (e.g. responsive-loader can't handle inlined images etc.). But for all other types (SVG, WEBP and GIF), img-loader will still be used and the queries are still available there.
I hope that this improves the experience for both use cases. Both changes are available in version 2.3.0
which has just been published to npm.
This does work great and I have now switched to next-optimized-images and deleted the hacks from my code! \o/ Thank you.
Thanks for putting in all the work. Is there currently a way to resize WEBP images through a query param? If only responsive-loader would support WEBP...
My use-case is that I have a JPEG image and I want to provide the following to a picture
element:
Hi @jonasIv
Your use-case makes total sense and I guess other devs would also like that.
Unfortunately, this isn't possible at the moment. Mainly because responsive-loader doesn't support WEBP.
Implementing it directly in next-optimized-images would be too much work and I also don't think that it would be the correct place to do it. It would be way easier in the responsive-loader itself which also has the benefit that it could be used for non next.js projects.
I just saw that there is an issue in responsive-loader for exactly your request: https://github.com/herrstucki/responsive-loader/issues/42 and even a PR which had it implemented: https://github.com/herrstucki/responsive-loader/pull/58 Unfortunately, there hasn't been recent activity on it, but we could maybe ask there if this feature is still planned or they need help. If this gets implemented in responsive-loader, I will of course also adapt next-optimized-images (if necessary).
I'll close this for now as the main functionality has been implemented. I'll keep an eye open for the webp implementation in responsive-loader and update this package as soon as they added support for webp images.
I had an issue of getting "responsive-loader/sharp" working in "next-optimized-images" (v2.6.2) in year 2021. Here is what I did in order to make it working.
responsive-loader/sharp
.Change next.config.js
like below:
const withPlugins = require("next-compose-plugins");
const optimizedImages = require("next-optimized-images");
module.exports = withPlugins([
[
optimizedImages,
{
// See: https://github.com/cyrilwanner/next-optimized-images#responsive
responsive: {
adapter: require("responsive-loader/sharp"),
sizes: [300, 320, 640, 960, 1200, 1800, 2400],
placeholder: true,
placeholderSize: 40,
},
},
],
// your other plugins here
]);
./.next
folder (e.g. rm -rf ./.next
). Otherwise NextJS may pick not desired cached config.Use image in JSX
import multipleSizes from './media/1-OpenProject.png?resize'
export default function App() {
return (
<>
<img srcSet={multipleSizes.srcSet} src={multipleSizes.src} />
</>
);
}
rm -rf ./build && next build && next export -o build
) As result you have HTML generated as below:
<img
srcset="
/_next/static/images/1-OpenProject-300-8bd205d8fa6712a27d68d10d2fa96041.png 300w,
/_next/static/images/1-OpenProject-320-149721ce42ee5cc54bb9969e9527f858.png 320w,
/_next/static/images/1-OpenProject-640-43595f0f9dc6d2e17b557d7def96c796.png 640w,
/_next/static/images/1-OpenProject-960-1c9adea9078cf40f468c7a2a5d4041e0.png 960w,
/_next/static/images/1-OpenProject-1200-0f021a08f50c63c7b0f47c0f6eb921a6.png 1200w,
/_next/static/images/1-OpenProject-1800-70b7d4f7b788d3418cf7729e764e9951.png 1800w,
/_next/static/images/1-OpenProject-2400-5bbb6e6fcc73108fff95a32dc9cf346b.png 2400w
"
src="/_next/static/images/1-OpenProject-300-8bd205d8fa6712a27d68d10d2fa96041.png"
/>
Would you consider resizing images to be a part of the design goals of this module? It would be very convenient to keep original images in the project directory and in the importing code specify
require('./images/my-photo.jpg?resize=1000px')}
. From my point of view, resizing images down is a similar semantically operation as minifying with mozjpeg. What do you think?