We're now using the Next.js server
for Image Optimization.
In this section we'll talk about other features
that are only available when running
our app in the Next.js server,
such as dynamic rendering.
To see how pages are rendered
I'll re-enable these log statements
in each page component.
But rather than the full "review" object
we could print only the "slug".
Which means we can move this line up.
Let's quickly do the same in the other pages.
Instead of the "reviews" array,
here we could print just the slugs
by iterating over each "review"
and extracting its "slug".
So we're transforming this
from an array of objects
into an array of strings.
We could also "join" the strings at the end
separating them with commas.
Let's do the same thing in the HomePage as well,
where we also have a "reviews" array,
but let's use the right component name.
With this, in the server logs we'll see
both when the HomePage is rendered
and which reviews it loaded,
but showing only the slugs so
it all fits in a single line.
Now, there's another interesting
thing going on here.
Next.js also logs each "fetch" request.
This is not a message coming from our code,
it's the Next.js dev server that
prints this automatically.
And, if you notice, it also includes
something about a "cache".
In this case it says the request was a "HIT",
meaning that the data was already in the cache.
So, Next.js automatically caches
all our "fetch" requests.
We can see this if we look
inside the ".next" folder.
Under "cache", along with the "images",
there's also a "fetch-cache" folder.
Now, I'm not going to show you
what's inside each file,
because it's a bit complicated,
but essentially Next.js saves each HTTP response,
so if our code makes the same request again
"fetch" will return the cached data
without sending another request
to Strapi for example.
As we'll see, the "fetch" cache
also has an impact on
how our pages are rendered.
Anyway, let's go and do a production build.
I'm going to remove the ".next" folder first,
to make sure it's not using any cached data.
The "rm" command is available on any Unix-like system,
including macOS.
On Windows you can use "rmdir" instead.
Anyway, let's do an "npm run build",
and generate the pages for production.
In the build output we can see
when each page component was rendered.
ReviewPage was called multiple times,
one for each slug.
In fact, it seems like all components
are called twice.
This may be because for each page Next.js
generates both an HTML file
and another file containing data
used by React Server Components.
In any case, it should have prerendered
all our components.
And in fact, in the route table
all pages have a circle symbol,
meaning they were statically generated.
So, if we go and start the production server
we should see that we can load any page
without it being re-rendered by the server.
Incidentally, there's a warning
about Image Optimization.
It says that in production we should
install the "sharp" package.
That's a library that provides
faster image conversions.
If you're setting up your own Next.js server
you should definitely install
that package as well.
But since I'm only running the
production server locally
I'll skip that step.
The "sharp" package is quite big, because it
includes binaries for various platforms.
Anyway, back to page rendering,
if we clear the logs
and then load a few different pages,
we can see that the server never
renders our components.
All pages have been statically
generated at build time
so whenever we request a page
the server simply returns the pregenerated file.
We've seen this before,
in one of the first sections of the course.
But things are a bit different now,
in that the data displayed on
the pages comes from the CMS.
It's no longer in files inside
the same Next.js project.
So we need think about
what happens if we modify the data in Strapi?
How will this affect our pages?
Now, before we actually change some data,
let me sort this list in the same
order we use in our app.
We can configure this view,
and sort the entries by
there is no "publishedAt" field here,
but we can use "updatedAt" that's close enough,
and we want descending order.
If we save, and confirm,
we should then see that
the entries are sorted like
we see them in our pages,
with "Hades" at the top.
Ok. Now, something we certainly
want to do on our website
is be able to publish new reviews.
Just for testing,
rather than creating a new entry from scratch,
I'm going to duplicate an existing one,
by clicking this button.
This way we don't have to fill in all the fields,
we can simply change the "title" for example.
Let's pretend "Cuphead 2" has been released,
and then we must change the "slug" as well,
because it needs to be unique.
Ok, let's save this as a new entry.
And we also need to publish it separately,
otherwise it remains in Draft.
But you can see that
"Cuphead 2" is now the most
recent entry in the list.
So, ideally we'd like our pages
to reflect that change.
However, since all our pages are
currently statically generated,
we'll always see the old data.
Unless we go and rebuild our application.
The Home page will always show "Hades"
as the most recent title,
and so will the Reviews page.
Clearly, if we want to be able to
publish new reviews from the CMS
we cannot simply generate fully
static pages any more.
We'll see how to enable dynamic
rendering in the next video.
But first, I want to show you that
there's already something different
when running our app in the Next.js server,
rather than as a statically exported website.
What if we manually open the
URL for the new review,
by typing "cuphead-2" here?
If you try this with a static website
you'll get a 404 page,
because "cuphead-2" wasn't one of the slugs
statically generated during the build.
But let's see what happens
with the Next.js server.
You can see that it generated
the new page on demand.
It rendered the ReviewPage dynamic route
passing "cuphead-2" as the slug.
And it returned the new page to the browser.
Now, if we go and reload this page,
there's nothing new in the server logs.
Once this page has been generated
it behaves just like any other static page.
The only difference is that this
one was rendered at runtime,
when it was first requested,
rather than at build time.
Note that, if we go to the Reviews page,
we still don't see "Cuphead 2" here.
And same for the Home page.
These pages will always stay as they are,
because they were statically
generated during the build.
The "cuphead-2" page was generated on demand
only because the server received a new path
for a dynamic route.
If you remember, in the ReviewPage
we have the "generateStaticParams" function
that returns an array with all
the known "slug" parameters,
so that Next.js can generate all
the static pages at build time.
Now, if at runtime the server receives a request
for a slug that wasn't in the list
generated during the build,
then by default it will render
that new route on demand.
You can configure this behaviour by setting
a property at the top-level.
You can find this in the documentation.
There is an option called "dynamicParams"
that defaults to "true".
We can configure this explicitly
in our "page.jsx" file.
"true" means that it will generate
the new page on demand,
which is what we just saw in action.
If we change this to "false" however,
then requesting a path that wasn't statically
generated during the build
would result in a 404 Not Found.
Feel free to test this if you like.
But in our application
we do want to generate a new page
when we add a new review in the CMS.
So we want "dynamicParams" to be true,
that is the default behaviour,
so we can leave it out.
As mentioned, in the next video we'll see
how to update the Home and Reviews pages as well.