1
00:00:03,000 --> 00:00:05,423
The ReviewsPage now automatically

2
00:00:05,423 --> 00:00:07,038
lists all the reviews.

3
00:00:07,112 --> 00:00:11,185
And each individual ReviewPage is a dynamic route,

4
00:00:11,185 --> 00:00:14,384
so whenever we write a new Markdown file,

5
00:00:14,384 --> 00:00:17,393
a new page will be available automatically

6
00:00:17,393 --> 00:00:18,682
for the same path.

7
00:00:18,753 --> 00:00:22,101
But so far we only tested this dynamic

8
00:00:22,101 --> 00:00:24,215
route in the dev server.

9
00:00:24,303 --> 00:00:26,557
Let's add a log statement here,

10
00:00:26,783 --> 00:00:28,702
printing a message every time

11
00:00:28,702 --> 00:00:30,489
this component is rendered.

12
00:00:30,555 --> 00:00:32,887
And let's log the "slug" as well,

13
00:00:32,887 --> 00:00:36,576
so we can tell exactly which route was generated.

14
00:00:36,576 --> 00:00:39,336
Now, we know that the dev server

15
00:00:39,336 --> 00:00:42,962
always re-renders each page at every request.

16
00:00:42,962 --> 00:00:45,215
But what will happen in production?

17
00:00:45,215 --> 00:00:48,206
Let's stop the server, and see our how

18
00:00:48,206 --> 00:00:50,883
dynamic route works in production.

19
00:00:50,962 --> 00:00:53,591
First of all, we need to build our app,

20
00:00:53,882 --> 00:00:57,112
to create an optimized production build.

21
00:00:57,112 --> 00:00:59,804
The build output itself is quite interesting.

22
00:00:59,804 --> 00:01:02,287
If you notice, "/reviews/[slug]"

23
00:01:02,287 --> 00:01:04,691
has a lambda symbol next to it,

24
00:01:04,769 --> 00:01:07,434
not a circle like the other pages.

25
00:01:07,434 --> 00:01:09,806
At the bottom, it explains that

26
00:01:09,806 --> 00:01:11,566
the "lambda" means that

27
00:01:11,642 --> 00:01:15,603
that route "server-side renders at runtime".

28
00:01:15,603 --> 00:01:19,416
So, it's not a static page, like the other ones.

29
00:01:19,416 --> 00:01:21,709
Let's see what this means in practice,

30
00:01:21,709 --> 00:01:24,137
if we start the production server.

31
00:01:24,137 --> 00:01:25,908
Let's reload this page.

32
00:01:26,397 --> 00:01:29,179
You can see that the server rendered

33
00:01:29,179 --> 00:01:30,957
the ReviewPage 3 times:

34
00:01:31,034 --> 00:01:33,469
once for every different slug.

35
00:01:33,469 --> 00:01:36,212
Now, that's because of prefetching.

36
00:01:36,212 --> 00:01:38,489
We opened the Reviews page,

37
00:01:38,489 --> 00:01:42,028
that contains links to those three other pages,

38
00:01:42,028 --> 00:01:45,126
so the browser prefetched all the links.

39
00:01:45,126 --> 00:01:47,481
But what's more interesting thing is that

40
00:01:47,481 --> 00:01:51,177
the server rendered each page at runtime.

41
00:01:51,177 --> 00:01:53,098
This will be clearer if we look

42
00:01:53,098 --> 00:01:54,585
at an individual review.

43
00:01:54,647 --> 00:01:57,322
There's nothing new in the server logs,

44
00:01:57,322 --> 00:01:59,660
because this page had already been

45
00:01:59,660 --> 00:02:01,449
prefetched by the browser.

46
00:02:01,517 --> 00:02:03,918
But if we reload the same page,

47
00:02:03,918 --> 00:02:06,694
you can see that the server re-rendered

48
00:02:06,694 --> 00:02:08,261
the "hellblade" route.

49
00:02:08,332 --> 00:02:10,737
And every time we click reload,

50
00:02:10,737 --> 00:02:13,953
the server will re-render this page again.

51
00:02:13,953 --> 00:02:17,669
Every time the browser requests this URL path

52
00:02:17,669 --> 00:02:20,170
the server runs our component code

53
00:02:20,170 --> 00:02:24,253
and regenerates the HTML sent to the browser.

54
00:02:24,253 --> 00:02:28,284
So, this is what server-side rendering means.

55
00:02:28,284 --> 00:02:31,379
It basically works like the dev server,

56
00:02:31,379 --> 00:02:33,754
with the difference that, in production,

57
00:02:33,754 --> 00:02:36,401
it also prefetches all the links.

58
00:02:36,401 --> 00:02:39,801
But with this approach we lose the benefits

59
00:02:39,801 --> 00:02:42,174
of statically generated pages.

60
00:02:42,253 --> 00:02:45,064
Returning a static page is faster,

61
00:02:45,064 --> 00:02:48,126
because the HTML file was generated

62
00:02:48,126 --> 00:02:49,613
during the build,

63
00:02:49,700 --> 00:02:52,812
there's no need to render it at runtime.

64
00:02:52,812 --> 00:02:56,083
And also, server-side rendering requires

65
00:02:56,083 --> 00:02:58,127
running a Node.js server.

66
00:02:58,209 --> 00:03:00,957
It's not compatible with doing

67
00:03:00,957 --> 00:03:02,881
a static HTML export.

68
00:03:02,973 --> 00:03:07,066
So, is there any way to generate static pages,

69
00:03:07,066 --> 00:03:09,811
even when using a dynamic route?

70
00:03:09,811 --> 00:03:11,747
It is in fact possible.

71
00:03:11,747 --> 00:03:13,836
But we need to tell Next.js

72
00:03:13,836 --> 00:03:15,769
which routes to generate.

73
00:03:15,846 --> 00:03:19,451
Because "/reviews/[slug]" is just a pattern;

74
00:03:19,451 --> 00:03:21,921
it will match any path named

75
00:03:21,921 --> 00:03:23,862
"/reviews/" something.

76
00:03:23,950 --> 00:03:26,365
To generate some static pages

77
00:03:26,365 --> 00:03:28,446
Next.js will need to know

78
00:03:28,530 --> 00:03:31,131
exactly which "slugs" are available.

79
00:03:31,131 --> 00:03:33,633
We can provide that information

80
00:03:33,633 --> 00:03:36,054
by exporting an async function

81
00:03:36,135 --> 00:03:39,026
called "generateStaticParams".

82
00:03:39,835 --> 00:03:42,343
And here we need to return an array,

83
00:03:42,343 --> 00:03:45,149
specifying which routes are valid.

84
00:03:45,149 --> 00:03:48,433
Each element in this array must be an object,

85
00:03:48,433 --> 00:03:51,332
containing the params that will be passed

86
00:03:51,332 --> 00:03:53,312
to the ReviewPage component.

87
00:03:53,383 --> 00:03:56,518
Since this route has a "slug" parameter

88
00:03:56,518 --> 00:03:59,574
that's what we need to put inside this object.

89
00:03:59,574 --> 00:04:02,881
For example, we have a review for "hellblade".

90
00:04:02,881 --> 00:04:05,595
Then we can add another similar object,

91
00:04:05,595 --> 00:04:07,840
this time for "hollow-knight".

92
00:04:08,195 --> 00:04:11,178
Let's just return these two for the moment,

93
00:04:11,178 --> 00:04:12,961
and see what happens now,

94
00:04:13,258 --> 00:04:15,677
if we build our app for production.

95
00:04:17,418 --> 00:04:19,629
You can see that our dynamic route

96
00:04:19,629 --> 00:04:21,189
was treated differently.

97
00:04:21,254 --> 00:04:24,031
Under the "/reviews/[slug]" pattern

98
00:04:24,031 --> 00:04:26,673
there are now two specific paths:

99
00:04:26,673 --> 00:04:29,259
"hellblade", and "hollow-knight".

100
00:04:29,259 --> 00:04:32,806
Those are, of course, the two slugs we returned

101
00:04:32,806 --> 00:04:35,901
from our "generateStaticParams" function.

102
00:04:35,976 --> 00:04:38,600
Also, this route is now marked

103
00:04:38,600 --> 00:04:40,436
with a filled circle.

104
00:04:40,524 --> 00:04:43,149
At the bottom, it explains that

105
00:04:43,149 --> 00:04:45,605
that symbol stands for "SSG",

106
00:04:45,690 --> 00:04:48,670
which means "Static Site Generation".

107
00:04:48,670 --> 00:04:51,447
Now, this legend shows SSG as

108
00:04:51,447 --> 00:04:53,745
different from "Static",

109
00:04:53,841 --> 00:04:55,322
but, in practice,Â they're

110
00:04:55,322 --> 00:04:56,802
basically the same thing.

111
00:04:56,861 --> 00:04:59,352
SSG is also static.

112
00:04:59,352 --> 00:05:01,147
You may also notice that

113
00:05:01,147 --> 00:05:04,451
our ReviewPage was rendered during the build,

114
00:05:04,451 --> 00:05:07,244
with different values for each slug.

115
00:05:07,244 --> 00:05:09,485
This didn't happen before we

116
00:05:09,485 --> 00:05:11,647
added generateStaticParams.

117
00:05:11,727 --> 00:05:14,696
So this is how we can get Next.js

118
00:05:14,696 --> 00:05:16,945
to generate static pages,

119
00:05:17,035 --> 00:05:19,827
even when using a dynamic route.

120
00:05:19,827 --> 00:05:22,484
But we don't really want to hard-code

121
00:05:22,484 --> 00:05:24,832
all the possible slug values

122
00:05:24,832 --> 00:05:26,845
in generateStaticParams.

123
00:05:26,929 --> 00:05:28,875
We already have a "getReviews"

124
00:05:28,875 --> 00:05:30,692
function in this other file,

125
00:05:30,757 --> 00:05:33,512
that we could call to get all the reviews.

126
00:05:33,512 --> 00:05:37,204
However, this code reads each Markdown file,

127
00:05:37,204 --> 00:05:41,083
to load all the properties, like title and body.

128
00:05:41,083 --> 00:05:43,493
While in generateStaticParams

129
00:05:43,493 --> 00:05:45,404
we only need the slugs.

130
00:05:45,487 --> 00:05:49,065
So, to avoid reading many files unnecessarily,

131
00:05:49,065 --> 00:05:51,117
let's write a separate function,

132
00:05:51,885 --> 00:05:53,640
called "getSlugs".

133
00:05:54,225 --> 00:05:56,700
And here we can use the same code

134
00:05:56,700 --> 00:05:58,500
we wrote for getReviews,

135
00:05:58,575 --> 00:06:02,007
that lists all the files in the "content" folder,

136
00:06:02,007 --> 00:06:05,349
and extracts the "slugs" from the file names.

137
00:06:05,349 --> 00:06:09,300
We can simply return the slugs directly from here.

138
00:06:09,300 --> 00:06:11,371
Now, to avoid duplication, we

139
00:06:11,371 --> 00:06:13,228
can also replace this code

140
00:06:13,299 --> 00:06:16,553
with a call to our new "getSlugs" function,

141
00:06:16,553 --> 00:06:19,577
and the rest will work in the same way.

142
00:06:19,577 --> 00:06:21,915
We basically just moved some code

143
00:06:21,915 --> 00:06:23,756
into a different function.

144
00:06:23,827 --> 00:06:27,078
But this way, in "generateStaticParams",

145
00:06:27,078 --> 00:06:28,755
we can get all the "slugs"

146
00:06:28,818 --> 00:06:31,142
by awaiting the Promise returned

147
00:06:31,142 --> 00:06:32,595
by our new function.

148
00:06:32,668 --> 00:06:36,317
generateStaticParams is already async.

149
00:06:36,317 --> 00:06:38,690
Now, here we need to return an

150
00:06:38,690 --> 00:06:40,668
array like the one below,

151
00:06:40,747 --> 00:06:42,988
where each element is an object

152
00:06:42,988 --> 00:06:44,650
with a "slug" property.

153
00:06:44,723 --> 00:06:48,253
But this "slugs" variable is an array of strings.

154
00:06:48,253 --> 00:06:52,282
So we need to use "map" to transform each string

155
00:06:52,282 --> 00:06:55,472
into an object with the "slug" as a property.

156
00:06:55,472 --> 00:06:57,560
Note that we need parentheses

157
00:06:57,560 --> 00:06:59,432
around the object literal,

158
00:06:59,504 --> 00:07:02,476
otherwise JavaScript will treat the curly

159
00:07:02,476 --> 00:07:04,651
brackets as the function body.

160
00:07:04,724 --> 00:07:08,331
Anyway, we can now delete this hard-coded array,

161
00:07:08,331 --> 00:07:09,492
save this file,

162
00:07:09,492 --> 00:07:11,398
and go and build our app again,

163
00:07:11,398 --> 00:07:14,734
to see if our code works as intended.

164
00:07:15,618 --> 00:07:17,728
You can see that the dynamic route

165
00:07:17,728 --> 00:07:21,544
now resulted in three statically generated pages,

166
00:07:21,544 --> 00:07:23,638
one for each available review.

167
00:07:23,638 --> 00:07:25,330
That's what we wanted!

168
00:07:25,330 --> 00:07:27,483
Let's start the production server,

169
00:07:27,483 --> 00:07:30,400
and see how our application works now.

170
00:07:30,400 --> 00:07:32,832
If we reload the Reviews page,

171
00:07:32,832 --> 00:07:35,398
there's nothing in the server logs.

172
00:07:35,398 --> 00:07:38,178
And if we open the Hellblade review,

173
00:07:38,178 --> 00:07:41,104
even if we try reloading it a few times,

174
00:07:41,104 --> 00:07:44,604
again the server never renders any component.

175
00:07:44,604 --> 00:07:48,068
Because all the pages have been statically

176
00:07:48,068 --> 00:07:50,048
generated at build time.

177
00:07:50,130 --> 00:07:54,138
So, to recap: we can write a generateStaticParams

178
00:07:54,138 --> 00:07:54,792
function

179
00:07:54,874 --> 00:07:57,406
returning all the possible paths,

180
00:07:57,406 --> 00:08:00,118
and Next.js will generate static

181
00:08:00,118 --> 00:08:02,745
pages even for a dynamic route.

