1
00:00:02,000 --> 00:00:04,000
Now that this works,

2
00:00:04,000 --> 00:00:05,000
let me come back to this content

3
00:00:05,000 --> 00:00:07,000
and let's see how we could make this content

4
00:00:07,000 --> 00:00:09,000
a bit more complex.

5
00:00:09,000 --> 00:00:12,000
To be precise, let's see how we could add images

6
00:00:12,000 --> 00:00:15,000
or code snippets to this content

7
00:00:15,000 --> 00:00:17,000
because since we're building a blog

8
00:00:17,000 --> 00:00:18,000
and we are developers,

9
00:00:18,000 --> 00:00:22,000
we might be blogging about development topics

10
00:00:22,000 --> 00:00:25,000
and that means that we also might wanna share code snippets

11
00:00:25,000 --> 00:00:27,000
as part of our posts.

12
00:00:27,000 --> 00:00:31,000
The great thing is that we can easily add such snippets

13
00:00:31,000 --> 00:00:33,000
and also images to Markdown

14
00:00:33,000 --> 00:00:35,000
but when it comes to rendering that,

15
00:00:35,000 --> 00:00:37,000
we'll face certain challenges,

16
00:00:37,000 --> 00:00:40,000
which we are going to solve together though.

17
00:00:40,000 --> 00:00:44,000
Let's start with adding images to our Markdown content.

18
00:00:44,000 --> 00:00:46,000
Attached, you find an updated

19
00:00:46,000 --> 00:00:50,000
getting-started-with-nextjs Markdown file.

20
00:00:50,000 --> 00:00:52,000
And you can replace your existing one with it.

21
00:00:52,000 --> 00:00:54,000
It has the same metadata

22
00:00:54,000 --> 00:00:57,000
but different content, just some dummy content

23
00:00:57,000 --> 00:01:00,000
with a list, another title

24
00:01:00,000 --> 00:01:02,000
and also with an image.

25
00:01:02,000 --> 00:01:05,000
This is how you include a image in Markdown.

26
00:01:05,000 --> 00:01:07,000
The problem is if you save that,

27
00:01:07,000 --> 00:01:11,000
and you reload this page, the image is not showing up

28
00:01:11,000 --> 00:01:14,000
because the path is incorrect.

29
00:01:14,000 --> 00:01:15,000
Now, we could fix the path here

30
00:01:15,000 --> 00:01:17,000
and change it to images/post

31
00:01:17,000 --> 00:01:20,000
and then our Slack,

32
00:01:20,000 --> 00:01:23,000
so getting-started-with-nextjs.

33
00:01:24,000 --> 00:01:26,000
Make sure you have no typos.

34
00:01:26,000 --> 00:01:28,000
And then also add that image,

35
00:01:28,000 --> 00:01:29,000
which you also find attached.

36
00:01:29,000 --> 00:01:31,000
You also need to do that.

37
00:01:31,000 --> 00:01:35,000
Attached, you find a Next.js file-based routing

38
00:01:35,000 --> 00:01:37,000
PNG dummy image,

39
00:01:37,000 --> 00:01:41,000
which you can also add to your posts folder

40
00:01:41,000 --> 00:01:42,000
in the images folder.

41
00:01:42,000 --> 00:01:45,000
So to this specific posts folder there.

42
00:01:46,000 --> 00:01:48,000
Now this path should be correct.

43
00:01:48,000 --> 00:01:51,000
Oops, that should be posts though

44
00:01:51,000 --> 00:01:53,000
but if you check for all typos,

45
00:01:53,000 --> 00:01:54,000
it should be correct

46
00:01:54,000 --> 00:01:57,000
and if you reload now, you should see the image here

47
00:01:57,000 --> 00:01:59,000
but we have a couple of problems.

48
00:01:59,000 --> 00:02:00,000
Clearly it's too big.

49
00:02:00,000 --> 00:02:02,000
It's not styled.

50
00:02:02,000 --> 00:02:03,000
Now, we could style it.

51
00:02:03,000 --> 00:02:05,000
That wouldn't be a problem.

52
00:02:05,000 --> 00:02:08,000
We could style it by simply adjusting the styles

53
00:02:08,000 --> 00:02:11,000
in the post-content.module file.

54
00:02:11,000 --> 00:02:13,000
We could target image elements here

55
00:02:13,000 --> 00:02:18,000
and for example, give them a max-width of 200 pixels

56
00:02:18,000 --> 00:02:19,000
or something like this

57
00:02:19,000 --> 00:02:21,000
and now it would be smaller.

58
00:02:21,000 --> 00:02:24,000
So that is a problem which we can solve.

59
00:02:24,000 --> 00:02:25,000
I'll get rid of this though.

60
00:02:25,000 --> 00:02:27,000
But that's something we could solve.

61
00:02:27,000 --> 00:02:30,000
The bigger problem is that we're not taking advantage

62
00:02:30,000 --> 00:02:33,000
of Next.js image optimizations here.

63
00:02:33,000 --> 00:02:34,000
If we inspect this,

64
00:02:34,000 --> 00:02:36,000
we see that it's a regular image element,

65
00:02:36,000 --> 00:02:38,000
which is being rendered here.

66
00:02:38,000 --> 00:02:41,000
And that is okay

67
00:02:41,000 --> 00:02:44,000
but we give up on all the optimization potential.

68
00:02:44,000 --> 00:02:48,000
For example, this is a huge image file, it's huge

69
00:02:48,000 --> 00:02:50,000
and even if I change the size in CSS,

70
00:02:50,000 --> 00:02:53,000
we still load this original file.

71
00:02:53,000 --> 00:02:56,000
And that's definitely not what we want.

72
00:02:56,000 --> 00:02:58,000
Lazy loading would also be nice to have

73
00:02:58,000 --> 00:03:00,000
because the image is not even visible

74
00:03:00,000 --> 00:03:02,000
when we start reading this post

75
00:03:02,000 --> 00:03:04,000
and therefore, it would be great

76
00:03:04,000 --> 00:03:07,000
if it is only loaded once we scroll there.

77
00:03:07,000 --> 00:03:10,000
And that's all something next/image does for us

78
00:03:10,000 --> 00:03:12,000
but not right now

79
00:03:12,000 --> 00:03:16,000
because by default, react-markdown translates an image

80
00:03:16,000 --> 00:03:19,000
in the Markdown file, so translates code like this

81
00:03:19,000 --> 00:03:21,000
into a regular image tag

82
00:03:21,000 --> 00:03:23,000
and that makes a lot of sense

83
00:03:23,000 --> 00:03:26,000
because how would it know that you want

84
00:03:26,000 --> 00:03:29,000
to have your own image transformation,

85
00:03:29,000 --> 00:03:32,000
that you want to use a different component?

86
00:03:32,000 --> 00:03:35,000
It doesn't know that but you can tell it.

87
00:03:35,000 --> 00:03:37,000
And therefore, first of all, I'll get rid

88
00:03:37,000 --> 00:03:42,000
of that path here and just stick to the image file name here

89
00:03:42,000 --> 00:03:44,000
because we will now override

90
00:03:44,000 --> 00:03:49,000
how react-markdown treats Markdown content like this,

91
00:03:49,000 --> 00:03:51,000
how it treats images.

92
00:03:51,000 --> 00:03:54,000
To override how certain elements are rendered,

93
00:03:54,000 --> 00:03:57,000
we can give react-markdown a special prop,

94
00:03:57,000 --> 00:04:01,000
the renderers prop.

95
00:04:01,000 --> 00:04:03,000
Renderers wants an object

96
00:04:03,000 --> 00:04:05,000
where you tell react-markdown

97
00:04:05,000 --> 00:04:08,000
how certain elements should be rendered.

98
00:04:08,000 --> 00:04:11,000
Now, you can't come up with your own elements here.

99
00:04:11,000 --> 00:04:13,000
Instead, there are built-in elements

100
00:04:13,000 --> 00:04:15,000
where you can override the default.

101
00:04:15,000 --> 00:04:18,000
The react-markdown documentation is the place to go

102
00:04:18,000 --> 00:04:20,000
for more details.

103
00:04:20,000 --> 00:04:23,000
There you find detailed usage instructions.

104
00:04:23,000 --> 00:04:25,000
You can also configure other things there

105
00:04:25,000 --> 00:04:29,000
and there, you also get like a list

106
00:04:29,000 --> 00:04:32,000
of the different elements it's able to render

107
00:04:32,000 --> 00:04:36,000
and the identifier in renderers.

108
00:04:37,000 --> 00:04:38,000
So for example, for an image,

109
00:04:38,000 --> 00:04:41,000
it by default renders the image element

110
00:04:41,000 --> 00:04:45,000
and we can target an image property

111
00:04:45,000 --> 00:04:49,000
in our renderers object if we wanna override it.

112
00:04:49,000 --> 00:04:52,000
So renderers are, let's say customRenderers

113
00:04:53,000 --> 00:04:55,000
is an object.

114
00:04:55,000 --> 00:04:57,000
That's what we should pass to renderers

115
00:04:57,000 --> 00:05:00,000
if we wanna override some renderers.

116
00:05:00,000 --> 00:05:03,000
And in this object we can now target identifiers

117
00:05:03,000 --> 00:05:04,000
like image here.

118
00:05:05,000 --> 00:05:06,000
Like this.

119
00:05:06,000 --> 00:05:08,000
And set them as a property

120
00:05:08,000 --> 00:05:11,000
or to be precise, as a method.

121
00:05:11,000 --> 00:05:14,000
And react-markdown will call this method

122
00:05:14,000 --> 00:05:18,000
if it finds a image in the Markdown content.

123
00:05:18,000 --> 00:05:21,000
We can do this for other kinds of elements as well

124
00:05:21,000 --> 00:05:22,000
as you see here.

125
00:05:23,000 --> 00:05:25,000
So here I'm interested in an image.

126
00:05:25,000 --> 00:05:26,000
If we find an image,

127
00:05:26,000 --> 00:05:29,000
then I don't wanna use the default image element

128
00:05:29,000 --> 00:05:32,000
but instead this method will be called.

129
00:05:32,000 --> 00:05:36,000
In this method, we get data about the image which was found

130
00:05:36,000 --> 00:05:39,000
and here we then should return our own JSX element.

131
00:05:39,000 --> 00:05:41,000
So we could return the built-in image

132
00:05:41,000 --> 00:05:45,000
but then we just do what react-markdown does anyways.

133
00:05:45,000 --> 00:05:47,000
And we set the src and so on.

134
00:05:47,000 --> 00:05:49,000
That's not what I'll do here.

135
00:05:49,000 --> 00:05:53,000
Instead, I'll return the Next.js image element,

136
00:05:53,000 --> 00:05:55,000
the Next.js image component,

137
00:05:55,000 --> 00:05:58,000
which we therefore, of course, also need to import.

138
00:05:58,000 --> 00:06:02,000
We import Image from next/image.

139
00:06:03,000 --> 00:06:04,000
Like this.

140
00:06:04,000 --> 00:06:06,000
So that's what we return here then

141
00:06:06,000 --> 00:06:09,000
and then we set the src to something,

142
00:06:09,000 --> 00:06:11,000
the alt text to something

143
00:06:11,000 --> 00:06:15,000
and also width and height.

144
00:06:15,000 --> 00:06:16,000
Like this.

145
00:06:16,000 --> 00:06:19,000
Now, let's start with alt.

146
00:06:19,000 --> 00:06:22,000
The image which we get here is actually an object

147
00:06:22,000 --> 00:06:26,000
with the image data react-markdown got

148
00:06:26,000 --> 00:06:28,000
from the Markdown text.

149
00:06:28,000 --> 00:06:30,000
And the alt text, for example,

150
00:06:30,000 --> 00:06:34,000
in Markdown is the text between those square brackets.

151
00:06:36,000 --> 00:06:38,000
So that is already made available

152
00:06:38,000 --> 00:06:43,000
by react-markdown and hence, we can set alt to image.alt.

153
00:06:46,000 --> 00:06:49,000
The name, the URL of the image,

154
00:06:49,000 --> 00:06:52,000
so the thing between the parentheses, this here,

155
00:06:52,000 --> 00:06:55,000
is also made available by react-markdown.

156
00:06:55,000 --> 00:06:57,000
It's also available on this image object

157
00:06:57,000 --> 00:06:59,000
and it's the image.url.

158
00:06:59,000 --> 00:07:02,000
But that's just a file name in our case.

159
00:07:02,000 --> 00:07:04,000
We need a full path here

160
00:07:04,000 --> 00:07:07,000
and for that, I'll create a template literal

161
00:07:07,000 --> 00:07:12,000
where I point at images/posts/post.slug,

162
00:07:12,000 --> 00:07:14,000
so the slug for this loaded post,

163
00:07:14,000 --> 00:07:17,000
slash and then this URL,

164
00:07:18,000 --> 00:07:21,000
this file name which was stored in the Markdown file.

165
00:07:21,000 --> 00:07:24,000
So in this case, image.url.

166
00:07:24,000 --> 00:07:25,000
So now that's that.

167
00:07:25,000 --> 00:07:27,000
Now, for width and height,

168
00:07:27,000 --> 00:07:30,000
it always comes down to how you present this to your styles

169
00:07:30,000 --> 00:07:31,000
and so on.

170
00:07:31,000 --> 00:07:33,000
Here a width of 600 and a height

171
00:07:33,000 --> 00:07:37,000
of 300 pixels should work quite well.

172
00:07:37,000 --> 00:07:41,000
Now with that, since we pass customRenderers to renderers,

173
00:07:41,000 --> 00:07:45,000
this next image will be rendered instead of a default image.

174
00:07:47,000 --> 00:07:48,000
If we save that,

175
00:07:48,000 --> 00:07:51,000
and reload, that fails.

176
00:07:52,000 --> 00:07:57,000
Actually because it's not image.url but image.src here, src.

177
00:07:57,000 --> 00:07:58,000
My bad.

178
00:07:58,000 --> 00:08:02,000
So image.src is the property on this image object,

179
00:08:02,000 --> 00:08:05,000
which holds a pointer at the image we're using

180
00:08:05,000 --> 00:08:07,000
and if we change this to image.src,

181
00:08:07,000 --> 00:08:09,000
we now see our image rendered here

182
00:08:09,000 --> 00:08:11,000
with the dimensions we gave it.

183
00:08:12,000 --> 00:08:14,000
But if we open the dev tools,

184
00:08:14,000 --> 00:08:17,000
we'll be greeted with a lot of warnings here.

185
00:08:17,000 --> 00:08:19,000
The warning in the end tells us

186
00:08:19,000 --> 00:08:22,000
that we're rendering a div inside of a paragraph

187
00:08:22,000 --> 00:08:23,000
because the next/image element

188
00:08:23,000 --> 00:08:25,000
is actually not just an image.

189
00:08:25,000 --> 00:08:28,000
Instead, it is wrapped in a couple of divs,

190
00:08:28,000 --> 00:08:31,000
which control its positioning and styling and so on.

191
00:08:31,000 --> 00:08:35,000
And that's all rendered automatically by Next.

192
00:08:35,000 --> 00:08:38,000
And that's then nested inside of a paragraph.

193
00:08:38,000 --> 00:08:41,000
Because Markdown is translated to HTML

194
00:08:41,000 --> 00:08:44,000
such that all content which is not a title

195
00:08:44,000 --> 00:08:46,000
or a list or something like this

196
00:08:46,000 --> 00:08:50,000
is treated as a paragraph, including images.

197
00:08:50,000 --> 00:08:52,000
We can ignore this, it works.

198
00:08:52,000 --> 00:08:54,000
But if we wanna get rid of that error,

199
00:08:54,000 --> 00:08:56,000
of that warning, which it is,

200
00:08:56,000 --> 00:09:00,000
we can also do that by not overriding the image

201
00:09:00,000 --> 00:09:03,000
but by instead getting a bit more tricky.

202
00:09:03,000 --> 00:09:05,000
Instead of only overriding images here

203
00:09:05,000 --> 00:09:06,000
in our customRenderer,

204
00:09:07,000 --> 00:09:11,000
we can actually have a look at all paragraphs,

205
00:09:11,000 --> 00:09:13,000
which are being rendered.

206
00:09:13,000 --> 00:09:15,000
So this now includes everything

207
00:09:15,000 --> 00:09:17,000
which would be rendered as a paragraph,

208
00:09:17,000 --> 00:09:21,000
including plain text, like this one or this one

209
00:09:21,000 --> 00:09:23,000
but also images, which as we just saw,

210
00:09:23,000 --> 00:09:26,000
are also rendered as paragraphs.

211
00:09:27,000 --> 00:09:29,000
Then here we still get

212
00:09:29,000 --> 00:09:32,000
that paragraph identified by react-markdown

213
00:09:32,000 --> 00:09:36,000
and we can return our own JSX element.

214
00:09:36,000 --> 00:09:41,000
And here the trick is that I only wanna override the default

215
00:09:41,000 --> 00:09:43,000
if we actually find that a image

216
00:09:43,000 --> 00:09:46,000
would be rendered inside of the paragraph

217
00:09:46,000 --> 00:09:49,000
and I will leave all other kinds of paragraphs alone.

218
00:09:50,000 --> 00:09:53,000
For this, we can extract the actual node

219
00:09:53,000 --> 00:09:56,000
which would be rendered by react-markdown

220
00:09:56,000 --> 00:10:01,000
from paragraph and then check if the node,

221
00:10:01,000 --> 00:10:03,000
if the first child of that node,

222
00:10:04,000 --> 00:10:07,000
if the type of that is image.

223
00:10:07,000 --> 00:10:10,000
So if we are trying to render a image element

224
00:10:10,000 --> 00:10:13,000
as a direct child of that paragraph.

225
00:10:13,000 --> 00:10:16,000
If we do render an image inside of the paragraph,

226
00:10:16,000 --> 00:10:20,000
I will override what react-markdown wants to render

227
00:10:20,000 --> 00:10:23,000
and instead of rendering a paragraph with the image

228
00:10:23,000 --> 00:10:27,000
inside of it, I then instead want to render just an image,

229
00:10:27,000 --> 00:10:29,000
just my next image.

230
00:10:29,000 --> 00:10:31,000
So for this, I'll then get my image

231
00:10:31,000 --> 00:10:35,000
by accessing node.children and then the first child

232
00:10:35,000 --> 00:10:38,000
and then I'll return a div actually

233
00:10:38,000 --> 00:10:43,000
with some extra styling where I add a class of image.

234
00:10:43,000 --> 00:10:47,000
That's simply a class I defined here in the CSS file.

235
00:10:48,000 --> 00:10:51,000
And in there, I'll then render this next image.

236
00:10:51,000 --> 00:10:54,000
So here I'll just repeat the code from up there,

237
00:10:54,000 --> 00:10:59,000
grab that code, add it here like this.

238
00:11:00,000 --> 00:11:01,000
And we're good.

239
00:11:02,000 --> 00:11:05,000
Now we can get rid of this customRenderer

240
00:11:05,000 --> 00:11:08,000
and I'll comment it out so that we still see it

241
00:11:08,000 --> 00:11:09,000
but will not use it anymore

242
00:11:09,000 --> 00:11:11,000
because we will now change image

243
00:11:11,000 --> 00:11:13,000
by looking into paragraphs

244
00:11:13,000 --> 00:11:14,000
and looking for images there

245
00:11:14,000 --> 00:11:17,000
and then replacing the entire paragraph

246
00:11:17,000 --> 00:11:18,000
with a div with the image.

247
00:11:19,000 --> 00:11:23,000
Now, otherwise, if we don't make it into this if check,

248
00:11:23,000 --> 00:11:28,000
I will return a regular paragraph with paragraph.children

249
00:11:29,000 --> 00:11:30,000
inside of it.

250
00:11:30,000 --> 00:11:34,000
So I'll basically render what react-markdown

251
00:11:34,000 --> 00:11:36,000
would have rendered otherwise.

252
00:11:36,000 --> 00:11:37,000
So I'll just use

253
00:11:37,000 --> 00:11:40,000
that unchanged content it identified wrapped

254
00:11:40,000 --> 00:11:42,000
in a regular paragraph.

255
00:11:43,000 --> 00:11:46,000
If we do this and reload,

256
00:11:46,000 --> 00:11:48,000
the image is broken simply

257
00:11:48,000 --> 00:11:52,000
because here it's now actually not image.src but image.url.

258
00:11:53,000 --> 00:11:56,000
That can be confusing but it is different here

259
00:11:56,000 --> 00:11:58,000
when we're not handing just a image

260
00:11:58,000 --> 00:12:01,000
but a paragraph that may contain an image.

261
00:12:01,000 --> 00:12:04,000
Then the image, which we get from inside the paragraph

262
00:12:04,000 --> 00:12:08,000
has the file name stored in a URL property

263
00:12:08,000 --> 00:12:11,000
instead of src but with that it works.

264
00:12:11,000 --> 00:12:15,000
And that's now the image presented on the screen.

265
00:12:15,000 --> 00:12:19,000
Now rendered again with Next.js

266
00:12:19,000 --> 00:12:21,000
as we can tell by the complex structure here

267
00:12:21,000 --> 00:12:24,000
and the fact that different images are fetched

268
00:12:24,000 --> 00:12:26,000
for different screen resolutions

269
00:12:26,000 --> 00:12:28,000
and in the console if we reload,

270
00:12:28,000 --> 00:12:30,000
we have no warnings.

271
00:12:30,000 --> 00:12:32,000
And that's how we can override

272
00:12:32,000 --> 00:12:35,000
how certain elements are rendered.

273
00:12:35,000 --> 00:12:37,000
And the image was just one example

274
00:12:37,000 --> 00:12:41,000
because another popular use case could be code snippets.

275
00:12:41,000 --> 00:12:44,000
That's what we're going to do explore in the next step.

