1
00:00:00,000 --> 00:00:01,000
So the images are displayed,

2
00:00:01,000 --> 00:00:04,000
and NextJS tries to optimize them.

3
00:00:04,000 --> 00:00:06,000
But in my case here,

4
00:00:06,000 --> 00:00:10,000
where I'm using Cloudinary for hosting those images,

5
00:00:10,000 --> 00:00:12,000
that's not all I wanna do.

6
00:00:12,000 --> 00:00:17,000
Because image hosts like Cloudinary typically give you

7
00:00:17,000 --> 00:00:22,000
more ways of loading images and files in an optimized way.

8
00:00:23,000 --> 00:00:26,000
Image hosts like Cloudinary allow you

9
00:00:26,000 --> 00:00:28,000
to manipulate the image URL

10
00:00:29,000 --> 00:00:32,000
and add some extra configuration,

11
00:00:32,000 --> 00:00:34,000
some extra parameters to that

12
00:00:34,000 --> 00:00:37,000
URL that will trigger Cloudinary

13
00:00:37,000 --> 00:00:40,000
to generate multiple versions of an image file,

14
00:00:40,000 --> 00:00:43,000
and cache those different versions

15
00:00:43,000 --> 00:00:46,000
and serve those different versions to your application.

16
00:00:46,000 --> 00:00:50,000
So, Cloudinary will perform the image resizing then.

17
00:00:50,000 --> 00:00:54,000
But in order to use these Cloudinary capabilities,

18
00:00:54,000 --> 00:00:59,000
we have to manipulate the URL that's set as an image source.

19
00:00:59,000 --> 00:01:03,000
And we have to do that in our NextJS application.

20
00:01:03,000 --> 00:01:06,000
Now, how can we do that though?

21
00:01:06,000 --> 00:01:10,000
Well, you can add a special loader prop

22
00:01:10,000 --> 00:01:12,000
on the NextJS image element.

23
00:01:13,000 --> 00:01:17,000
And this loader prop wants a function as a value,

24
00:01:17,000 --> 00:01:21,000
a function that will be executed by NextJS

25
00:01:21,000 --> 00:01:25,000
when it determines the path of the image.

26
00:01:25,000 --> 00:01:27,000
So when it determines this source here,

27
00:01:28,000 --> 00:01:31,000
it will essentially funnel the source you're setting here

28
00:01:31,000 --> 00:01:35,000
through that loader function so that you can manipulate it,

29
00:01:35,000 --> 00:01:39,000
and overwrite the image path before the image

30
00:01:39,000 --> 00:01:41,000
is actually served and rendered onto the screen.

31
00:01:42,000 --> 00:01:45,000
Now, therefore, here I'll add a new function outside

32
00:01:45,000 --> 00:01:49,000
of the component function, and I'll name it imageLoader.

33
00:01:49,000 --> 00:01:51,000
The name is up to you though.

34
00:01:51,000 --> 00:01:54,000
And this will get a configuration object

35
00:01:54,000 --> 00:01:57,000
automatically passed in by NextJS.

36
00:01:57,000 --> 00:02:00,000
And I will log that configuration object

37
00:02:00,000 --> 00:02:02,000
so that we can see what's inside.

38
00:02:04,000 --> 00:02:08,000
And then I will actually return config.src

39
00:02:08,000 --> 00:02:10,000
because that's one property

40
00:02:10,000 --> 00:02:12,000
we'll have on this configuration object,

41
00:02:12,000 --> 00:02:14,000
which is the source we're setting here

42
00:02:14,000 --> 00:02:16,000
through that source prop.

43
00:02:16,000 --> 00:02:20,000
And I'm returning that unchanged for the moment

44
00:02:20,000 --> 00:02:23,000
so that the image is still displayed, though of course,

45
00:02:23,000 --> 00:02:25,000
at moment, we won't do anything about it,

46
00:02:25,000 --> 00:02:26,000
but that will change.

47
00:02:27,000 --> 00:02:30,000
But now we can use this image loader as a value

48
00:02:30,000 --> 00:02:32,000
for this loader prop.

49
00:02:33,000 --> 00:02:38,000
And if we now save everything and reload, the images,

50
00:02:38,000 --> 00:02:41,000
of course, are displayed as they were before.

51
00:02:41,000 --> 00:02:45,000
But if we open up the terminal to see the logs,

52
00:02:45,000 --> 00:02:49,000
we can see that our configuration object looks like this.

53
00:02:49,000 --> 00:02:52,000
It in the end has the source property,

54
00:02:52,000 --> 00:02:56,000
which has the source as we set it on the image

55
00:02:56,000 --> 00:03:00,000
then a width property which is very large here way too large

56
00:03:00,000 --> 00:03:04,000
because NextJS doesn't know how to size the image here.

57
00:03:05,000 --> 00:03:09,000
And a quality property which in my case here is undefined.

58
00:03:09,000 --> 00:03:13,000
Now, you can control the value of that quality property

59
00:03:13,000 --> 00:03:16,000
by adding the quality prop on the image element,

60
00:03:16,000 --> 00:03:20,000
and setting this to a numeric value between zero and 100,

61
00:03:20,000 --> 00:03:22,000
like for example 50.

62
00:03:22,000 --> 00:03:25,000
And you can do this whenever you're using

63
00:03:25,000 --> 00:03:27,000
the NextJS image component,

64
00:03:27,000 --> 00:03:30,000
and behind the scenes NextJS will generate,

65
00:03:30,000 --> 00:03:34,000
and serve the same image with that quality then instead

66
00:03:34,000 --> 00:03:37,000
of the native quality of the image.

67
00:03:37,000 --> 00:03:40,000
And that quality value you're setting here will then,

68
00:03:40,000 --> 00:03:43,000
for example, when using an image loader function

69
00:03:43,000 --> 00:03:44,000
as we're doing it here,

70
00:03:44,000 --> 00:03:47,000
be made available on this config object

71
00:03:47,000 --> 00:03:48,000
so that you can pick it up

72
00:03:48,000 --> 00:03:53,000
when generating that URL you wanna actually render.

73
00:03:53,000 --> 00:03:55,000
And that's what we'll work on next now.

74
00:03:55,000 --> 00:03:58,000
Generate a different URL so that we take advantage

75
00:03:58,000 --> 00:04:03,000
of those on-demand image optimization capabilities

76
00:04:03,000 --> 00:04:05,000
offered by Cloudinary.

77
00:04:05,000 --> 00:04:07,000
And therefore, this approach-approach, of course,

78
00:04:07,000 --> 00:04:11,000
only makes sense if you're using a host like Cloudinary,

79
00:04:11,000 --> 00:04:15,000
which does offer on-demand resizings and optimizations,

80
00:04:15,000 --> 00:04:17,000
which most static asset hosts

81
00:04:17,000 --> 00:04:20,000
like Cloudinary do support though.

82
00:04:20,000 --> 00:04:24,000
So, how can we now change that URL?

83
00:04:24,000 --> 00:04:27,000
Well, of course, if you don't know

84
00:04:27,000 --> 00:04:29,000
the backend you're working with,

85
00:04:29,000 --> 00:04:31,000
you might wanna check out its documentation.

86
00:04:31,000 --> 00:04:34,000
So here in the Cloudinary docs, you can, for example,

87
00:04:34,000 --> 00:04:38,000
learn how you can manipulate and change the URL

88
00:04:38,000 --> 00:04:41,000
to which the request is sent to change the image

89
00:04:41,000 --> 00:04:44,000
that's served back from Cloudinary.

90
00:04:44,000 --> 00:04:45,000
And you can change a lot there.

91
00:04:45,000 --> 00:04:48,000
You can, for example, crop it on demand,

92
00:04:48,000 --> 00:04:49,000
but you can also change the height

93
00:04:49,000 --> 00:04:52,000
and width of the served image file.

94
00:04:52,000 --> 00:04:55,000
And that's the part that's interesting to us here.

95
00:04:56,000 --> 00:04:58,000
For that, to apply those changes,

96
00:04:58,000 --> 00:05:03,000
we need to add parameters like this to the Cloudinary URL,

97
00:05:03,000 --> 00:05:06,000
and therefore we need to manipulate the URL we have

98
00:05:06,000 --> 00:05:08,000
in our application.

99
00:05:08,000 --> 00:05:11,000
Because at the moment it looks like this,

100
00:05:11,000 --> 00:05:15,000
and we now essentially need to add parameters like this

101
00:05:15,000 --> 00:05:18,000
in front of the image file name

102
00:05:18,000 --> 00:05:22,000
after this upload segment here in the path.

103
00:05:24,000 --> 00:05:26,000
So, we need to add those parameters

104
00:05:26,000 --> 00:05:29,000
after this upload segment in our path here.

105
00:05:30,000 --> 00:05:32,000
Therefore, in this image loader function,

106
00:05:32,000 --> 00:05:37,000
what we should do here is split this source path

107
00:05:37,000 --> 00:05:39,000
into two parts, one part,

108
00:05:39,000 --> 00:05:40,000
which is the file name and one part,

109
00:05:40,000 --> 00:05:45,000
which is everything up to including that upload segment.

110
00:05:46,000 --> 00:05:49,000
And I'll name the first part here URL start.

111
00:05:49,000 --> 00:05:52,000
And here I'll use my config source value,

112
00:05:52,000 --> 00:05:55,000
and call the built-in split function,

113
00:05:55,000 --> 00:05:59,000
which you can call on any string in JavaScript to split it

114
00:05:59,000 --> 00:06:01,000
on that upload segment,

115
00:06:01,000 --> 00:06:04,000
including that slash that comes after it.

116
00:06:04,000 --> 00:06:06,000
And that will then give me an array

117
00:06:06,000 --> 00:06:08,000
which includes two elements

118
00:06:08,000 --> 00:06:11,000
where the first element will essentially be this part.

119
00:06:13,000 --> 00:06:16,000
And the second element will be this part.

120
00:06:16,000 --> 00:06:18,000
And indeed, that version number here belongs

121
00:06:18,000 --> 00:06:20,000
to the file name and therefore should be included

122
00:06:20,000 --> 00:06:22,000
in that second part.

123
00:06:24,000 --> 00:06:28,000
So therefore, to get the first element,

124
00:06:28,000 --> 00:06:30,000
I'll access the first element in the array

125
00:06:30,000 --> 00:06:32,000
that's generated by split.

126
00:06:33,000 --> 00:06:37,000
And then I'll get my URL end here by using the same code,

127
00:06:37,000 --> 00:06:39,000
but getting the second element.

128
00:06:40,000 --> 00:06:44,000
And now we can insert our transformation parameters

129
00:06:44,000 --> 00:06:48,000
between these two segments, between start and end.

130
00:06:49,000 --> 00:06:53,000
Therefore, I'll add a transformations constant

131
00:06:53,000 --> 00:06:56,000
where I'll dynamically generate a string.

132
00:06:56,000 --> 00:06:58,000
And for that, I'll use backticks

133
00:06:58,000 --> 00:07:01,000
so that I can easily inject values into a string.

134
00:07:02,000 --> 00:07:03,000
Where I wanna set the width,

135
00:07:03,000 --> 00:07:05,000
which when using Cloudinary,

136
00:07:05,000 --> 00:07:09,000
is done by adding a parameter called W_,

137
00:07:09,000 --> 00:07:13,000
and then width value you want Cloudinary to generate

138
00:07:13,000 --> 00:07:14,000
for this image on the server.

139
00:07:16,000 --> 00:07:18,000
Here, I'll set this to, let's say,

140
00:07:18,000 --> 00:07:21,000
200 because we have very small images here,

141
00:07:21,000 --> 00:07:23,000
so I don't need a lot of width.

142
00:07:24,000 --> 00:07:28,000
Then, separate by a comma, I'll also set the height.

143
00:07:29,000 --> 00:07:32,000
And here I'll set this to 150

144
00:07:32,000 --> 00:07:34,000
because it's a bit less than the width.

145
00:07:34,000 --> 00:07:36,000
And rough values are good enough here

146
00:07:36,000 --> 00:07:38,000
because I don't care about

147
00:07:38,000 --> 00:07:40,000
getting the exact width and height

148
00:07:40,000 --> 00:07:41,000
that will be displayed on the screen.

149
00:07:41,000 --> 00:07:46,000
I just wanna make sure that I do get a much smaller image,

150
00:07:46,000 --> 00:07:48,000
and I do load a much smaller image

151
00:07:48,000 --> 00:07:52,000
than what the user uploaded, because there is no reason

152
00:07:52,000 --> 00:07:55,000
to load a large file if we then display it

153
00:07:55,000 --> 00:07:57,000
in a very small size.

154
00:07:58,000 --> 00:08:03,000
Last but not least, I also wanna get Cloudinary to generate

155
00:08:03,000 --> 00:08:05,000
an image at a different quality.

156
00:08:05,000 --> 00:08:08,000
And for that, we can add the Q_parameter.

157
00:08:08,000 --> 00:08:11,000
And then I actually wanna use the quality

158
00:08:11,000 --> 00:08:14,000
that was set here through the quality prop.

159
00:08:15,000 --> 00:08:19,000
And as you see, that is made available here.

160
00:08:19,000 --> 00:08:22,000
This output was before I added the quality prop.

161
00:08:22,000 --> 00:08:23,000
That's why it's undefined here,

162
00:08:23,000 --> 00:08:27,000
but it will be this value here if the quality prop is set.

163
00:08:27,000 --> 00:08:30,000
And therefore, I'll set this to the value I get

164
00:08:30,000 --> 00:08:32,000
from config.quality.

165
00:08:34,000 --> 00:08:37,000
Well, and with that, we can then return a new string,

166
00:08:37,000 --> 00:08:42,000
a new source path, which is essentially the URL start.

167
00:08:43,000 --> 00:08:46,000
Then we need to add upload/

168
00:08:48,000 --> 00:08:50,000
because we split on that value

169
00:08:50,000 --> 00:08:53,000
so that was actually excluded from the URL start.

170
00:08:55,000 --> 00:08:58,000
Then I inject my transformations.

171
00:08:59,000 --> 00:09:03,000
And then another/ and then URL end.

172
00:09:04,000 --> 00:09:08,000
And that's now the new path that will now get Cloudinary

173
00:09:08,000 --> 00:09:11,000
to resize and optimize the image

174
00:09:11,000 --> 00:09:14,000
on the Cloudinary servers already.

175
00:09:14,000 --> 00:09:15,000
And then the next image component

176
00:09:15,000 --> 00:09:19,000
will display that pre-optimized image.

177
00:09:20,000 --> 00:09:23,000
But the next component is used to make sure that this loader

178
00:09:23,000 --> 00:09:26,000
is executed before the image is rendered.

179
00:09:26,000 --> 00:09:28,000
So, that's what the next image component

180
00:09:28,000 --> 00:09:29,000
will do for us here.

181
00:09:31,000 --> 00:09:35,000
So now with that imageloader added, if you save everything,

182
00:09:35,000 --> 00:09:40,000
you'll see the images are loaded up, but they are distorted.

183
00:09:41,000 --> 00:09:43,000
And they are distorted because

184
00:09:43,000 --> 00:09:44,000
I'm setting a width and height here

185
00:09:44,000 --> 00:09:48,000
which doesn't necessary match the aspect ratio

186
00:09:48,000 --> 00:09:52,000
of the original image and therefore distortion happens.

187
00:09:53,000 --> 00:09:57,000
Now, one way to work around that would be to manipulate

188
00:09:57,000 --> 00:10:02,000
the Cloudinary URL to automatically crop the image as part

189
00:10:02,000 --> 00:10:06,000
of their resizing process so that the aspect ratio

190
00:10:06,000 --> 00:10:11,000
is kept and we don't distort the image.

191
00:10:11,000 --> 00:10:13,000
So, that's something you could do.

192
00:10:13,000 --> 00:10:15,000
But an alternative would be to remove

193
00:10:15,000 --> 00:10:20,000
this height resizing request here and just set the width.

194
00:10:21,000 --> 00:10:24,000
And with that, Cloudinary will make sure to resize

195
00:10:24,000 --> 00:10:25,000
the height automatically

196
00:10:25,000 --> 00:10:29,000
whilst keeping the original aspect ratio.

197
00:10:30,000 --> 00:10:34,000
And therefore, by changing this, if I save that and reload,

198
00:10:34,000 --> 00:10:37,000
you see that the distortion now is gone,

199
00:10:37,000 --> 00:10:42,000
but we still make sure that a smaller image is requested

200
00:10:42,000 --> 00:10:44,000
from that backend.

201
00:10:45,000 --> 00:10:46,000
And therefore with that,

202
00:10:46,000 --> 00:10:51,000
we make sure that no unnecessarily large images are loaded

203
00:10:51,000 --> 00:10:56,000
when serving images that have been uploaded by users.

204
00:10:56,000 --> 00:10:57,000
And that's therefore another way

205
00:10:57,000 --> 00:11:01,000
of using the NextJS image component.

206
00:11:01,000 --> 00:11:05,000
Here, we're using it with the fill prop and the loader prop

207
00:11:05,000 --> 00:11:10,000
to on-the-fly resize the image or request a resized image

208
00:11:12,000 --> 00:11:15,000
from the backend that hosts the images,

209
00:11:15,000 --> 00:11:20,000
so that we then serve and display the optimized image.

210
00:11:20,000 --> 00:11:22,000
In our header component on the hand,

211
00:11:22,000 --> 00:11:26,000
we were using a locally stored image that was part

212
00:11:26,000 --> 00:11:28,000
of the project,

213
00:11:28,000 --> 00:11:31,000
and we were using the image component to load

214
00:11:31,000 --> 00:11:35,000
that locally stored image in an optimized way.

215
00:11:35,000 --> 00:11:37,000
In that case, when using a local image,

216
00:11:37,000 --> 00:11:41,000
we then don't have to specify width and height,

217
00:11:41,000 --> 00:11:45,000
but we can still do it as a little workaround, so to say,

218
00:11:45,000 --> 00:11:49,000
to get NextJS to load a smaller image

219
00:11:49,000 --> 00:11:51,000
than the original image file,

220
00:11:51,000 --> 00:11:54,000
though it would be preferred to actually resize

221
00:11:54,000 --> 00:11:56,000
the original file.

222
00:11:56,000 --> 00:11:59,000
But these are some of the different ways of using

223
00:11:59,000 --> 00:12:02,000
this image component to optimize images

224
00:12:02,000 --> 00:12:04,000
on your NextJS website.

225
00:12:04,000 --> 00:12:08,000
As mentioned, you can learn more about configuring images

226
00:12:08,000 --> 00:12:10,000
and using this image component

227
00:12:10,000 --> 00:12:12,000
in the official documentation.

228
00:12:12,000 --> 00:12:16,000
Because, of course, there are a lot of different use cases

229
00:12:16,000 --> 00:12:17,000
for displaying images,

230
00:12:17,000 --> 00:12:20,000
and they all have different requirements.

231
00:12:20,000 --> 00:12:22,000
But I now hopefully got you started

232
00:12:22,000 --> 00:12:24,000
with the image component and showed you some

233
00:12:24,000 --> 00:12:27,000
of the most important features it offers.

234
00:12:27,000 --> 00:12:30,000
Now, one thing you might notice now

235
00:12:30,000 --> 00:12:32,000
that we basically finished our work

236
00:12:32,000 --> 00:12:35,000
on those user-generated images

237
00:12:35,000 --> 00:12:37,000
is that I'm getting a warning here

238
00:12:37,000 --> 00:12:40,000
in my developer tools JavaScript console

239
00:12:40,000 --> 00:12:43,000
that I should add the sizes prop

240
00:12:43,000 --> 00:12:46,000
when using the fill prop on an image

241
00:12:46,000 --> 00:12:47,000
to optimize performance.

242
00:12:48,000 --> 00:12:52,000
And indeed, in general, when using the fill prop,

243
00:12:52,000 --> 00:12:54,000
because you don't know the width

244
00:12:54,000 --> 00:12:57,000
and height of the loaded image in advance,

245
00:12:57,000 --> 00:13:00,000
it is recommended that you add the sizes prop,

246
00:13:00,000 --> 00:13:02,000
which I mentioned earlier already.

247
00:13:03,000 --> 00:13:07,000
And then you should use this sizes prop to set one

248
00:13:07,000 --> 00:13:11,000
or more sizes depending on the available viewport width.

249
00:13:12,000 --> 00:13:15,000
Now here it's special though.

250
00:13:15,000 --> 00:13:18,000
Due to the way I'm loading this image,

251
00:13:18,000 --> 00:13:20,000
where I'm loading this image loader function

252
00:13:20,000 --> 00:13:25,000
and where I enforce a certain width for this image,

253
00:13:25,000 --> 00:13:28,000
I actually don't really care about my sizes here

254
00:13:28,000 --> 00:13:31,000
because I make sure that I load an image

255
00:13:31,000 --> 00:13:33,000
of a certain width anyways.

256
00:13:33,000 --> 00:13:36,000
Therefore, what you could do in that case

257
00:13:36,000 --> 00:13:39,000
is actually get rid of fill

258
00:13:39,000 --> 00:13:44,000
and instead manually re-add width here

259
00:13:44,000 --> 00:13:46,000
and set that to 200, for example,

260
00:13:46,000 --> 00:13:51,000
because I know that here I'll be loading an image of a width

261
00:13:51,000 --> 00:13:54,000
of 200 because that's the setting I have here.

262
00:13:54,000 --> 00:13:59,000
So, the width of this image is actually no longer unknown.

263
00:14:00,000 --> 00:14:03,000
But of course, if I do that and I remove fill,

264
00:14:03,000 --> 00:14:05,000
and set the width

265
00:14:05,000 --> 00:14:06,000
and I try to load this page,

266
00:14:06,000 --> 00:14:08,000
I'll get an error that the required

267
00:14:08,000 --> 00:14:10,000
height property is missing.

268
00:14:10,000 --> 00:14:13,000
Because that's another required property you need to set

269
00:14:13,000 --> 00:14:16,000
if you're not importing a local image,

270
00:14:16,000 --> 00:14:18,000
and you're not using the fill prop.

271
00:14:20,000 --> 00:14:23,000
Now, the height, however, is something I don't know here

272
00:14:23,000 --> 00:14:27,000
because I leave that up to Cloudinary in this case.

273
00:14:27,000 --> 00:14:31,000
I'm just setting some width and I leave it up to Cloudinary

274
00:14:31,000 --> 00:14:34,000
to then adjust the height of the image appropriately.

275
00:14:36,000 --> 00:14:37,000
Now, what we could do here

276
00:14:37,000 --> 00:14:39,000
if we still wanna set the width,

277
00:14:39,000 --> 00:14:41,000
since we do know that in advance,

278
00:14:41,000 --> 00:14:46,000
is we could set any height that's about right here.

279
00:14:47,000 --> 00:14:49,000
Because in my use case here,

280
00:14:49,000 --> 00:14:52,000
this actually won't matter too much,

281
00:14:52,000 --> 00:14:54,000
because I'll be resizing the image

282
00:14:54,000 --> 00:14:58,000
and how it's displayed with CSS anyways.

283
00:14:58,000 --> 00:15:01,000
Now, we should just make sure that we go

284
00:15:01,000 --> 00:15:03,000
to the global CSS file,

285
00:15:03,000 --> 00:15:07,000
and there we should actually set the width and height

286
00:15:07,000 --> 00:15:10,000
of the image as it will be displayed due to CSS

287
00:15:10,000 --> 00:15:13,000
on the image element itself again, like this,

288
00:15:13,000 --> 00:15:17,000
so that it is displayed correctly with CSS.

289
00:15:19,000 --> 00:15:19,000
And with that,

290
00:15:19,000 --> 00:15:23,000
the images are still displayed correctly here,

291
00:15:23,000 --> 00:15:27,000
but I'm still performing those changes with Cloudinary,

292
00:15:27,000 --> 00:15:30,000
and I'm just setting width and height here to get rid

293
00:15:30,000 --> 00:15:32,000
of these extra warnings.

294
00:15:32,000 --> 00:15:35,000
And that's something you might consider doing

295
00:15:35,000 --> 00:15:37,000
from an optimization perspective.

296
00:15:37,000 --> 00:15:39,000
It actually won't really matter here

297
00:15:39,000 --> 00:15:42,000
because we were using Cloudinary

298
00:15:42,000 --> 00:15:45,000
for the image transformation and optimization anyways.

299
00:15:45,000 --> 00:15:47,000
Nonetheless, this is something you might

300
00:15:47,000 --> 00:15:49,000
wanna consider changing.

