Next.js by Example - Course Extract

Next.js by Example - Course Extract


Next.js by Example - Course Extract

Extract from the Next.js by Example course.

For the full course (over 8 hours) go to https://encoded.io/nextjs

Described as “The React Framework for Production”, Next.js makes it easy to build highly optimized web applications in React.

This course will guide you through learning Next.js by developing two examples: a fully static website, and a hybrid (static + server-side rendered) app.

The first example, a personal blog website, will introduce you to fundamental Next.js concepts such as pre-rendering, file-system based routing, and hydration.

It will show you how to load data in pages that are statically generated at build time, and how to style your pages in global CSS files or with the styled-jsx library that provides component-scoped styles…

Lectures:
00:00:00 - Next Blog: Overview
00:02:21 - Next.js Project Setup
00:09:19 - Pre-rendering
00:15:23 - Development vs Production Server
00:23:21 - Adding New Pages
00:26:40 - Next Link Component
00:31:19 - Shared NavBar Component
00:36:06 - Custom App Component
00:41:11 - Next Head Component
00:44:31 - Global Styles
00:49:14 - Component Styles with Styled JSX
00:55:55 - Images and Other Assets
01:00:38 - First Post Page
01:03:22 - Markdown Syntax
01:05:46 - getStaticProps Function
01:09:45 - getStaticProps in Production Mode
01:16:39 - Reading a File
01:20:24 - Lib Module
01:23:58 - Rendering Markdown
01:30:17 - Front Matter
01:35:09 - Dynamic Route and getStaticPaths
01:43:19 - Listing Files in a Folder
01:47:51 - Listing Posts


Content

3.28 -> in the first part of this course we'll
5.759 -> develop a next.js app that is a fully
8.96 -> static website the app will build is a
12.4 -> personal blog let me show you what it
14.88 -> will look like once it's finished
17.279 -> as you can see it's a simple blog
19.52 -> website where we can post some articles
22.56 -> that will write in markdown files
25.439 -> and the app will automatically generate
28.16 -> a page for each markdown file
30.88 -> we'll also implement a dark mode switch
34.079 -> so our users can toggle between light
37.2 -> and dark colors
38.879 -> so it's a fairly simple website to get
41.52 -> us started with next gs but it will
44.48 -> already teach us quite a few things
46.96 -> we'll see how to set up a next gs
49.52 -> project we'll talk about pre-rendering
52.64 -> that is perhaps the biggest advantage of
55.28 -> using next gs rather than playing react
59.039 -> we'll cover page navigation and routing
62.399 -> we'll see how to style our components
65.36 -> using a library called styled jsx a very
69.28 -> important section explains how to load
72.4 -> data in a next.js page in this example
75.68 -> we'll read the data from local markdown
78.479 -> files but the concepts we'll learn here
81.36 -> will be useful in many other cases like
84 -> if we want to fetch data from a web api
87.439 -> then we'll see how to build a dynamic
90 -> route that allows us to use the same
92.4 -> component for generating multiple pages
95.6 -> in this case for all our blog posts
98.96 -> as we've seen we'll add a dark mode
101.6 -> switch which will also be an example of
104.159 -> how to write client-side functionality
107.52 -> and related to that we'll learn about
110.24 -> hydration which is the mechanism used to
113.28 -> add client-side functionality to
115.84 -> components that were rendered on the
118.399 -> server side
119.759 -> finally we'll see how to deploy our
121.84 -> application and we'll cover a few
124 -> different options from versailles that's
126.719 -> the platform behind next.js to building
130.479 -> our app in a way that can be deployed to
133.36 -> any static hosting provider so let's get
137.2 -> started
144.48 -> in this video we'll create our first
146.72 -> next js project
148.72 -> now the easiest way to initialize a next
151.76 -> js application is to use the create next
155.04 -> app command line tool and we'll look at
157.599 -> this tool later in the course but to
160.08 -> begin with i want to show you how to set
162.319 -> up a new project entirely from scratch
164.879 -> because this will give you a better
166.72 -> understanding of how a next.js app is
170.16 -> structured
171.44 -> here i have visual studio code open with
174.319 -> its default welcome screen what i'm
176.72 -> going to do now is open a folder i'll
179.68 -> select my projects folder which is where
182.48 -> i like to keep my projects and inside
185.12 -> there i'll create a new folder let's
187.36 -> call it next blog since it's a blog
190.159 -> written using next.js
192.64 -> so i'm going to open this new folder in
194.72 -> visual studio code right now it's just
197.599 -> empty of course now let's go and create
200.239 -> a new file called package.json so we can
203.599 -> use npm to manage the project
206.08 -> dependencies like all modern javascript
208.879 -> projects here we need at least a name
211.68 -> that we can set to next blog same as the
214.64 -> folder name and then let's set private
217.599 -> to true
219.2 -> because this project is not a library
221.76 -> that we want to publish to the npm
224.08 -> registry okay let's save this file now
227.36 -> i'm going to open a new terminal inside
230 -> visual studio code and here we can run
232.72 -> the mpm command line tool to install
235.68 -> some dependencies we want the next
238.319 -> package that is next gs and then react
241.92 -> and react dom just like a regular react
245.04 -> app
246 -> let's wait a few seconds for npm to
248.4 -> download all the dependencies
251.12 -> okay you can see that those three
253.36 -> packages have been added to our
255.239 -> package.json file and their dependencies
258.32 -> and also there's a node modules folder
261.04 -> with all the packages now inside here
263.919 -> there's a dot bin folder that contains
266.88 -> command line tools installed along with
269.6 -> the packages and one of these tools is
272.32 -> next
273.36 -> this is the main tool we can use to
276.08 -> manage our next js project let's see how
278.88 -> it works
281.44 -> in the terminal we can use mpx to
284.4 -> execute that next command directly and
287.68 -> we can pass the minus minus help option
290.32 -> to see some usage instructions it says
293.28 -> that we can tell this tool to build
296.08 -> start export and so on in fact the first
300 -> command we want to use is dev that
302.88 -> starts our project in the development
305.12 -> server let's try that out
307.6 -> let's run mpx next dev
310.88 -> and it failed with an error what the
313.36 -> error says is couldn't find a pages
316.479 -> directory please create one that's a
319.36 -> helpful message not only says what the
321.84 -> problem is it also tells us how to fix
324.4 -> it so let's go and create a new folder
327.12 -> at the top level of our project named
329.68 -> pages now since we're going to use that
332.96 -> next dev command all the time i'll add
335.68 -> the scripts section to our package.json
338.479 -> file
339.52 -> and here configure a dev script that
342.479 -> will execute next dev
344.8 -> this way if we go back to our terminal
347.44 -> we can now type npm run dev and this
350.72 -> will take care of launching next dev as
354.08 -> defined in our scripts you can see that
356.88 -> now that we have a pages folder the
359.6 -> development server started successfully
362.4 -> and it's running at this url like i lost
365.28 -> on port 3000
367.28 -> let's open it in the web browser what we
369.84 -> get at the moment is a 404 not found
372.96 -> page which is not entirely surprising
375.68 -> given that we haven't created any pages
378.479 -> yet but this already shows that the
381.12 -> development server is working
383.44 -> i'll resize these windows so i can show
386.08 -> you the editor and the browser side by
388.88 -> side
389.84 -> and let me hide the terminal the dev
392.319 -> server will still be running in the
394.24 -> background of course
395.919 -> it is now time to create our first next
399.039 -> js page
400.4 -> inside our pages folder we want to add a
403.12 -> new file which we want to call index.js
407.039 -> because it will be the index page of our
409.759 -> application but what exactly is a page
413.12 -> in a next.js project
415.28 -> for now you can think of a page simply
418.24 -> as a standard react component let's
421.12 -> write a function component called home
423.919 -> page since that's what the index page is
427.44 -> and here we'll return some jsx elements
430.479 -> like all react function components
433.28 -> i like having a main element as the root
436.16 -> of the page to use semantic html and
439.759 -> here we could have a simple h1 heading
442.72 -> saying my blog for example
445.28 -> so this is just a very simple react
448 -> component the only other thing we need
450.479 -> to do is to export the component as the
453.84 -> default export of this file with this we
456.72 -> can now save this file and try and
459.28 -> reload the same url in the browser you
462 -> can see that it works our homepage
464.56 -> component is being displayed as the
466.96 -> index page of our application i'll open
469.52 -> the chrome developer tools so we can see
471.84 -> any console messages and since we're
474.4 -> running our next js app in development
476.8 -> mode this means that if we make any
479.36 -> changes to our code like if i write
481.919 -> mirko's blog here as soon as i save the
484.96 -> app updates automatically reflecting the
487.759 -> latest changes as you would expect when
490.639 -> working with the modern web framework
493.28 -> let me quickly revert this change
495.68 -> now before we move on note how the next
498.639 -> command created a dot next folder in our
501.84 -> project
502.879 -> you don't really need to worry about
505.039 -> what's inside here but if you use get in
508.08 -> your project make sure to add that
510.319 -> folder to your dot git ignore file
513.36 -> because it contains temporary build
515.68 -> files that shouldn't be kept in version
518.159 -> control just like you want to ignore the
521.039 -> node modules folder with all the
523.2 -> dependencies so this was just a quick
525.76 -> note if you use get
527.68 -> but with that aside we created our first
530.399 -> next js project and wrote our first page
534 -> which as it turns out is simply a normal
536.8 -> react component but as simple as this
539.6 -> page may look right now believe it or
542.08 -> not there's already a big difference
544.32 -> between how this page is rendered with
547.04 -> next gs and how a similar page would be
550.32 -> rendered in a plain react app we'll see
553.519 -> exactly what's different in the next
555.519 -> video
562.64 -> now that we have a next.js project set
565.519 -> up with a simple index page we can see
568.72 -> what is perhaps the main feature
571.12 -> provided by next.js compared to a normal
574.72 -> react project and that feature is
577.6 -> pre-rendering
579.04 -> to show you exactly what that means i
581.12 -> have created a standard react project
584 -> using the create react app tool
586.88 -> so in my projects folder along with the
589.6 -> next blog project we created in the last
592.32 -> video i now have a react blog as well
595.76 -> and if i open that react blog folder in
598.399 -> visual studio code
600.88 -> this is the initial project as generated
603.519 -> by create react app what i'm going to do
606.399 -> now is remove everything from this app
609.44 -> component
610.72 -> then i'm going back to our next js
613.04 -> project
614.48 -> and copy exactly the same jsx elements
618.64 -> so our playing react page will look
621.44 -> exactly the same as our next gs page and
624.64 -> we can compare the two
626.72 -> now i'm going to open a terminal
629.68 -> and run npm start to launch the react
632.8 -> dev server it's not starting straight
635.6 -> away because it detected that something
638.8 -> is already running on port 3000 and that
641.839 -> something is our next gs app but that's
644.959 -> okay we just need to type yes and it
647.6 -> will start on a different part in fact
650.32 -> it's running on port 3001
653.04 -> and here's our react app displayed in
655.279 -> the browser now i'm going to open the
657.6 -> chrome developer tools and look at the
659.92 -> network request
661.68 -> let me select only doc or documents that
664.88 -> is html files then i'm going to reload
668.399 -> the app
669.36 -> and we can see a request for local lost
672.079 -> and port 3001
674.48 -> now if we look at their response we can
676.72 -> see the html returned by the server if
680.079 -> we scroll to the body
682.16 -> here you can see that this page
684.079 -> basically contains only a single empty
687.04 -> dev so how can we see the my blog
690.48 -> heading displayed in the page if it's
693.12 -> not in this html as you probably know
696.079 -> already that's because after loading
698.64 -> this initial html file from the server
701.6 -> the browser also loads these javascript
704.48 -> files
705.44 -> and when that javascript code is
707.92 -> executed our react component is inserted
711.519 -> into the page in other words react
714.24 -> components are normally rendered on the
716.88 -> client side which means in the browser
720.079 -> we can further prove this if we go to
722.56 -> the settings and down here there should
725.2 -> be an option to disable javascript now
728.24 -> with javascript disabled if we try
730.72 -> reloading the page it doesn't work
732.959 -> anymore it just says you need to enable
735.76 -> javascript which is the text that was
738.079 -> inside the no script tag in the html
741.76 -> without javascript our react component
744.399 -> cannot be rendered by the browser now
747.2 -> let me go and re-enable javascript
750.639 -> otherwise not many things will work
753.44 -> so that's what happens with the playing
756 -> react app
757.36 -> now let's go back to our next gs app
760.24 -> that's still running on port 3000 what
763.44 -> happens in this case if we look at the
765.6 -> network requests let's try and reload
768.72 -> this page
770.079 -> we can see a local lost request but the
772.959 -> html for this page is all in one line so
776.72 -> it's a bit difficult to see what i'm
778.959 -> going to do is copy the whole html and
782.32 -> go and paste it into the editor so we
784.399 -> can look at it more easily
786.959 -> let me set the file type
789.2 -> to html
791.92 -> and also format this document so it's no
794.88 -> longer all in a single line if we look
797.68 -> inside the body
799.44 -> you can see that there's a dev element
802 -> and inside that we can see our main tag
804.959 -> with the h1 heading
807.04 -> so the react component we wrote in our
810.04 -> index.js file has been pre-rendered the
814.16 -> html file returned by the server already
817.519 -> contains the component elements
820.16 -> now you may notice that this file also
822.959 -> includes a bunch of javascript files as
825.68 -> well and that's because in a next.js app
828.639 -> we may still want some functionality
830.88 -> that runs on the client side for example
833.92 -> if we want to do something when the user
836.639 -> clicks on a button but for this simple
839.36 -> page the html actually already contains
843.04 -> all the content
844.48 -> let's do the same experiment as before
846.8 -> and see what happens if we disable
849.199 -> javascript let's reload the page
852.56 -> and as you can see our page still works
854.959 -> fine it renders correctly even with
857.76 -> javascript disabled this proves that the
860.639 -> rendering happened on the server side
863.76 -> let me re-enable javascript so we can
866.079 -> keep developing our app
869.199 -> but this is the main difference between
871.92 -> a normal react app and a next gis app
875.839 -> whenever possible next gs pre-renders
879.12 -> are react components this has a few
881.839 -> advantages for a start our app will feel
885.199 -> faster because the page content becomes
888.079 -> visible as soon as the html is loaded
891.68 -> without waiting for any javascript code
894.399 -> to be loaded and executed but also this
898.16 -> helps with seo or search engine
901.199 -> optimization because pages that have all
904.32 -> their content in html are easier for
907.68 -> search engines to crawl compared to
910.16 -> pages that require javascript
912.639 -> in other words thanks to pre-rendering
915.279 -> your pages may rank higher in google and
918.48 -> other search results
926.399 -> we've seen how next js pre-renders our
929.92 -> react components so that the html page
933.519 -> returned by the server already includes
936.32 -> the elements defined in our home page
939.04 -> component but how does this work exactly
942.48 -> let me close this html file now so we
945.199 -> can go back to our javascript code
947.839 -> how does next.js render this component
950.959 -> to html on the server well let's show
954.56 -> our terminal where the server is running
956.959 -> and see what's going on there let's add
959.44 -> a log statement inside our component
961.92 -> function so we can see when this
964.24 -> component is rendered
966.639 -> now if i save this file you can see the
969.199 -> render message being logged in the
971.279 -> browser console that's because the
973.519 -> component was updated using fast refresh
976.8 -> which is a bit special in that it only
979.199 -> happens in development mode but let's
981.92 -> see what happens if we go and reload the
984.079 -> page when the browser requests the page
986.959 -> from the server you can see that the
989.44 -> render message shows up in the server
992 -> logs
992.88 -> this means that our component is
994.88 -> rendered on the server the server takes
997.68 -> our javascript code and generates the
1000.72 -> html page returned to the browser
1003.839 -> interestingly the same message is also
1006.24 -> displayed in the browser console so our
1009.36 -> react component is rendered twice once
1012.56 -> by the server and once in the browser
1015.839 -> now you may be wondering why it needs to
1018.399 -> be rendered again in the browser if it
1020.959 -> was already rendered by the server and
1023.759 -> we'll talk more about this later in the
1025.76 -> course but for now let's say it's in
1028.48 -> case we need client-side functionality
1031.52 -> like responding to the user clicking a
1034 -> button
1034.959 -> anyway if you pay close attention you'll
1037.52 -> notice that the render on the server
1040.319 -> happens before the one on the client let
1043.439 -> me reload the page again so you can
1045.6 -> hopefully see it what happens is that
1048.16 -> when we load the page in the browser the
1050.559 -> browser requests the page from the
1052.72 -> server so that's when the server renders
1055.76 -> our component to html to return the html
1059.84 -> page to the browser after that the
1062.48 -> browser displays the page but it also
1065.039 -> loads the javascript files included by
1068 -> the html and at that point it will
1070.799 -> execute the javascript code that renders
1073.919 -> the component in the browser the other
1076.48 -> thing to notice is that every time we
1079.28 -> reload the page the component is
1081.679 -> re-rendered by the server this happens
1084.64 -> because we are currently running the
1086.64 -> next gs server in dev mode so it
1090.24 -> re-renders our page every time to make
1093.2 -> sure it reflects the latest changes we
1096.08 -> made to the code
1097.679 -> but this is not actually what happens
1100 -> when we run our next js application in
1102.88 -> production let me stop the dev server so
1105.84 -> i can show you how to run it in
1107.76 -> production mode
1109.52 -> as we've seen before the next tool
1112.16 -> supports a few different commands so far
1115.28 -> we always run next dev but there are
1118.4 -> other options like build and start in
1121.84 -> fact build and then start is exactly
1124.72 -> what we need to do to run the app in
1127.12 -> production mode let's try this out we
1130.24 -> can add some scripts to our package to
1132.559 -> json file so in addition to dev we want
1135.76 -> a build task that executes next build
1139.6 -> and then a start command that runs next
1142.96 -> start
1144.72 -> once we have these scripts we can run
1146.72 -> them with npm
1148.48 -> let's do an npm run build which will
1151.52 -> generate a production build of our next
1154.32 -> gs app
1155.679 -> now let me show you the full output
1157.919 -> there are a few interesting things here
1160.32 -> first of all notice that as part of the
1162.88 -> build next.js generates static pages it
1167.12 -> doesn't just compile and bundle our
1169.84 -> javascript code like a normal react
1172.64 -> project it also generates static html
1176.08 -> pages
1177.2 -> and it's during that step that it
1179.679 -> rendered our home page component as we
1182.559 -> can tell because it printed our log
1184.96 -> message here the other interesting thing
1187.6 -> is that at the end it shows a summary of
1190.88 -> all the files it has generated including
1193.919 -> javascript files their size and so on
1197.039 -> but for now let's focus on the pages
1200.08 -> it has generated a page for the root
1202.72 -> path which corresponds to our index.js
1206.08 -> file containing our homepage component
1209.12 -> and it also generated a 404 page
1211.919 -> automatically which is always needed if
1214.64 -> somebody requests a page that doesn't
1217.039 -> exist
1218.159 -> now notice how before each page there's
1221.039 -> a symbol and for both these pages it's
1224.08 -> an empty circle it explains what that
1226.799 -> means at the bottom an empty circle
1229.44 -> means that's a static page which means a
1232.72 -> page that's automatically rendered as
1235.52 -> static html there are other possible
1238.96 -> types of pages server
1241.84 -> ssg that stands for static site
1245.12 -> generation or isr which means
1248.4 -> incremental static regeneration will
1251.52 -> cover these other page types in the
1253.76 -> following sections but for now it's good
1256.559 -> to know that our index page is a fully
1259.84 -> static page
1261.52 -> now let's see what happens when we run
1263.52 -> the app in production mode
1265.84 -> we can do that by typing simply npm
1268.799 -> start and this starts the server on the
1271.84 -> same port as the dev server that is port
1275.76 -> but in this case it's running in
1277.6 -> production mode
1279.2 -> if we load the home page it looks the
1281.679 -> same as before obviously and it logged
1284.4 -> our render message in the browser
1286.4 -> console which happens after the html is
1289.679 -> loaded
1290.4 -> when the javascript code is executed but
1293.6 -> if you notice there is no render message
1296.48 -> printed in the server logs remember how
1299.919 -> in dev mode the server re-rendered our
1302.799 -> component every time we reloaded the
1305.76 -> page but not in production mode that's
1308.88 -> because in this case the html page has
1312.48 -> already been generated during the build
1315.28 -> step so all the server needs to do is
1318.559 -> return that static html file we can see
1322.559 -> that file if we look inside the dot next
1325.44 -> folder under server and then pages
1328.799 -> here's the index.html file that was
1332.08 -> generated by the build command
1334.799 -> if i format this document so it's a bit
1337.36 -> easier to read
1339.44 -> here inside the body you can see our
1341.919 -> home page component as rendered to
1344.84 -> html so the next gs server can simply
1348.48 -> return this html file every time the
1351.679 -> browser requests the page it doesn't
1354.4 -> need to regenerate it every time
1359.52 -> now let me stop the production server
1364.64 -> and restart the dev server so we can
1367.28 -> keep developing
1368.72 -> just keep in mind that there are some
1371.12 -> differences between the dev and
1373.679 -> production server in depth mode as we've
1376.72 -> seen the page is re-rendered by the
1379.44 -> server every time we request it
1382.559 -> and by the way we'll also talk more
1384.799 -> about how to run our next gsr-pin
1387.36 -> production later in the course the key
1390.159 -> point of this video was showing how
1392.64 -> next.js generates static html pages at
1396.799 -> build time
1404.32 -> we've seen how our home page is rendered
1407.36 -> into a static html file by next gs but
1411.6 -> we still have a single page in our
1413.679 -> application what if we want to add
1415.76 -> another page to our blog website for
1418.559 -> example we may want an about page
1421.44 -> visible at the slash about path
1424.48 -> if we try this now of course we'll get a
1427.039 -> 404 not found
1429.039 -> now a typical react app is a single page
1432.799 -> application but you can use something
1434.96 -> like react router
1437.6 -> to display a different component based
1440.24 -> on the url path this requires defining a
1443.76 -> route that specifies that path and the
1447.039 -> component to render in this case the
1449.679 -> about component so there's some amount
1452.799 -> of let's call it configuration involved
1456.24 -> in a next next.js app creating a new
1459.039 -> route is actually a lot simpler all we
1461.76 -> need to do is add a new file under the
1465.2 -> pages folder just like we already have
1468.48 -> the index.js file so we can just create
1472.4 -> a new file and call it about.js
1476 -> so the name is the same as the path
1478.72 -> where we want it to be visible at
1481.36 -> as we know a page in next.js is simply a
1484.96 -> react component
1486.4 -> in fact we could even copy everything
1488.72 -> from our home page and then rename home
1491.84 -> page to about page
1494.32 -> incidentally you can call your component
1496.88 -> whatever you like as long as it's the
1499.2 -> default export it makes no difference to
1502 -> next.js
1503.36 -> so you could call it simply about
1505.84 -> instead of about page but i find it more
1509.679 -> descriptive to call them something page
1513.279 -> now let's change the heading to say
1515.84 -> about as well save this file and go and
1519.12 -> reload it in the browser and just like
1521.919 -> that our new page is visible under the
1524.559 -> slash about path
1526.48 -> really really simple no configuration
1528.72 -> required
1529.919 -> this works because next gs uses a file
1533.36 -> system based router what this means is
1536.24 -> that the next.js server looks inside the
1539.679 -> pages folder and automatically exposes
1543.12 -> each file in there under a url path
1546.96 -> so our about.js file is automatically
1550.88 -> mapped to the slash about path
1553.76 -> it's basically the name of the file
1555.84 -> without the extension as for the
1558.44 -> index.js file that's a bit of a special
1561.279 -> case because that's not visible at slash
1564.4 -> index but simply at the root path we
1567.279 -> need a way to show a page at the root of
1570 -> our website so next.js uses index.js for
1574.4 -> that purpose which should be pretty
1576.4 -> intuitive but apart from this special
1579.279 -> case any javascript file you put inside
1582.559 -> that pages folder will be visible as a
1585.679 -> web page under the same path as the file
1588.88 -> name you can try creating another page
1591.6 -> yourself with the name of your choosing
1594.159 -> and verified that you can open it in the
1596.32 -> browser
1603.039 -> we added a new about page to our website
1606.32 -> but if we go to the home page there's
1608.799 -> actually no way for the user to navigate
1611.679 -> to that about page
1613.84 -> so let's go and add a link into our home
1616.88 -> page
1617.84 -> in fact we probably want a navigation
1620.32 -> bar inside a header where we could add
1623.2 -> other links as well now in a react
1626.08 -> component we need a single root element
1628.96 -> in jsx so i'm wrapping everything inside
1632.24 -> a fragment which is this special empty
1635.12 -> tag inside the header we can have a nav
1638.559 -> element which in turn contains a list
1641.84 -> and then we can have a list item for
1644.24 -> every link in our navigation bar let's
1647.039 -> start by using a regular a tag linking
1650.32 -> to slash about and the text can say
1653.52 -> about
1654.559 -> so we have a very basic navigation bar
1657.76 -> we'll add some styles later to make it
1660.32 -> look nicer but we can click the about
1663.039 -> link and it takes us to the about page
1665.919 -> of course we can also go back using the
1668.399 -> browser back button that's all pretty
1670.96 -> straightforward but let's look in more
1673.36 -> detail at the network requests and i'm
1676.64 -> only interested in documents that is
1679.12 -> html files now if we reload this page
1683.2 -> we can see a request for locker lost
1685.76 -> which really means the index page when
1688.559 -> we click the about link notice how it
1691.76 -> loaded the about page so it replaced the
1695.6 -> whole document the browser unloaded the
1698.72 -> home page and loaded the about page as a
1702.72 -> completely separate document and if we
1705.52 -> go back you can see the same thing
1707.44 -> happening in reverse it discarded the
1710.559 -> about page and loaded the home page from
1713.76 -> the server again that's how traditional
1716.72 -> websites work where each page is a
1719.6 -> separate html file but it's different
1722.72 -> from a typical react app that is a
1725.6 -> single page application and all the
1728.48 -> navigation is done on the client side
1731.76 -> client-side navigation is actually
1734.159 -> faster because it doesn't load a
1736.559 -> completely separate html file from the
1739.36 -> server every time we navigate to a new
1742.32 -> page
1743.2 -> so does this mean that by using next gs
1746.72 -> we are losing one of the advantages of
1749.44 -> react apps of course not we can use
1752.72 -> client-side navigation even in next.js
1755.84 -> apps all we need to do is use a
1758.64 -> component provided by next gs called
1762 -> link that's from the next link module
1766.24 -> and the way it works is that we simply
1768.799 -> wrap our anchor element in this link
1771.919 -> component
1773.12 -> and then we need to pass the href
1775.52 -> property to the link itself rather than
1778.24 -> the a tag you can actually wrap any
1781.52 -> elements you want in a link so you could
1784.48 -> also have an image for example inside
1787.44 -> here
1788.32 -> now let's save this file and see what
1790.96 -> difference this makes let's reload the
1793.6 -> home again and of course the browser
1796 -> requested the html file for the home
1799.039 -> page now let's go and click the about
1802.08 -> link and this time notice how the
1804.96 -> browser didn't make any other request
1807.76 -> there's a still only local lost so it
1810.399 -> didn't request the about page that's
1813.36 -> because the next router is now doing
1816.399 -> client-side navigation it already
1819.279 -> pre-loaded everything necessary to
1821.52 -> display the about component when we
1824.399 -> loaded the home page so you didn't have
1827.52 -> to make any additional requests which
1830.08 -> means that the navigation was a lot
1832.72 -> faster as well that also works if we use
1836.08 -> the back button
1837.679 -> it simply replaces the react component
1840.559 -> on the page instead of reloading the
1842.96 -> whole document from the server
1845.279 -> so by using next gs we can basically
1848.159 -> have the best of both worlds
1850.48 -> we get very quick client-side navigation
1853.6 -> just like a single page react app but we
1856.96 -> can also go directly to this lash about
1859.679 -> url and get a pre-rendered html page
1863.519 -> from the server like a traditional
1866.08 -> multi-page web application all we need
1868.96 -> to do to take advantage of these
1870.88 -> features is remember to wrap all our
1873.6 -> links in the next link component
1882.88 -> we added a navigation link to our blog
1885.84 -> app so we can go from the home page to
1888.72 -> the about page but once we get here
1891.679 -> there are no links to navigate elsewhere
1894.64 -> we probably want the navigation bar to
1897.279 -> be displayed on the about page as well
1900.24 -> we could simply copy this nav block into
1903.279 -> the other page but to make it more
1905.679 -> reusable let's put it into its own
1908.159 -> component so let's create a new file
1910.96 -> let's call it
1912.279 -> navbar.js this will be a regular react
1915.679 -> component
1917.039 -> and in its body we can return the same
1919.6 -> elements we copied from our home page we
1922.799 -> also need to make sure to import the
1925.2 -> link component and i'll use the auto
1927.919 -> import feature provided by visual studio
1930.96 -> code so it automatically added the
1933.919 -> correct import line at the top
1936.88 -> and finally we want to export this nav
1939.919 -> bar as the default
1941.84 -> okay we can save this one and now in our
1944.96 -> home page we can import that navbar
1948.24 -> component from the file we just created
1952.559 -> at this point we can use it to replace
1955.2 -> this blocker code
1956.88 -> with our new component
1958.96 -> let's save these changes and go back to
1961.519 -> the home page
1963.039 -> it's still showing the about link at the
1965.76 -> top that we can click to go to the other
1968.08 -> page so the navbar component is working
1971.6 -> but we're still not showing any links in
1974.159 -> this about page let's go and add the nav
1977.279 -> bar to the about page as well we can
1980.159 -> wrap everything in a fragment first so
1982.72 -> we can have multiple elements inside
1985.919 -> and here we can add a header with our
1988.559 -> navbar component that i'll auto import
1992.48 -> and that should be it we can see the nav
1995.039 -> bar at the top however the only link is
1998.159 -> to the about page itself so that's not
2001.279 -> particularly useful we want to add
2003.519 -> another link to our nav bar
2006.159 -> let's copy this list item and duplicate
2009.039 -> it then we can change the href to slash
2012.96 -> and the text to home
2015.2 -> and we now have a link to the home page
2017.84 -> as well
2018.799 -> so we can click home and navigate back
2021.84 -> and forth between our two pages
2024.48 -> so that's all working fine
2026.96 -> but there's actually a small problem
2028.96 -> with this nav bar at the moment i have
2031.919 -> created this component in the same
2034.32 -> folder as our pages can you think why
2037.919 -> this may be a problem we've seen a
2040.24 -> couple of videos ago that next gs uses a
2043.76 -> file system based router where all the
2047.12 -> files under the pages folder are
2050 -> automatically exposed as web pages this
2053.679 -> means that right now we could open the
2056.32 -> navbar url
2058.72 -> and we can see our navbar component
2061.28 -> displayed as a full page that's
2064.24 -> obviously not what we want because the
2066.72 -> nav bar is not meant to be a standalone
2070.24 -> page it's just a reusable component that
2073.599 -> we want to include in our pages so how
2076.72 -> do we stop this navbar component from
2079.52 -> being exposed as a web page as you might
2082.96 -> guess we need to move it somewhere else
2085.839 -> outside of the pages folder
2088.399 -> a common approach is to create a
2090.879 -> components folder at the top of our
2093.28 -> project so we can now move
2095.72 -> navbar.js inside that separate
2098.64 -> components folder let's confirm
2101.599 -> visual studio code can automatically
2104 -> update the imports in our code so let's
2107.2 -> accept
2108.16 -> and we should see that in index.js the
2111.2 -> navbar is now being imported from inside
2114.24 -> our components folder but we still need
2117.119 -> to save this file ourselves because the
2119.92 -> editor updated the import but didn't
2122.48 -> actually save the change that's why the
2124.96 -> page in the browser is showing an error
2127.68 -> if we save the about page as well that
2130.16 -> should fix it
2131.44 -> and it's now importing the nav bar from
2134 -> inside the components folder we can
2136.4 -> quickly check that everything still
2138.48 -> works
2139.44 -> good
2140.24 -> so that's it for this video we've seen
2142.96 -> how we can create reusable components in
2146.079 -> our app just like in any other react app
2149.359 -> the only thing we need to be careful
2151.359 -> about with next gs is that we should not
2155.04 -> put our components inside the pages
2157.92 -> folder unless we want them to be visible
2160.8 -> directly as web pages
2169.2 -> in the previous step we introduced this
2171.44 -> navbar component that we are then using
2174.16 -> in both our pages by writing a shared
2177.119 -> component we can avoid duplicating the
2179.68 -> same code over multiple pages however
2182.8 -> there is still some duplication between
2185.2 -> our pages they all share the same basic
2188.16 -> structure with the header and a main
2191.04 -> section in fact it's not unusual for all
2194.16 -> the pages in a website to share the same
2197.04 -> general layout it would be nice to be
2199.599 -> able to define such layout in a single
2202.72 -> place like in a sort of template with
2206.079 -> next gs we can do that by creating a
2208.88 -> custom app component inside pages we can
2212.32 -> create a new file named
2215.079 -> underscoreapp.js the name begins with an
2217.92 -> underscore because it's a special file
2220.88 -> it's not a regular page
2223.2 -> but it's still a react component so we
2225.76 -> can write a function component as usual
2229.04 -> now this component will receive some
2231.359 -> props that are passed automatically by
2233.76 -> the next gs framework one such prop is
2236.96 -> called component this is the page
2239.92 -> component corresponding to the page
2242.32 -> being displayed so if we render in the
2245.2 -> index page for example component will be
2248.4 -> the home page but if we load this lash
2251.68 -> about path it will be our about page
2254.839 -> component the other prop we need is
2257.44 -> called page props and as the name
2260.16 -> suggests this contains props that we
2263.119 -> need to pass to the page component as a
2266.16 -> minimum in our app we want to render the
2268.88 -> component representing the current page
2271.92 -> and we need to pass all the page props
2274.8 -> to that component using the object
2277.359 -> spread syntax then as usual we need to
2280.64 -> export this as the default export for
2283.599 -> this module so like this our custom app
2287.04 -> component simply renders the desired
2289.52 -> page without adding anything now let's
2292.64 -> add at least a logging statement here
2295.92 -> so we can see when this component is
2298.16 -> rendered
2300 -> okay let's save this file now when we
2303.04 -> first create a custom app component we
2305.839 -> need to manually restart the dev server
2309.04 -> this is one of the very few cases where
2311.839 -> the dev server does not automatically
2314.32 -> pick up the changes and that's because
2316.64 -> the app component is special in that
2319.68 -> it's used for all the pages so let's
2323.04 -> stop the server with ctrl c and then
2326 -> launch npm run dev again let's hide this
2329.68 -> terminal
2330.88 -> and reload the app
2333.52 -> you can see in the browser console that
2335.68 -> our new app component was rendered first
2338.88 -> and then the home page was also rendered
2341.92 -> so this proves that our app component is
2344.48 -> getting called
2345.839 -> now what we wanted to do is extract the
2348.88 -> common page layout from our existing
2352 -> pages
2353.04 -> so let's copy all these elements and go
2356.079 -> and paste them into the app component
2358.96 -> but here we want to keep only the common
2361.68 -> elements the main section will be
2364 -> different for each page so let's remove
2366.48 -> this and in its place we want to render
2369.2 -> this page specific component
2372.32 -> so each page can basically insert its
2375.359 -> own elements into this sort of template
2378.64 -> if we save now well there's an error
2381.2 -> because i forgot to import the navbar
2384.32 -> component but if we fix that the app
2387.359 -> component will render the common navbar
2390.32 -> in fact we see two nav bars on the page
2393.2 -> now that's because the home page also
2395.839 -> displays its own header so we can remove
2398.56 -> it from here now given that it's already
2401.2 -> provided by the common app component in
2404.079 -> this way we should see a single nav bar
2406.88 -> we can actually remove this import as
2409.119 -> well
2410.4 -> okay the home page is working if we go
2413.28 -> to the about page again we'll see the
2416 -> nav bar twice because the about page
2418.96 -> still adds its own header let's remove
2421.599 -> it from here as well
2423.2 -> and also get rid of the import and
2425.76 -> that's it the about page looks good by
2428.48 -> the way we could remove the fragment
2431.04 -> that wraps the main element in this code
2434 -> but it will be useful later on when we
2436.48 -> add some more stuff so i'm going to
2438.64 -> leave it there
2439.92 -> also note in the browser console how the
2442.88 -> app component is always rendered before
2446.24 -> every page in fact now that we've seen
2448.96 -> this i'm going to remove that log
2451.359 -> statement otherwise it will keep being
2453.92 -> logged every single time okay
2456.88 -> but this is how a custom app component
2460.079 -> works in next gs it's the perfect place
2463.76 -> to write code that applies to all the
2466.319 -> pages in your application
2474.48 -> we introduced a custom app component
2477.44 -> where we keep the common elements so
2479.76 -> that in each page we only keep the parts
2482.72 -> that are specific to that page now
2485.68 -> there's something else that we typically
2487.599 -> want to add to each page and that's a
2490.48 -> title you can see that at the moment the
2492.96 -> browser tab simply displays the url and
2496.4 -> it's the same if we look at the about
2498.64 -> page as well that's because in our pages
2501.599 -> at the moment we don't define a title
2504.72 -> and i mean the title element that you
2507.28 -> can put inside the head tag in html it's
2511.28 -> simply not present in here how can we
2514.319 -> add a title to each page it's slightly
2517.119 -> tricky because our components are
2519.28 -> usually rendered inside the body of the
2522.4 -> document but in this case we need to add
2524.96 -> something to the head of the html
2527.839 -> thankfully next.js provides a head
2530.56 -> component that we can use exactly for
2533.04 -> this purpose
2534.4 -> we can put this head component wherever
2536.88 -> we want inside our jsx elements and
2540.079 -> anything we write inside here will be
2542.8 -> added to the document head so we can use
2545.92 -> this to set the title for example my
2548.88 -> blog and once we save this you can see
2551.76 -> that the title in the browser tab
2554.24 -> changed to my blog
2556.24 -> also if we go and look inside the
2558.4 -> document head there is now a title
2561.359 -> element exactly as we wrote it in our
2563.68 -> component this can be used to set any
2566.72 -> elements that go inside the head so in
2569.76 -> addition to the title we could set a
2572.24 -> meta tag with a description which is
2574.96 -> something that can be useful for search
2577.2 -> engines
2578.64 -> let's just write this is my blog as an
2581.28 -> example
2582.72 -> and that meta tag is of course added to
2585.68 -> the document head it's been added
2588.079 -> dynamically here because we're running
2590.72 -> in depth mode but remember that next gs
2593.92 -> will build static html pages for
2597.2 -> production so this tag will be present
2600.079 -> in the static html which will be used by
2603.28 -> search engines
2604.64 -> anyway for this simple blog we don't
2606.8 -> really need to worry about seo let's
2609.52 -> just keep the title okay now let's go
2612.72 -> and add the same to the about page as
2615.28 -> well let me show that page in the
2617.2 -> browser
2619.52 -> so we can paste our head section and we
2622.64 -> can simply change the title to say about
2625.76 -> we also need to import this head
2628.16 -> component
2629.28 -> and that should be that
2631.28 -> you can see our new title displayed in
2633.28 -> the browser tab just as we expected note
2636.48 -> that the title will also change
2638.72 -> dynamically when we navigate from one
2641.119 -> page to the other even though as we've
2643.839 -> seen this kind of navigation happens
2647.28 -> side without reloading the html page
2650.4 -> from the server the next js head
2652.88 -> component will dynamically update the
2655.52 -> values inside the document head
2658.48 -> and that's all for this video the head
2661.119 -> component is very simple to use but also
2663.839 -> very useful for setting the page title
2666.8 -> and other meta tags
2674.64 -> in this video we'll start adding some
2677.04 -> styles to our application so far
2679.839 -> everything in our page is displayed
2682.079 -> using the default browser styles which
2685.119 -> doesn't make for a great look the most
2687.76 -> basic way to add some styles is to add a
2690.56 -> regular css file that is used for the
2693.44 -> entire website let's start with this
2695.92 -> approach let's create a styles folder at
2698.96 -> the top of our project just to keep the
2701.119 -> css files separate from the rest of our
2703.839 -> code and inside that folder let's create
2706.64 -> a new file called
2708.839 -> globals.css since it will contain global
2711.839 -> styles here we can add some css rules
2715.28 -> for example we may want to set a font
2717.76 -> family
2719.119 -> and i'll accept this suggestion which is
2721.76 -> a common choice of sensory fonts okay
2725.599 -> let's save this file now for these
2728.16 -> styles to actually be used we need to
2730.96 -> import that css file into our custom app
2734.64 -> component relative to the pages folder
2737.44 -> it's up one level and then styles
2740.76 -> globals.css and if we save you can now
2743.76 -> see that the page is using a different
2746.24 -> font you can actually import any css
2749.2 -> file you like into your app component
2752 -> and it will be applied globally it
2754.24 -> doesn't have to be called globals.css
2757.52 -> that's just an arbitrary name
2759.68 -> in fact you could also import multiple
2762.079 -> css files if you want to anyway let's go
2765.28 -> and add some more styles to make our app
2767.92 -> look a bit nicer maybe we could change
2770.48 -> the color of the links
2773.2 -> and set it to dark red for example i'm
2776.64 -> using a named color for simplicity but
2779.359 -> of course you could select a custom
2781.599 -> shade using the color picker anyway if
2784.56 -> we save this change the links become
2786.96 -> dark red we could also remove the
2789.44 -> underline by setting text decoration to
2792.8 -> none and that's the result there's no
2795.359 -> need to underline those links because
2797.839 -> they're in the navigation bar however we
2800.64 -> could show the underline when the link
2803.119 -> is focused or when the user moves the
2805.92 -> mouse over it so in this case set the
2808.88 -> text decoration back to underline and if
2812.4 -> you save this
2813.839 -> it should underline the links when we
2816.16 -> hover over them which can help the user
2819.119 -> a little bit
2820.24 -> now those links are still displayed as a
2822.96 -> bulleted list which is not really what
2825.599 -> we want in a navigation bar let's remind
2828.64 -> ourselves of the structure of that nav
2831.44 -> bar as you can see here there's a ul
2834.56 -> element that is an unordered list that
2838 -> contains an li or list item element for
2842.48 -> each link
2843.68 -> so we want to restart the ul element
2847.599 -> to remove the bullet points and that can
2850.48 -> be done by setting list style type to
2854 -> none
2854.96 -> okay the bullet points are gone but
2857.76 -> there's still a lot of space before each
2860.24 -> link let's remove it by setting padding
2863.52 -> to zero that's better now we also want
2866.72 -> to display those links all in the same
2869.44 -> line
2870.319 -> so let's go install the li elements and
2873.92 -> set them to display inline
2876.8 -> so they're all on the same row but
2879.119 -> there's no space between them now let's
2881.76 -> add a bit of a margin maybe on the left
2884.319 -> so before each link and let's set it to
2887.599 -> 0.75 ram units
2890.319 -> that's more readable ideally we don't
2892.8 -> really need the margin before the first
2895.359 -> item so we could set the margin only on
2898.559 -> items that are not the first
2902.72 -> child
2905.92 -> so let's set the margin left only in
2908.4 -> this case and if you save the home link
2911.68 -> is aligned to the left
2913.52 -> okay that's enough for this example as
2916.079 -> you probably know you can easily spend a
2918.64 -> lot of time fiddling with the styles to
2921.359 -> make your app look really nice but since
2924.16 -> this course is not specifically about
2926.559 -> css i'll keep the styles fairly basic
2930.079 -> the important thing to know is that with
2932.8 -> next.js you can have global css files
2936.4 -> that apply to your entire app simply by
2939.599 -> importing them into your underscore
2941.839 -> app.ges file in the next video we'll see
2945.28 -> how to define component level styles as
2948.96 -> opposed to global styles
2957.599 -> in the previous video we added the css
2960.16 -> file to our app containing global styles
2963.359 -> that apply to all our pages now keeping
2967.04 -> all the styles in a global css file
2970 -> doesn't work so well when our app
2972.319 -> becomes larger and we add many different
2975.2 -> pages and components for example here we
2978.72 -> added some rules for the ul and li
2982.4 -> elements used in the navigation bar but
2985.44 -> as they are these rules really apply to
2988.24 -> any ul and li elements anywhere in our
2992.24 -> application
2993.359 -> what happens if we have a list of items
2995.92 -> somewhere else like in our home page
2998.88 -> let's add a list here for example
3001.599 -> with some test items saying one two
3005.44 -> and three
3007.44 -> you can see that in the page these items
3009.839 -> are displayed all in a single line
3012.559 -> because it's applying the same rules we
3015.04 -> defined in our global css file written
3018.48 -> for the navigation bar but if we have a
3021.04 -> list in the main section of the page we
3023.599 -> probably want that list to be displayed
3026.24 -> as bullet points so we need a way to
3029.28 -> apply these rules only to the ul
3032.16 -> elements that are inside the navigation
3034.96 -> bar in this simple example we could
3037.44 -> apply them only inside a nav element
3041.76 -> and that would work fine in this case
3044.24 -> you can see that the links at the top
3046.4 -> are all on the same line while the list
3049.2 -> in the main content is displayed with
3051.68 -> bullet points this works in this case
3054.48 -> because we have a single nav element in
3057.44 -> our page but what if we have another nav
3060.48 -> element somewhere else and we want to
3063.04 -> style it differently to be absolutely
3066 -> sure those styles only apply to the
3068.64 -> elements inside our navbar component we
3071.52 -> could add a class name to the root
3073.76 -> element named like the react component
3076.559 -> itself
3077.599 -> so now that nav element has class nav
3080.96 -> bar and we can use this in our css
3083.68 -> selectors
3085.52 -> instead of applying these styles to all
3088.16 -> nav elements we can apply them only to
3090.72 -> those who have class nav bar
3094.16 -> and the result is the same but our rules
3097.119 -> are more specific
3098.88 -> so this is a better approach but having
3101.839 -> to add a css class to each react
3104.72 -> component by hand and then writing the
3107.68 -> correct rules in a global css file is
3110.72 -> still a bit of a pain especially once
3113.04 -> our code grows and we have lots of
3116 -> components that's why these days there
3118.559 -> are many libraries available for react
3121.119 -> that give us component scoped styles
3124.64 -> in this example we're going to use
3126.559 -> styled jsx which is a library created by
3130.079 -> versel that is the same company behind
3132.8 -> next gs but this is just one of many
3136.559 -> possible options next gs also supports
3140.16 -> css modules out of the box and if you
3143.44 -> prefer some other library that works
3146 -> with react it should work with next.js
3149.119 -> as well
3150 -> but let's have a look at how styled jsx
3153.28 -> works let's comment out these global
3156.079 -> navbar styles for now and let's
3158.8 -> re-implement them using styled jsx we
3162.319 -> can actually remove this class name as
3164.4 -> well
3166.559 -> okay
3167.44 -> with styled jsx we can write our css
3170.64 -> rules directly inside our jsx elements
3174.24 -> all we need to do is add the style
3176.64 -> element with a special property called
3179.44 -> jsx we can insert this style element
3182.88 -> wherever we like inside the jsx tree for
3186.16 -> our component but typically we put it
3188.64 -> just before the end like this now inside
3192.24 -> the element we want a jsx expression
3194.88 -> that is a bacteric delimited string this
3198.16 -> way the string can span multiple lines
3201.119 -> and inside here we can write our styles
3203.92 -> using the regular css syntax for example
3207.28 -> let's style our ul element let's go and
3210.4 -> copy the same styles we were using in
3212.88 -> our global css file and just paste them
3216.24 -> here
3217.04 -> if we save
3218.8 -> you can see that the styles have been
3220.96 -> applied to the nav bar
3223.119 -> if we look at the elements as rendered
3225.28 -> in the browser you can see how styled
3228.079 -> jsx automatically added a class to the
3231.359 -> nav element a class with a unique id
3234.559 -> that starts with jsx and then some
3237.359 -> random number and the same class is
3239.92 -> applied to all the elements inside the
3242.559 -> nav bar as well that's how styled jsx
3246.319 -> makes sure that our styles only apply to
3249.44 -> this component it's basically similar to
3252.16 -> what we did earlier when we manually
3254.559 -> added the class to our navbar component
3257.599 -> except that now styled jsx is doing it
3261.119 -> automatically for us okay now that we've
3263.92 -> seen how it works let's go and copy the
3266.4 -> other styles as well
3268.72 -> and paste all the rules inside our
3271.04 -> component styles
3272.8 -> we can remove the navbar class
3275.76 -> since these styles are already isolated
3279.359 -> okay if we save now
3281.44 -> the links in the nav bar have the
3283.44 -> expected styles but the other list in
3286.319 -> the main content is not affected all
3289.2 -> right we can now go and remove those
3291.76 -> styles from the global css file
3294.799 -> all the navbar specific styles are now
3297.92 -> inside the component itself where they
3300.559 -> belong
3301.599 -> i should also mention that to get syntax
3304.48 -> highlighting and code completion i had
3307.44 -> to install a couple of visual studio
3309.76 -> code extensions
3311.52 -> one is called styled jsx syntax
3314.48 -> highlighting and the other one is
3317.2 -> the styled jsx language server
3320.48 -> so you may want to install those
3322.4 -> extensions as well
3324.16 -> but this is how styled jsx works
3327.44 -> personally i like having all the styles
3330.559 -> in the same place as the component code
3333.44 -> that's what makes stalled jsx a
3335.92 -> so-called css in js solution and i also
3340.079 -> like being able to use the regular css
3342.88 -> syntax but if you prefer some other
3345.68 -> styling solution for react as i
3348.079 -> mentioned you should be able to use it
3350.079 -> with next js as well
3358.64 -> now that we added some styling to our
3361.04 -> blog website i want to cover another
3363.599 -> small thing that has to do with the
3365.76 -> appearance and that's the 5 icon
3368.88 -> perhaps you noticed before that when we
3371.52 -> load the page sometimes we get a not
3374.319 -> found error for fav icon dot ico
3378.079 -> and you can also notice that the icon
3381.04 -> shown in the browser tab is just a
3383.839 -> generic one because we don't currently
3386.559 -> have a custom icon for our website so
3390.559 -> for a start let's go and find an image
3393.04 -> that we can use as the icon and i'll
3395.599 -> choose one from this fav icon dot io
3398.48 -> which is one of the many fav icon
3400.48 -> generators you can find out there for
3403.28 -> simplicity i'll just select one of the
3405.76 -> emoji icons and i know there's one
3408.72 -> called infinity that is this infinity
3411.599 -> symbol
3412.559 -> feel free to pick a different icon if
3414.72 -> you see one you like better so i'll
3417.119 -> download this image and this is actually
3419.68 -> a zip file that we can open
3422.48 -> it contains a few different variants of
3425.119 -> the same image in different sizes and
3427.839 -> formats that can be useful if you want
3429.839 -> to support devices like android and ios
3433.599 -> but for this example we're going to use
3435.839 -> a single image
3437.599 -> now the question is where should we put
3440.4 -> that icon inside our project with next
3443.52 -> gs we can have a folder called public
3446.96 -> and any file we put inside that folder
3450 -> will be served as it is to the browser
3453.359 -> let's start with a different example we
3455.92 -> can create a robots.txt file that as you
3459.68 -> probably know can be used to tell search
3462.72 -> engines which pages they can index
3465.76 -> in our blog website we want to let all
3468.559 -> search engines access all the pages so
3471.92 -> these will be the rules now that we have
3474.4 -> that file inside the public folder we
3477.2 -> can request
3478.44 -> robots.txt in the browser and we get
3481.28 -> exactly the same content we just wrote
3483.839 -> in the editor
3485.119 -> so the file is simply returned as it is
3488.72 -> unlike the javascript files that we have
3491.599 -> inside the pages folder that are
3494.16 -> processed and rendered to html before
3497.52 -> they are returned to the browser okay
3500.319 -> now that we have that public folder we
3502.799 -> can copy our valve icon file inside
3505.92 -> public and this should now be used as
3508.64 -> the icon for our website you can see
3511.44 -> that the icon is visible in the browser
3514.16 -> tab okay so this works because the
3516.96 -> browser requests that
3519.24 -> favicon.ico url by default but we can
3522.64 -> also explicitly declare where to load
3525.76 -> our icon from and we want to do that in
3528.64 -> our app component since it applies to
3531.28 -> all the pages now the tag for the icon
3534.72 -> goes inside the document head so if you
3538.079 -> remember we can use the next head
3540.559 -> component for that and we want a link
3543.839 -> element with rel icon which is the
3547.2 -> relationship type and then the href
3550.4 -> property will point to the image file in
3553.44 -> this case it's slash vav icon dot icon
3556.96 -> because the file is directly inside the
3559.76 -> public folder so it's visible under the
3562.72 -> root of our website and if we save our
3565.839 -> icon still works
3567.599 -> but we're not limited to keeping all the
3570.079 -> files directly under public of course we
3573.44 -> can have subfolders for example create
3576.16 -> one for icons
3578 -> and if we move our image inside there
3581.52 -> then it will be accessible in the
3583.119 -> browser at a different path that's why
3585.76 -> we now get a 404 not found because the
3589.04 -> file is no longer at that url it's now
3592.16 -> under the slash icons path so if we
3595.28 -> change the href
3597.119 -> then the icon will work again let me
3599.68 -> reload just to show that the error
3601.76 -> disappears but you could already tell by
3604.4 -> looking at the icon in the browser tab
3607.04 -> just to be clear i only moved the icon
3609.359 -> to a different path to show you how the
3612.079 -> public folder works we could have left
3614.559 -> the icon in the default location of
3616.72 -> course but the point is that you can use
3619.599 -> this public folder to keep any assets
3622.72 -> you want to use in your web pages they
3625.68 -> can be images fonts videos anything that
3629.599 -> should be served as it is you can put it
3632 -> inside here and reference it from your
3634.72 -> pages
3641.839 -> we've seen how we can use the public
3644.4 -> folder to keep images and other assets
3648 -> used in our pages now we're building a
3651.2 -> blog website but we still have no blog
3654.559 -> posts
3655.52 -> so it's time to write our first blog
3658.4 -> post and we could start by adding a link
3662.079 -> to what will be the page for our blog
3664.96 -> post we may want all the pasts under the
3668.24 -> same path and under there we will have
3671.44 -> different pages starting with the first
3674.4 -> post for example here we need an anchor
3677.359 -> element with the title for this link
3680.079 -> that can be again first paused now let
3683.2 -> me remove these other list items
3685.839 -> and in our page we see the link to first
3688.559 -> post
3689.52 -> of course if we click that link we'll
3691.68 -> get a 404 page because we haven't
3694.559 -> actually created the page for that url
3697.52 -> yet you should know by now how to create
3700.4 -> a page so why don't you pause this video
3703.839 -> and try and add that page yourself
3707.2 -> there's just a tiny challenge here in
3710.079 -> that the page must be in a sub path
3713.76 -> i'll wait just a couple of seconds
3715.76 -> before showing you the solution
3718.96 -> okay let's see how to create that first
3721.839 -> past page we know that pages go inside
3725.2 -> the pages folder but in this case we
3728.079 -> first want to create a subfolder called
3731.039 -> posts
3732.079 -> and inside that subfolder we'll create a
3736.039 -> firstpost.js file so that's how we'll
3739.039 -> get this page exposed as slash posts
3742.48 -> slash first passed in the url now we
3745.76 -> need our component code and i'll copy
3748.24 -> that from our about page just to save
3750.88 -> some time
3752.799 -> let's rename about page to first post
3756.079 -> page
3757.28 -> and also change the title accordingly
3762.4 -> and this is a good starting point for
3764.72 -> our new page if we try opening that link
3767.599 -> again we can see our new first post page
3771.039 -> that's pretty simple
3772.64 -> now we could add a paragraph
3774.96 -> with the content of our post like this
3778 -> is my first ever blog post
3780.88 -> and you know we could keep writing more
3783.599 -> content into this page but writing an
3786.4 -> article by hand using jsx elements
3789.599 -> inside a react component is probably not
3792.88 -> the best approach maybe we could use
3795.52 -> markdown instead we'll look at that in
3798.16 -> the next video
3805.68 -> so we created this first post page but
3809.2 -> we also mentioned that it will be better
3811.68 -> to write our blog posts in markdown
3814.88 -> format so let's open a new editor tab
3819.2 -> and set the file type to mark down
3822.64 -> in markdown we can write a header by
3825.2 -> starting the line with a hash mark so we
3827.92 -> could use this for the title
3830.079 -> and then we can write a paragraph simply
3832.559 -> as normal text without special tags
3836 -> let's also note that this post was
3838.64 -> written using markdown now in visual
3841.839 -> studio code we can also preview it if we
3844.799 -> open the command palette by pressing
3847.52 -> command shift p or control shift p if
3851.28 -> you're not on mac os here you can search
3853.92 -> all available commands and there is one
3856.48 -> called markdown open preview to the side
3860.16 -> so if i press enter we can see the
3862.48 -> rendered markdown on the right and we
3865.44 -> can keep adding content on the left like
3868.64 -> some bold text for example
3871.2 -> or we could add a list
3874.559 -> starting each line with an asterisk that
3877.2 -> will be displayed as a bullet point so
3880.48 -> this is a much better way to write an
3882.72 -> article compared to writing it directly
3885.44 -> inside a react component
3887.68 -> now let's save this markdown file and
3890.48 -> i'll create a new folder called content
3893.359 -> just to keep it separate from the rest
3895.28 -> of our code inside content we could have
3897.92 -> another folder called posts and this is
3900.72 -> where we want to save this file
3904.4 -> i'll have to find that folder in this
3906.799 -> dialog now
3908.799 -> okay and we can call this file
3911.2 -> firstpost.md
3914.48 -> there you go
3916.16 -> so our challenge now is how do we take
3919.039 -> this markdown file and display it as the
3922.16 -> content of our first post page
3925.76 -> this will require quite a few separate
3928.24 -> steps we need to read that file parse
3931.92 -> the markdown and render it to html but
3935.68 -> also see how we can load data in a next
3938.88 -> gs page we'll cover all of this in the
3942 -> next few videos
3949.52 -> to recap we created this first post page
3953.28 -> but we'd like to load the content to be
3956.16 -> displayed inside that page from this
3959.2 -> markdown file to get there step by step
3962.799 -> let's leave the markdown aside for the
3965.52 -> moment and instead look at how we can
3968.559 -> load some data into a next.js page it
3972.24 -> doesn't really matter if that data comes
3974.88 -> from a local markdown file or somewhere
3978.24 -> else like an external api
3981.119 -> we know that a next.js page is a react
3984.48 -> component and you should also know that
3986.799 -> we can pass props to a react component
3990.559 -> let's log those props when the component
3993.359 -> is rendered at the moment props is just
3996.319 -> an empty object in other words there are
3998.96 -> no props passed to this component which
4001.68 -> is perhaps not surprising because this
4004.48 -> component is a page so in a sense it's
4007.839 -> the top level component of our
4010.079 -> application there's nothing passing
4012.72 -> props down to this component but in next
4016.4 -> gs there is actually a way for us to
4019.119 -> pass some props to a page which is
4021.92 -> useful precisely to load some data that
4025.039 -> can then be displayed in the page to do
4028 -> that we need to create a function named
4030.96 -> get static props and this function needs
4034.24 -> to be exported and also async
4038.24 -> because loading data is usually done
4041.119 -> asynchronously so it makes sense to
4043.599 -> return a promise
4045.359 -> now this function returns an object or
4048.64 -> more accurately a promise of an object
4051.52 -> since it's async and this object
4054.079 -> contains the props that we want to pass
4056.88 -> to our page component as props we can
4060 -> pass whatever we want so let's start
4062.24 -> with a couple of test values
4066.16 -> and if we save this now
4068.079 -> we need to reload the page because those
4071.119 -> props are set server-side but you can
4074.48 -> see in the browser console that the
4076.559 -> first post page component received the
4079.359 -> value we returned in our get static
4082.079 -> props function okay now that we know how
4085.2 -> to pass props we can use this to pass
4088 -> the post data each post can have a title
4092.16 -> like first passed
4094.4 -> and then let's call it the body will
4097.279 -> contain the main content for this post
4100.4 -> let's specify that this comes from
4103.04 -> static props so it will be clearer once
4105.6 -> we load it into the page
4107.679 -> and if we reload the page of course we
4110.48 -> should see our post object received in
4113.279 -> the props okay at this point we can use
4116.719 -> that post data in our component we can
4119.759 -> extract the past prop since it's the
4122.56 -> only one we expect and then replace
4125.359 -> anywhere we wrote first past with the
4128.48 -> past title
4130.88 -> while inside this paragraph we want to
4133.199 -> display the post body
4136.319 -> so with this you can see that the page
4138.96 -> is now displaying my first post as
4142.159 -> static props it updated using fast
4145.199 -> refresh but it will be the same if we
4147.759 -> reload the page of course okay so this
4150.88 -> is how we can pass props to a page
4153.92 -> component in next.js so far we hard
4157.44 -> coded these props inside our get static
4160.64 -> props function but later on we'll load
4163.52 -> the post data from our markdown file
4166.719 -> before we get to that though in the next
4169.44 -> video i want to show you in more detail
4172.08 -> how get static props works in terms of
4175.52 -> when next gs calls that function and
4178.719 -> also why it's called get static props
4188.799 -> we wrote our first get static props
4191.52 -> function to pass props to our page
4194.159 -> component now let's make sure we fully
4197.04 -> understand how it works let's start by
4199.92 -> checking when this function is called by
4202.8 -> adding a logging statement
4205.92 -> and i'll print the page name as well as
4208.32 -> the function
4209.76 -> now let's open the terminal so we can
4211.76 -> look at the server logs i'll clear
4213.92 -> everything so it's easier to see the new
4215.92 -> messages when we load the page you can
4218.88 -> see that the get static props function
4221.6 -> is called on the server side but not in
4224.8 -> the browser while our component render
4227.76 -> function as we know is called both by
4230.64 -> the server and in the client
4233.199 -> so that's the first interesting thing
4235.76 -> get static props is only executed on the
4238.88 -> server to generate the html returned to
4242.32 -> the browser if we reload the page then
4245.44 -> get static props is called again so it's
4248.239 -> called before every render and this is
4251.199 -> because we are currently running the app
4253.28 -> in the dev server we'll see in a minute
4256.08 -> what happens in production mode but
4258.719 -> first i want to point out this
4260.8 -> peculiarity of writing next gs apps in
4264.719 -> this same file we have our component
4267.679 -> function that's executed both by the
4270.159 -> server and in the browser and this is
4272.719 -> already different from a normal react
4275.12 -> app where everything runs in the browser
4278 -> but now we also have this get static
4280.64 -> props function that only runs in the
4283.28 -> server so in the same file we have a mix
4286.719 -> of server-side and client-side code
4290.64 -> this is different from most other
4292.88 -> frameworks where you either write
4295.04 -> server-side code or you write
4297.679 -> client-side code this can be a bit
4300.4 -> confusing at first but it is actually
4303.04 -> one of the advantages of using next gs
4306.56 -> this component page and the function
4309.12 -> that populates its props are strictly
4311.84 -> related so it makes sense to keep them
4314.719 -> in the same file the fact that they can
4317.679 -> then be executed in two different
4320.48 -> environments is more of a deployment
4323.04 -> concern and next js takes care of that
4326.239 -> for us by intelligently deciding which
4329.44 -> code needs to run where
4331.6 -> it's pretty clever if you think about it
4333.92 -> now let's see what happens when we build
4336.4 -> our app for production let's run npm run
4340 -> build
4343.6 -> and look at the output
4346.88 -> the get static props function is called
4349.76 -> while generating static pages and in
4353.04 -> fact it's locked just before rendering
4355.44 -> our first post page component which
4358.08 -> makes sense because you need the props
4360.8 -> to render the component now if we look
4363.52 -> at the build summary remember how our
4366.159 -> other pages that is home and about are
4369.199 -> marked with an empty circle which means
4371.76 -> they are static as in automatically
4374.56 -> rendered as static html and they use no
4378.64 -> initial props if we look at our new
4381.52 -> first post page this one has a filled
4384.719 -> circle instead and a filled circle means
4388.32 -> it's ssg or static site generation which
4392.4 -> is explained as automatically generated
4395.199 -> as static html plus json
4398.4 -> and uses get static props
4401.04 -> so next gs treats pages with a get
4404.719 -> static props function slightly
4406.96 -> differently from fully static pages
4410.48 -> for most practical purposes static or
4413.84 -> ssg are pretty much the same we can
4416.64 -> deploy both types of pages to any web
4419.84 -> server as static files but let's see why
4423.36 -> it says that it generates html plus json
4427.36 -> rather than just html
4429.76 -> here's the
4431.239 -> firstpost.html file generated by the
4433.92 -> build process and if we look inside it
4436.64 -> we can see our react component
4438.8 -> pre-rendered to html as usual and it
4442.08 -> used the prop values we returned in our
4444.96 -> get static props function which are the
4447.36 -> post title and body so far nothing
4450.8 -> strange but in addition to the html file
4454.32 -> the build also generated this json file
4457.6 -> as you can see this file simply contains
4460.08 -> our page props in json format so again
4464.48 -> why does next gs generate that separate
4468 -> json file with our props to explain that
4471.04 -> let's run the app in production mode
4473.36 -> with npm start
4478.08 -> now if we reload the page you'll see
4480.56 -> that nothing gets logged in the server
4483.36 -> let me clear the logs to make it more
4485.199 -> obvious
4486.719 -> nothing gets locked so our get static
4489.6 -> props function is not called because the
4492.64 -> page is already available as a static
4495.52 -> html file generated during the build we
4498.8 -> can check that by looking at the network
4501.12 -> requests
4502.32 -> and the server response will be the same
4505.8 -> firstpost.html file we opened in the
4508.32 -> editor a minute ago this is what happens
4511.6 -> when we load the first post page
4513.92 -> directly but what if we start from the
4516.719 -> home page instead we know that in this
4519.6 -> case the browser loads the html file for
4522.48 -> the home page but when we click the
4525.04 -> first post link next js uses client site
4529.04 -> navigation to open the new page so in
4532.08 -> this case the browser does not load the
4534.96 -> full html page for the first post
4538.56 -> instead if we look at all the requests
4541.36 -> not just html the browser loaded that
4545.48 -> firstboss.json file that we've seen in
4548.159 -> the build folder
4549.84 -> so the browser will render the first
4552.159 -> post page component by loading the props
4555.36 -> from this json file and this solves that
4558.64 -> small mystery of why next gs generates a
4562.32 -> json file along with the html for an ssg
4566.239 -> page it's used to support client-side
4569.44 -> navigation now let's restart our dev
4572.4 -> server so we can continue our
4574.159 -> development
4577.28 -> but hopefully this video has given you a
4579.92 -> better understanding of how get static
4582.8 -> props works and you can probably see why
4585.92 -> the function is called get static props
4589.28 -> because those props are set at build
4592.159 -> time and used to render static html
4595.92 -> pages
4603.04 -> now that we know how get static props
4605.76 -> works let's go back to our original plan
4608.719 -> that was to load the post data from this
4612 -> markdown file to take one step at a time
4615.28 -> in this video we'll focus only on how to
4618.08 -> read a file and leave parsing the
4620.88 -> markdown for later so for now let's
4623.92 -> assume we want to load the data from a
4626.48 -> json file called firstpost.json
4630.239 -> this will contain a json object with our
4632.8 -> past details that is the title and the
4636 -> body that for now can be some simple
4638.64 -> text
4640.159 -> but let's write that this is in a json
4643.199 -> file so we'll see something different
4645.6 -> when we load the data
4647.6 -> okay starting with the json file
4650.159 -> simplifies our task a little bit in that
4653.199 -> now we just need to figure out how to
4656.64 -> read a file from this code now if this
4660.08 -> code was meant to run inside the browser
4663.12 -> it wouldn't really be possible to read a
4665.679 -> local file that's inside our project but
4668.88 -> remember that the getstaticprops
4671.36 -> function runs on the server which really
4674.239 -> means in node.js so in our function we
4677.52 -> can use any of the apis provided by
4680.64 -> node.js and node.js provides a module
4684.4 -> called filesystem or fs for short which
4688.239 -> includes a function called read file
4691.12 -> that does exactly what the name says so
4693.679 -> let's see how to use this function in
4695.76 -> our code
4697.92 -> first we want to import that function
4700.48 -> from the fs module and i'll use the
4703.44 -> promises variant that's more convenient
4706.159 -> so that module should contain a function
4708.56 -> named readfall
4711.44 -> now we can call readfall here
4715.04 -> and we want to pass it the path to the
4717.28 -> file which is under the content and then
4720.4 -> posts folders inside our project so the
4723.44 -> path is content slash posts slash
4727.719 -> firstpost.json and this is relative to
4730.56 -> the project folder because that's where
4733.28 -> the server runs we also need to pass a
4736.159 -> second argument with the character
4738.4 -> encoding in this case utf-8 now this
4742.32 -> function returns the data inside that
4745.12 -> file but it's asynchronous so we need to
4747.92 -> await the result let's quickly log the
4751.04 -> data so we can see exactly what that
4753.28 -> function returns
4756.56 -> let me show the server logs
4759.36 -> and if we reload this page you can see
4761.84 -> that the data is in fact the content of
4764.64 -> the json file as we expected okay so at
4768.32 -> this point we can get the past details
4772.4 -> simply by parsing that json data and
4776 -> that past object is what we want to
4778.719 -> return in our props instead of these
4781.36 -> hard-coded values
4783.199 -> let's see if this works
4785.12 -> i'll show the server logs as well
4789.04 -> and if we reload the page now we can see
4791.679 -> that it displays my first post in a json
4795.04 -> file so it's clearly reading the data
4797.76 -> from the file of course the server logs
4800.4 -> printed the same data let's stop here
4803.199 -> for this video this is how we can read
4806.239 -> data from a local file but perhaps more
4809.199 -> importantly we've also seen that in our
4811.76 -> get static props function we can use any
4814.88 -> of the functionality provided by node.js
4818.32 -> because this code only runs on the
4820.8 -> server
4827.84 -> we've seen how to load some data from a
4830.639 -> local file in our get static props
4833.28 -> function now i'd like to do some
4835.44 -> refactoring and extract that bit of
4838.4 -> logic into its own separate module to
4841.12 -> follow this separation of concerns
4843.679 -> design principle let's start by creating
4846.639 -> a separate function inside this well
4849.36 -> let's call it get post
4852 -> and this function will read the post
4854.4 -> data so we can just copy our existing
4857.12 -> code
4858 -> except that here we can return the post
4861.28 -> object directly so now we can call this
4864.48 -> get post function inside get static
4867.44 -> props and get the past object by
4870.639 -> awaiting the promise returned by get
4873.6 -> post we're doing a refactoring so the
4876.4 -> functionality of our app should stay the
4878.719 -> same but it's always good to check
4881.44 -> now at the moment we're always loading
4883.84 -> the first pass but we can make our get
4886.8 -> post function more general by passing
4889.679 -> which post to load as an argument and
4892.48 -> then accept it as a parameter here that
4894.96 -> i'll call slug meaning the part of the
4897.679 -> url that identifies a specific post
4901.52 -> now we can change the string to be
4903.76 -> backtick delimited so that we can insert
4906.639 -> this log as a placeholder and let's
4909.52 -> quickly check that we didn't break
4911.36 -> anything it's all good
4913.44 -> what i'd like to do now is move that
4916.239 -> function to a separate module because
4918.8 -> this file is really about rendering a
4921.36 -> page so the details of how to get the
4924.8 -> data don't really belong in here a
4928 -> common approach in next.js apps is to
4930.96 -> have a lab folder at the top level of
4933.6 -> the project that contains any code
4936.32 -> that's not specific to pages or other
4939.679 -> visual components so here we could
4942.08 -> create a module called post since it
4944.96 -> will contain functions to get the post
4947.76 -> data and we can simply move the function
4950.719 -> we just wrote from the first post page
4954.48 -> we just need to make sure to export it
4957.04 -> from this module
4958.56 -> so we can then go and import it in the
4961.12 -> other file
4963.28 -> and i'll use the auto import feature so
4966 -> the editor automatically finds the right
4968.239 -> path let's save and we have an error now
4971.84 -> that's why it's good to test the app
4974.4 -> after every change so if anything breaks
4977.28 -> it's easier to fix in this case i simply
4980.08 -> forgot to move the read file import into
4983.52 -> the new posts module where it's actually
4986.159 -> used
4987.12 -> if i save both files now
4990.32 -> that error should go away
4993.12 -> okay it's working again and that's all
4996.32 -> the refactoring i wanted to do
4998.8 -> note how this way in this file to get
5001.679 -> the past data we simply call the getpost
5004.639 -> function there's nothing in here about
5007.36 -> how to get that data and that's a good
5010.48 -> thing because in this page we're only
5012.96 -> interested in getting the data so we can
5015.199 -> display it the fact that the past data
5018.4 -> comes from a local file is irrelevant as
5021.76 -> far as displaying the page is concerned
5025.12 -> that's why it's good practice to
5027.52 -> encapsulate that sort of logic in a
5030.08 -> separate layer of our application that
5032.719 -> deals with fetching the data
5041.36 -> okay we've extracted the logic to read
5044.48 -> the past file in its own module but
5047.199 -> we're still reading the data from a json
5049.92 -> file rather than from the markdown file
5053.04 -> which was our ultimate goal to be able
5055.76 -> to use the contents of this file we need
5058.56 -> a way to parse the markdown format and
5061.6 -> transform it to html that will then
5065.12 -> insert into our page there are quite a
5067.84 -> few libraries available in javascript to
5070.48 -> work with markdown in this example we'll
5073.36 -> use one called marked that's very easy
5076.56 -> to use let's see how it works
5080.4 -> for a start we'll need to install that
5083.199 -> library so let me open the package to
5085.6 -> json where we have our dependencies
5087.92 -> let's open the terminal
5091.12 -> and stop the dev server
5093.52 -> because we need to run npm install and
5096.8 -> download the marked package
5099.44 -> okay now i want to show you quickly how
5102.239 -> that library works and i'll do that by
5104.719 -> starting an interactive node prompt
5108.08 -> let's start by importing the marked
5110.88 -> module and i'm using require instead of
5113.92 -> import just because import statements
5116.96 -> are still not supported when running
5119.36 -> node.js in this way but once we have the
5122.56 -> marked function we can use it to
5124.719 -> generate some html from a markdown
5127.76 -> string let's write a markdown header for
5130.719 -> example
5133.12 -> and if we print that html
5136.239 -> you can see that it generated an h1
5139.04 -> heading in html
5141.28 -> so it's very simple to use
5143.679 -> now let's restart our next gs dev server
5148.239 -> and let's go and use that library to
5150.56 -> read markdown files
5152.719 -> so in this file we want to import the
5155.28 -> marked function
5157.84 -> from the module with the same name
5160.48 -> now reading the data from the file will
5163.36 -> work in the same way except that we want
5166 -> to read a markdown file instead of a
5168.56 -> json one at this point we want to
5171.12 -> transform that data that is a markdown
5174.239 -> string to html using marked
5177.76 -> and i think i'm going to rename this
5179.76 -> variable because data is a bit too vague
5182.96 -> let's call it source instead as in the
5186.08 -> markdown source
5187.84 -> now we no longer need to parse any json
5190.88 -> but we still need to return an object
5193.36 -> from here because that's what we expect
5196.239 -> where we use the post data if you
5198.88 -> remember in the page we expect the post
5202.08 -> to have a title and a body so the get
5205.679 -> post function should return an object
5208 -> with those two properties but here we
5210.639 -> have a small problem in that we parse
5213.52 -> the markdown into a single html variable
5217.28 -> so we could return the html as the body
5221.28 -> of the post but right now we don't
5224 -> really have a separate title to return
5227.44 -> that's okay for now we'll see how to add
5230.239 -> metadata to our markdown file in the
5233.04 -> next video for the time being the title
5236 -> will just be empty which is not ideal
5238.96 -> but shouldn't break anything
5241.199 -> so let's save these changes and see
5243.6 -> what's being displayed in the page now
5246.32 -> you can see that it's clearly reading
5248.4 -> the content from our markdown file and
5251.36 -> converting it to html the problem is
5254.4 -> that it's actually displaying the html
5257.28 -> source code rather than rendering it and
5260.719 -> that's because in our page component
5263.199 -> we're currently displaying the past body
5266.08 -> as the child of a paragraph element so
5269.52 -> react will escape any special html
5272.8 -> characters contained in the post body
5275.52 -> string but in this case we actually want
5278.4 -> to insert the post body directly as html
5282.96 -> so how can we do that let's remove this
5285.6 -> paragraph since our post body could
5288.4 -> potentially contain multiple paragraphs
5291.28 -> let's use an article element instead to
5294.159 -> contain the past body which is
5296.48 -> semantically more appropriate
5298.88 -> now react provides a way to insert html
5302.8 -> directly inside an element by using a
5305.6 -> prop called dangerously set inner html
5309.679 -> and it's called like that because
5312.159 -> setting the html directly can be
5314.88 -> dangerous from a security point of view
5317.679 -> if the html we're setting here comes
5320.639 -> from content entered by our users they
5324.32 -> could use this to inject scripts into
5327.28 -> our page but in this case we know that
5330.48 -> the content always comes from markdown
5333.28 -> files that we wrote so it's not a
5336.159 -> problem here now to set this prop we
5339.04 -> need to pass a javascript object that's
5341.92 -> inside the jsox expression so you end up
5344.639 -> with double curly braces
5346.96 -> this object must have a property called
5349.52 -> underscore underscore html and this is
5352.32 -> where we pass our past body variable
5355.44 -> react makes this deliberately convoluted
5358.639 -> because they want developers to think
5361.199 -> very carefully before setting the inner
5364.08 -> html directly
5366 -> anyway if we save this now you can see
5368.4 -> that the page displays the content as we
5371.44 -> expected so it rendered the markdown we
5375.04 -> had in our paused file in a suitable way
5378.08 -> the markdown header is shown as a h1
5381.52 -> heading in the page the text within
5384.159 -> double underscores is displayed as bold
5387.28 -> text and so on okay so now that we are
5390.56 -> finally using the content from the
5392.96 -> markdown file we can delete this json
5395.92 -> file that we wrote just as a stepping
5398.56 -> stone
5399.76 -> and to recap we added the marked library
5403.12 -> to pass the markdown into html and we're
5406.719 -> using dangerously set inner html to
5410.48 -> display that html directly into the page
5420.719 -> in our post page we're now displaying
5423.28 -> the content from our markdown file as
5426.32 -> the body of the post but we're missing a
5429.44 -> separate title property as we can notice
5432.56 -> in the browser tab title that's because
5435.76 -> when we parse the markdown we get the
5438.4 -> result as a single html string
5441.679 -> so how could we extract the title from
5444.4 -> our markdown file the best approach is
5447.28 -> to add a front matter to this file the
5450.639 -> front matter is a block at the beginning
5453.28 -> of a file delimited by triple minus
5456.48 -> signs and it contains metadata in yaml
5460.239 -> format
5461.36 -> so we can use this block to define
5463.92 -> arbitrary properties related to this
5466.56 -> file for example the title
5469.12 -> this way we'll be able to extract these
5471.679 -> properties separately from the rest of
5474 -> the file now if we define the title
5476.719 -> separately we don't need to repeat it in
5479.36 -> the main content as well so let's remove
5481.92 -> this header
5483.28 -> the question at this point is how do we
5485.92 -> extract those properties from the front
5488.56 -> matter where we read that file we'll
5491.6 -> need to change this logic a little bit
5494.08 -> to first parse the front matter and then
5497.44 -> render the markdown and to parse the
5500.4 -> front matter we'll use another library
5502.88 -> called gray matter let's look at an
5505.44 -> example
5507.04 -> given a string that starts with a front
5509.84 -> matter block and then some other content
5512.56 -> gray matter will return an object
5514.719 -> containing both the main content and a
5518 -> data object with the properties defined
5520.96 -> in the front matter let's keep this in
5523.52 -> mind as we go and use that library in
5526.639 -> our project
5528.48 -> first of all we'll need to install that
5530.88 -> package as usual
5534.56 -> so i'm going to stop the dev server and
5537.199 -> run npm install grey meta
5542.96 -> let's restart the dev server again
5546.88 -> and go back to our javascript code in
5549.6 -> this file we want to import that library
5552.56 -> let's call it simply matter even though
5555.12 -> the module is gray matter and this is a
5558.32 -> function that we can call
5561.679 -> to parse the content of the file that is
5564.4 -> our source
5565.84 -> as we've seen in the documentation this
5568 -> returns an object
5569.84 -> with data and content properties where
5573.28 -> data contains the properties defined in
5575.84 -> the front matter and content is the rest
5578.48 -> of the file that in our case is in
5580.639 -> markdown format so this is what we want
5583.84 -> to convert to html but now we can also
5587.199 -> return a title property
5590.159 -> because that will be available in the
5592.32 -> data extracted from the front meta okay
5596 -> let's save this file and see if it works
5600.8 -> i'll reload the page just in case but
5603.6 -> you can see in the browser tab that it's
5605.76 -> displaying the title correctly and if
5608.56 -> you look at the message in the browser
5610.239 -> console you can see the title there as
5612.719 -> well
5613.52 -> okay so that's how we can attach
5616 -> properties to a post we only set a title
5619.679 -> so far but we can add any properties we
5622.48 -> like here for example it would be useful
5625.199 -> to have a date showing when the post was
5628.88 -> written
5629.84 -> and this could be a date string in iso
5632.719 -> format like this
5634.4 -> so if we save this file now we can go
5637.12 -> and use that date in our get post
5640.239 -> function we simply want to return the
5642.96 -> date extracted from the front matter
5645.679 -> data and then in the page we can add
5648.8 -> maybe a simple paragraph with the past
5651.44 -> date
5652.8 -> i'm not going to worry about the styling
5655.44 -> for this example but you can see the
5657.36 -> date displayed at the top of the page
5660.08 -> okay so that's how the front matter
5662.88 -> works we could actually simplify this
5665.36 -> code a little bit by destructuring the
5668.32 -> data properties directly here so then in
5671.679 -> the post object we can use shorthand
5674.56 -> property names for date and title and at
5677.92 -> this point we could even rename html to
5681.04 -> body
5683.44 -> and finally we could move all the
5685.28 -> properties to the same line to make the
5687.92 -> code shorter
5690.239 -> that was just a bit of refactoring that
5692.639 -> shouldn't change the functionality
5695.199 -> but with this we are finally done with
5698 -> rendering our first past page
5700.56 -> loading the markdown and everything
5703.04 -> so in the next video we'll see how to
5705.04 -> add more posts
5713.119 -> at this stage our app can display our
5715.84 -> first post loading the content from a
5718.96 -> markdown file
5720.639 -> now what if we want to add another blog
5723.36 -> post we could create another markdown
5726.08 -> file let's say second post and let's
5729.6 -> change the date
5731.199 -> the title to say second and same in the
5734.48 -> body
5736.56 -> we can remove the rest for this example
5739.76 -> now how do we display the data in the
5742.56 -> new markdown file we could create
5745.119 -> another page here but it will be very
5747.679 -> similar to this existing first past page
5751.44 -> almost all the code in this page would
5754.239 -> stay exactly the same when displaying a
5756.96 -> different post the only thing that needs
5759.84 -> to change is the value we passed to get
5762.88 -> past that specifies which file to load
5766.56 -> so it would be nice to be able to reuse
5769.44 -> the code in this page for all the posts
5773.199 -> we can easily rename this component to
5775.6 -> simply post page rather than first post
5779.119 -> page
5782.32 -> and our app still works fine because the
5785.119 -> name of our component doesn't really
5786.88 -> matter as long as it's the default
5789.119 -> export but as it is this page will still
5792.56 -> be visible only under the first parsed
5795.679 -> path because as we know the next gs
5798.639 -> router exposes each page based on its
5801.84 -> file name
5803.119 -> what if we want the same component to be
5805.679 -> used for multiple pages under slush
5808.96 -> posts like a sort of wildcard match
5812.639 -> next.js allows us to define dynamic
5816 -> routes by naming this page in a special
5818.719 -> way we can write square brackets and
5821.52 -> inside that the name of the path
5823.92 -> parameter for example slug this is a
5827.52 -> strange name for file but it's perfectly
5830.48 -> legal to have square brackets in a file
5833.04 -> name
5833.92 -> so the idea is that any url that starts
5837.76 -> with posts slash something will match
5840.88 -> our post
5842.4 -> slog page but we need to do something
5845.44 -> else before this works we now get an
5848.239 -> error that says get static paths is
5851.36 -> required for dynamic ssg pages
5855.04 -> so we need to add a get static paths
5858.08 -> function to our code
5860.159 -> this is similar to get static props in
5863.119 -> that it must be exported and async
5866.8 -> but the purpose of this function is to
5869.44 -> tell next gs which paths are valid for
5873.199 -> this dynamic route
5875.119 -> let's implement this function and you'll
5877.119 -> see what i mean
5878.56 -> this function returns an object that
5880.88 -> contains a path array and each item in
5884.56 -> this array is an object that in turn
5887.199 -> contains a params object with parameters
5890.88 -> that identify this specific route
5894.08 -> for example in our case we want to set a
5896.719 -> parameter called slug because that's
5899.52 -> what we put inside square brackets in
5902.239 -> the file name
5903.52 -> now we know that our existing page was
5906.4 -> visible under posts slash first passed
5909.92 -> so we can set slug to first post here we
5913.52 -> are basically telling next gs that first
5916.8 -> post is one of the valid paths for our
5920.56 -> post page but now we can add more paths
5924.32 -> for example add a second post here so
5927.76 -> this way next gs knows that posts slash
5931.6 -> second post is also a valid url now the
5935.679 -> object returned by get static paths must
5938.88 -> also include a fallback property that in
5941.92 -> our case we want to set to falls
5944.88 -> the fallback option tells next.js what
5947.92 -> to do if none of the paths above matches
5951.84 -> the requested url setting it to false
5954.88 -> means no match will result in a 404 not
5958.32 -> found page which is what we want in this
5961.199 -> case next js also provides some more
5964.719 -> advanced features where if a page
5967.44 -> doesn't exist you can try building it on
5970.4 -> demand but in that case your website
5973.44 -> will no longer be fully static
5976.32 -> now the path resetting get static paths
5979.52 -> will be available in get static props
5982.8 -> this function receives an argument
5984.719 -> called context
5986.32 -> let's start by logging that context so
5989.119 -> we'll see exactly what it contains now
5991.679 -> let me show the browser window again
5995.92 -> and also the server logs let's reload
5998.639 -> the page and see what gets logged here's
6001.679 -> the call to get static props and the
6004.48 -> context object contains some params with
6007.679 -> this log set to first passed
6010.719 -> let's go through what happened step by
6013.119 -> step to make sure we understand what's
6015.44 -> going on in the browser we requested the
6018.4 -> posts first post url the next gs server
6022.719 -> received the request and matched it to
6025.92 -> our slug in square brackets page because
6029.199 -> it's under the posts folder and it's a
6032.159 -> dynamic route so it matches anything
6035.52 -> but for this particular request this log
6038.56 -> parameter is set to first post
6042 -> then next gs executes our get static
6045.44 -> paths function to check if first post is
6049.119 -> in fact a valid path for this page
6052.48 -> and it finds that it matches the first
6055.36 -> item in our paths array so first post is
6058.88 -> a valid request and next js goes on to
6062.56 -> call the get static props function
6065.6 -> passing the matching path in the context
6069.04 -> in get static props we then load the
6071.76 -> post data from the markdown file which
6074.56 -> is then passed as props to the component
6077.52 -> render function that renders the html as
6080.96 -> usual
6081.92 -> now what happens if we request second
6085.04 -> post instead the page still says first
6088.48 -> passed but that's just because at the
6091.199 -> moment we always load the same markdown
6094.239 -> file if we look at the server logs
6096.639 -> however
6097.679 -> we can see that this time get static
6100.48 -> props was called with second passed as
6104.08 -> this log parameter so we should make use
6107.6 -> of that slog parameter in our
6109.96 -> getstaticprops function to load the data
6112.88 -> for the rightpost
6114.8 -> let's destructure this context object
6117.6 -> and extract the params in fact we could
6120.639 -> even go one level deeper and get this
6123.6 -> lock directly from here
6125.92 -> and now instead of always loading the
6128.48 -> first post data we can pass this log
6131.52 -> here
6132.4 -> this should work because we named our
6134.88 -> markdown files in the same way as our
6137.52 -> url paths
6139.28 -> so if we save this change we can
6141.44 -> immediately see that the page now shows
6144.32 -> the second post data so it's loading the
6147.44 -> right markdown file let's make sure
6150.239 -> everything else still works if we start
6153.04 -> from the first post that still shows the
6155.92 -> right content and if we request the
6158.48 -> second post we need to enter the path
6161.04 -> manually because we haven't added a link
6163.36 -> to it yet but of course that also works
6166.239 -> fine so that's how dynamic routes work
6169.84 -> in next.js there are a few moving parts
6173.6 -> here we need to name the page file with
6177.04 -> this special square bracket syntax to
6179.76 -> match any request under the post path
6183.44 -> write a get static paths function that
6186.4 -> says which paths are actually valid and
6189.36 -> then use the params passed in the
6191.84 -> context to get static props to load the
6195.119 -> right data
6202.48 -> we made our past page a dynamic root so
6206.159 -> the same page component will be used for
6208.96 -> all the posts and the paths we return in
6212.32 -> the get static paths function will
6214.88 -> inform next gs of which posts actually
6218.239 -> exist
6219.199 -> but why do we need to write each post's
6221.84 -> log manually in here we could just look
6224.8 -> at the content posts folder see which
6227.679 -> markdown files it contains and generate
6230.639 -> the list of static paths automatically
6233.6 -> this way if we add more markdown files
6236.48 -> they will automatically be visible as
6239.04 -> post pages
6240.56 -> this is exactly what we'll do in this
6242.639 -> video
6243.679 -> just like we have a get post function
6246.32 -> that reads a markdown file we can add
6248.8 -> another function that will list all the
6251.199 -> files and return those logs
6254.239 -> now how do we get a list of files in
6257.119 -> addition to read file the node.js file
6260.239 -> system module provides a read there
6263.04 -> function and we can use this function to
6265.6 -> read all the files inside our content
6268.48 -> posts folder reader returns an array of
6271.84 -> files and it's asynchronous
6274.48 -> at this point we have the list of files
6277.119 -> so our files array will contain the file
6280.08 -> names as strings
6282.199 -> firstpost.md and secondpost.md
6285.679 -> but in our getslugs function we want to
6288.08 -> return just those logs that are
6290.719 -> effectively the file names but without
6293.28 -> extension so we want to take the files
6295.76 -> array and transform it
6298 -> first i'd like to filter it and keep
6300.4 -> only the files that end in dot md
6303.44 -> just in case there are any other files
6305.679 -> inside that folder that are not marked
6308.32 -> down we should just ignore them and then
6310.88 -> we want to map or transform each file to
6314.239 -> remove its extension for that we can use
6317.119 -> the slice method and we want to keep all
6320.08 -> characters from the beginning of the
6322 -> string up until three characters from
6324.8 -> the end so minus three let me show you
6327.6 -> quickly y minus three if we have a
6330.56 -> string with a file name like
6333.08 -> sumpast.md then slice from 0 to -3 will
6337.52 -> return some past
6339.6 -> dot md is 3 characters so to stop before
6343.199 -> that we write -3 in fact we could
6346.32 -> actually make this more explicit in our
6348.719 -> code by defining a constant called
6351.44 -> suffix which is our file extension and
6354.239 -> then instead of dot md we can use that
6356.96 -> suffix and instead of this magic number
6359.92 -> we can write suffix dot length that's
6362.8 -> the same thing but it should be more
6364.56 -> readable anyway this function should now
6367.36 -> return all these logs for our posts
6370.159 -> based on the markdown file names
6372.96 -> now we can go and use our new function
6375.44 -> inside getstaticpath
6377.76 -> we'll get all availables logs by
6380.159 -> awaiting the result of calling getslugs
6384.56 -> now we want to use these logs to
6386.639 -> generate the paths
6389.52 -> i'll write it above the old paths for
6391.679 -> now slugs is an array of strings so we
6394.8 -> want to transform each element into an
6397.44 -> object
6398.96 -> because each element in the paths array
6401.679 -> must contain a params property and
6404.56 -> inside params we can simply pass our
6407.119 -> slog value so our new paths array
6410.239 -> contains the same type of elements as
6412.8 -> our old one and we can delete the old
6415.28 -> one now let's save and check if this
6417.92 -> works the second past page is still
6420.639 -> working
6421.76 -> now if we start from home and open the
6424.719 -> first post this also works so the
6427.679 -> existing paths are still valid but now
6430.719 -> we can try adding another post
6434.08 -> i'll simply duplicate the second post
6436.48 -> and call it third past
6438.8 -> and then change the content as well to
6440.96 -> say third everywhere
6443.92 -> and just by adding that new markdown
6446.8 -> file we should now be able to request
6448.96 -> the third past path and this shows a
6451.84 -> page with the content loaded from the
6454.159 -> new file this worked without us having
6456.88 -> to write third post manually in the get
6459.76 -> static paths function because now it
6462.48 -> automatically finds all the available
6464.719 -> markdown files by reading the directory
6467.44 -> contents
6474.4 -> we're now generating the list of
6476.56 -> available posts automatically based on
6479.199 -> the markdown files present inside our
6482 -> content folder but there's another place
6484.719 -> where we still have a manual list of
6486.96 -> posts and that's the home page in fact
6489.84 -> right now we're only showing a link to
6492.08 -> the first post here we could change the
6495.119 -> home page code to call our new get slugs
6498.48 -> function and automatically generate a
6500.96 -> list of links for all the available
6503.44 -> posts
6504.56 -> now we know that there's a way to pass
6507.04 -> some props to a page component so here's
6510.239 -> a mini challenge for you why don't you
6512.56 -> pause this video and try to implement
6514.96 -> this step yourself we want the home page
6518.08 -> to receive the list of posters logs
6521.119 -> returned by the get slugs function and
6524.159 -> just log them for now do you remember
6526.8 -> how to do that i'll wait just a couple
6529.199 -> of seconds before moving on to the
6531.199 -> solution
6532.96 -> okay so the way we can pass some props
6535.84 -> to a page component is by writing a get
6538.92 -> getstaticprops function
6541.04 -> here we can call getslugs that we can
6543.679 -> auto-import and this will return those
6546.4 -> logs but as a promise that we need to
6549.119 -> await
6550.159 -> the getstaticprops function always
6552.639 -> returns an object with the props and in
6555.36 -> this case we want our props to contain
6557.92 -> those lugs okay let's save this file and
6560.88 -> see what happens
6562.239 -> we'll need to reload the page for get
6564.56 -> static props to get called but you can
6566.96 -> see that the homepage component received
6569.84 -> an array of slugs with the three
6571.84 -> available posts okay at this point we
6574.8 -> could use those slugs to generate the
6577.44 -> list of links in the page by repeating
6580.32 -> the list item element using a different
6582.88 -> slug on each link
6584.8 -> there's a small problem though in
6586.639 -> addition to this log in the link we also
6589.199 -> show the post title and we don't
6591.92 -> currently have this in our props
6594.4 -> so just calling gets logs is not enough
6598 -> we'll need to write another function
6599.679 -> that gives us not only those logs but
6602.08 -> also the titles of all posts
6605.119 -> let's create that new function as usual
6607.679 -> exported and async and let's call it get
6610.719 -> posts
6612.4 -> here we can start by getting all this
6614.8 -> logs by calling our existing get slugs
6617.679 -> function and then we can build an array
6620.239 -> of posts
6622 -> that is what we want to return from this
6624.4 -> function and to fill that array we want
6627.119 -> to iterate through each slug
6630.08 -> given as log we can get a full post
6632.88 -> object by calling our other existing
6635.199 -> function that is getpost and at this
6637.76 -> point we can simply add this post to the
6640.56 -> array
6641.92 -> okay let's see if this works
6645.599 -> in our home page we want to use get
6648.08 -> posts instead of get slugs and we'll get
6651.119 -> a list of posts that's what we'll pass
6654 -> in the props
6655.36 -> if we reload the page we can see that
6657.92 -> the home page received an array with
6660.56 -> three pasts and each past object has
6663.76 -> body date and title so that's not quite
6667.84 -> what we wanted because we also need this
6670.56 -> log for each post to generate a link and
6673.599 -> that's missing from these properties so
6676.159 -> let's go and modify our get posts
6678.4 -> function a little bit and when we push
6680.96 -> each element we can create an object
6683.199 -> that includes this log and then expand
6686 -> all the other past properties using the
6688.48 -> spread syntax let's save these changes
6691.28 -> and try again
6693.44 -> if we look at an individual post now you
6696.239 -> can see that we have this log in
6698.239 -> addition to the other properties we only
6700.8 -> really need slug and title so we could
6703.28 -> actually remove the body but that's an
6705.599 -> optimization that i'm not going to worry
6708.159 -> about for this example rather let's go
6710.8 -> and make use of those posts we receive
6713.76 -> in the home page props now
6717.76 -> we want to repeat each list item element
6720.56 -> so let's take the posts and map each
6723.199 -> post
6725.599 -> to the jsx elements displaying a link to
6728.719 -> that post we can reuse our existing list
6731.92 -> item element
6733.28 -> but we want to replace the href with an
6735.92 -> expression
6738.32 -> and i'm using a template literal so we
6740.48 -> can insert the post slug inside this
6743.599 -> string
6744.639 -> finally we can display the post title as
6747.599 -> the link text
6749.199 -> and let's not forget to add a key to
6751.76 -> each item as you probably know in react
6754.8 -> whenever we have an array of elements we
6757.28 -> need to set a key on each element that
6760.239 -> uniquely identifies it so here we could
6763.04 -> use the posters log that should be
6765.44 -> unique and with this we can save and we
6768.639 -> see three links in the page one for
6770.88 -> every available post let's refresh the
6773.44 -> page just in case
6775.28 -> and test those links the second past
6778.4 -> works fine
6779.76 -> and so does the third one so looks like
6782.48 -> our task for this video is done
6785.199 -> and this is how we can generate a list
6787.84 -> of links automatically in our home page
6790.8 -> we are simply using a get static props
6793.36 -> function to populate the list of
6795.52 -> available posts

Source: https://www.youtube.com/watch?v=gCtagNB3W2U