Skip to content

Commit 3c1e69e

Browse files
committed
Added lesson 10
1 parent e54b6dd commit 3c1e69e

32 files changed

+9137
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,5 @@
7878
- 🔗 [Chapter 7 - Route Handlers for API Routes](https://github.com/gitdagray/next-js-course/tree/main/next07)
7979
- 🔗 [Chapter 8 - Build a REST API](https://github.com/gitdagray/next-js-course/tree/main/next08)
8080
- 🔗 [Chapter 9 - Middleware](https://github.com/gitdagray/next-js-course/tree/main/next09)
81+
- 🔗 [Chapter 10 - Background & On-Demand Revalidation](https://github.com/gitdagray/next-js-course/tree/main/next10)
8182

next10/.eslintrc.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "next/core-web-vitals"
3+
}

next10/.gitignore

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# next.js
12+
/.next/
13+
/out/
14+
15+
# production
16+
/build
17+
18+
# misc
19+
.DS_Store
20+
*.pem
21+
22+
# debug
23+
npm-debug.log*
24+
yarn-debug.log*
25+
yarn-error.log*
26+
.pnpm-debug.log*
27+
28+
# local env files
29+
.env*.local
30+
31+
# vercel
32+
.vercel
33+
34+
# typescript
35+
*.tsbuildinfo
36+
next-env.d.ts

next10/README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2+
3+
## Getting Started
4+
5+
First, run the development server:
6+
7+
```bash
8+
npm run dev
9+
# or
10+
yarn dev
11+
# or
12+
pnpm dev
13+
```
14+
15+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
16+
17+
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
18+
19+
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
20+
21+
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
22+
23+
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
24+
25+
## Learn More
26+
27+
To learn more about Next.js, take a look at the following resources:
28+
29+
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
30+
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
31+
32+
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
33+
34+
## Deploy on Vercel
35+
36+
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
37+
38+
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

next10/app/api/hello/route.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export async function GET(request: Request) {
2+
return new Response('Hello, Next.js!')
3+
}

next10/app/components/ListItem.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import Link from "next/link"
2+
import getFormattedDate from "@/lib/getFormattedDate"
3+
4+
type Props = {
5+
post: BlogPost
6+
}
7+
8+
export default function ListItem({ post }: Props) {
9+
const { id, title, date } = post
10+
const formattedDate = getFormattedDate(date)
11+
12+
return (
13+
<li className="mt-4 text-2xl dark:text-white/90">
14+
<Link className="underline hover:text-black/70 dark:hover:text-white" href={`/posts/${id}`}>{title}</Link>
15+
<br />
16+
<p className="text-sm mt-1">{formattedDate}</p>
17+
</li>
18+
)
19+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import Image from "next/image"
2+
3+
export default function MyProfilePic() {
4+
return (
5+
<section className="w-full mx-auto">
6+
<Image
7+
className="border-4 border-black dark:border-slate-500 drop-shadow-xl shadow-black rounded-full mx-auto mt-8"
8+
src="/images/profile-photo-600x600.png"
9+
width={200}
10+
height={200}
11+
alt="Dave Gray"
12+
priority={true}
13+
/>
14+
</section>
15+
)
16+
}

next10/app/components/Navbar.tsx

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import Link from "next/link"
2+
import { FaYoutube, FaTwitter, FaGithub, FaLaptop } from "react-icons/fa"
3+
4+
export default function Navbar() {
5+
return (
6+
<nav className="bg-slate-600 p-4 sticky top-0 drop-shadow-xl z-10">
7+
<div className="prose prose-xl mx-auto flex justify-between flex-col sm:flex-row">
8+
<h1 className="text-3xl font-bold text-white grid place-content-center mb-2 md:mb-0">
9+
<Link href="/" className="text-white/90 no-underline hover:text-white">Dave Gray</Link>
10+
</h1>
11+
<div className="flex flex-row justify-center sm:justify-evenly align-middle gap-4 text-white text-4xl lg:text-5xl">
12+
<Link className="text-white/90 hover:text-white" href="https://www.youtube.com/@DaveGrayTeachesCode">
13+
<FaYoutube />
14+
</Link>
15+
<Link className="text-white/90 hover:text-white" href="https://courses.davegray.codes/">
16+
<FaLaptop />
17+
</Link>
18+
<Link className="text-white/90 hover:text-white" href="https://github.com/gitdagray">
19+
<FaGithub />
20+
</Link>
21+
<Link className="text-white/90 hover:text-white" href="https://twitter.com/yesdavidgray">
22+
<FaTwitter />
23+
</Link>
24+
</div>
25+
</div>
26+
</nav>
27+
)
28+
}

next10/app/components/Posts.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { getSortedPostsData } from "@/lib/posts"
2+
import ListItem from "./ListItem"
3+
4+
export default function Posts() {
5+
const posts = getSortedPostsData()
6+
7+
return (
8+
<section className="mt-6 mx-auto max-w-2xl">
9+
<h2 className="text-4xl font-bold dark:text-white/90">Blog</h2>
10+
<ul className="w-full">
11+
{posts.map(post => (
12+
<ListItem key={post.id} post={post} />
13+
))}
14+
</ul>
15+
</section>
16+
)
17+
}

next10/app/favicon.ico

25.3 KB
Binary file not shown.

next10/app/globals.css

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
@tailwind base;
2+
@tailwind components;
3+
@tailwind utilities;

next10/app/layout.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import './globals.css'
2+
import Navbar from './components/Navbar'
3+
import MyProfilePic from './components/MyProfilePic'
4+
5+
export const metadata = {
6+
title: "Dave's Blog",
7+
description: 'Created by Dave Gray',
8+
}
9+
10+
export default function RootLayout({
11+
children,
12+
}: {
13+
children: React.ReactNode
14+
}) {
15+
return (
16+
<html lang="en">
17+
<body className="dark:bg-slate-800">
18+
<Navbar />
19+
<MyProfilePic />
20+
{children}
21+
</body>
22+
</html>
23+
)
24+
}

next10/app/page.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import Posts from "./components/Posts"
2+
3+
export const revalidate = 10
4+
5+
export default function Home() {
6+
return (
7+
<main className="px-6 mx-auto">
8+
<p className="mt-12 mb-12 text-3xl text-center dark:text-white">
9+
Hello and Welcome 👋&nbsp;
10+
<span className="whitespace-nowrap">
11+
I&apos;m <span className="font-bold">Dave</span>.
12+
</span>
13+
</p>
14+
<Posts />
15+
</main>
16+
)
17+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default function NotFound() {
2+
return (
3+
<h1>The requested post does not exist.</h1>
4+
)
5+
}

next10/app/posts/[postId]/page.tsx

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import getFormattedDate from "@/lib/getFormattedDate"
2+
import { getSortedPostsData, getPostData } from "@/lib/posts"
3+
import { notFound } from "next/navigation"
4+
import Link from "next/link"
5+
6+
export function generateStaticParams() {
7+
const posts = getSortedPostsData() //deduped!
8+
9+
return posts.map((post) => ({
10+
postId: post.id
11+
}))
12+
}
13+
14+
export function generateMetadata({ params }: { params: { postId: string } }) {
15+
16+
const posts = getSortedPostsData() //deduped!
17+
const { postId } = params
18+
19+
const post = posts.find(post => post.id === postId)
20+
21+
if (!post) {
22+
return {
23+
title: 'Post Not Found'
24+
}
25+
}
26+
27+
return {
28+
title: post.title,
29+
}
30+
}
31+
32+
export default async function Post({ params }: { params: { postId: string } }) {
33+
34+
const posts = getSortedPostsData() //deduped!
35+
const { postId } = params
36+
37+
if (!posts.find(post => post.id === postId)) {
38+
return notFound()
39+
}
40+
41+
const { title, date, contentHtml } = await getPostData(postId)
42+
43+
const pubDate = getFormattedDate(date)
44+
45+
return (
46+
<main className="px-6 prose prose-xl prose-slate dark:prose-invert mx-auto">
47+
<h1 className="text-3xl mt-4 mb-0">{title}</h1>
48+
<p className="mt-0">
49+
{pubDate}
50+
</p>
51+
<article>
52+
<section dangerouslySetInnerHTML={{ __html: contentHtml }} />
53+
<p>
54+
<Link href="/">← Back to home</Link>
55+
</p>
56+
</article>
57+
</main>
58+
)
59+
}

next10/blogposts/new.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
title: 'My New Post'
3+
date: '2023-04-19'
4+
---
5+
6+
We recommend using **Static Generation** (with and without data) whenever possible because your page can be built once and served by CDN, which makes it much faster than having a server render the page on every request.
7+
8+
You can use Static Generation for many types of pages, including:
9+
10+
- Marketing pages
11+
- Blog posts
12+
- E-commerce product listings
13+
- Help and documentation
14+
15+
You should ask yourself: "Can I pre-render this page **ahead** of a user's request?" If the answer is yes, then you should choose Static Generation.
16+
17+
On the other hand, Static Generation is **not** a good idea if you cannot pre-render a page ahead of a user's request. Maybe your page shows frequently updated data, and the page content changes on every request.
18+
19+
In that case, you can use **Server-Side Rendering**. It will be slower, but the pre-rendered page will always be up-to-date. Or you can skip pre-rendering and use client-side JavaScript to populate data.

next10/blogposts/pre-rendering.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
title: 'Two Forms of Pre-rendering'
3+
date: '2023-03-14'
4+
---
5+
6+
Next.js has two forms of pre-rendering: **Static Generation** and **Server-side Rendering**. The difference is in **when** it generates the HTML for a page.
7+
8+
- **Static Generation** is the pre-rendering method that generates the HTML at **build time**. The pre-rendered HTML is then _reused_ on each request.
9+
- **Server-side Rendering** is the pre-rendering method that generates the HTML on **each request**.
10+
11+
Importantly, Next.js lets you **choose** which pre-rendering form to use for each page. You can create a "hybrid" Next.js app by using Static Generation for most pages and using Server-side Rendering for others.

next10/blogposts/ssg-ssr.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
title: 'When to Use Static Generation vs. Server-side Rendering'
3+
date: '2023-03-17'
4+
---
5+
6+
We recommend using **Static Generation** (with and without data) whenever possible because your page can be built once and served by CDN, which makes it much faster than having a server render the page on every request.
7+
8+
You can use Static Generation for many types of pages, including:
9+
10+
- Marketing pages
11+
- Blog posts
12+
- E-commerce product listings
13+
- Help and documentation
14+
15+
You should ask yourself: "Can I pre-render this page **ahead** of a user's request?" If the answer is yes, then you should choose Static Generation.
16+
17+
On the other hand, Static Generation is **not** a good idea if you cannot pre-render a page ahead of a user's request. Maybe your page shows frequently updated data, and the page content changes on every request.
18+
19+
In that case, you can use **Server-Side Rendering**. It will be slower, but the pre-rendered page will always be up-to-date. Or you can skip pre-rendering and use client-side JavaScript to populate data.

next10/lib/getFormattedDate.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function getFormattedDate(dateString: string): string {
2+
return new Intl.DateTimeFormat('en-US', { dateStyle: 'long' }).format(new Date(dateString))
3+
}

0 commit comments

Comments
 (0)