Next.js ์์ ์ ๋ณต
Next.js ํ๋ ์์ํฌ ๊ตฌ์กฐ
Pages: url๊ณผ ๋งค์นญ๋๋ ๊ฒ๋ค
Date Fetching
- SSR: ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง์ผ๋ก,
getServerSidePropsํจ์๋ฅผ ํ์ฉํด ๋ง๋ค ์ ์๋ค. ์๋ฒ์
์์ฒญ์ด ์๊ธธ ๋๋ง๋ค ์ธ๋ถ ๋ฐ์ดํฐ๋ฅผ ์กฐํํด์ ๋ณด์ฌ์ค ์ ์๋ค.
- CSR: ํด๋ผ์ด์ธํธ ์ฌ์ด๋ ๋ ๋๋ง์ผ๋ก, ์ผ๋ฐ React๋ฅผ ์ฌ์ฉํ๋ ๊ฒ๊ณผ ๊ฐ๋ค.
- SSG: ์ ์ ์ฌ์ดํธ ์ ๋๋ ์ด์
, ๋น๋ ํ์ ๋ ๋ฏธ๋ฆฌ ํ์ํ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ํ๋ฉด์ ๊ทธ๋ ค๋๋๋ค.
yarn dev๋ก ์คํํ ํ๊ฒฝ์์๋
SSR๊ณผ ๋์ผํ๊ฒ ๋์ํ๊ณ ๋น๋ ํ ์คํํ์ ๋ ์๊ธฐ๋ฅ์ ํ์ธํ ์ ์๋ค. ๋น๋ ์ ๊ฐ์ ธ์จ ๋ฐ์ดํฐ๋ก ๊ทธ๋ ค์ฃผ๊ธฐ ๋๋ฌธ์ ์๋ฌด๋ฆฌ ์๋ก๊ณ ์นจ์ ํด๋ ๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋๊ฑฐ๋ ๋ฆฌํจ์น ๋์ง ์๋๋ค.
- ISR:
getStaticProps์์์ ๋์ํ๋๊ฑฐ์ง๋ง ํน์ ์ฃผ๊ธฐ๋ฅผ ์ง์ ํด์ฃผ๋ฉด ๊ทธ ์ฃผ๊ธฐ๋ง๋ค ๋ฆฌ์ ๋๋ ์ด์ ํ์ฌ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฐ์ดํธํ ์ ์๋ค.
SSR์ ๋งค๋ฒ ์๋ฒ๋ก ํธ์ถํ๊ธฐ ๋๋ฌธ์ ์๋ฒ ๋ถํ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์์ด SSG + ISR์ ๋์์ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํ๋ค.
SSR VS SSG
SSR์ ๋งค๋ฒ ์๋ฒ์ ์์ฒญ์ด ์ด๋ฃจ์ด์ง๋ฏ๋ก ์๋ฒ ๋ถํ๊ฐ ์ฌ ์ ์๋ค. ๋ฐ๋ผ์ ๋น๋ ์ ํ์ผ์ ์์ฑํ๋ SSG๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ฑ๋ฅ ์ธก๋ฉด์์ ๋ ์ข์๋ฐ ๋๊ฐ์ง ์ค ๊ฒฐ์ ํ๋ ๊ฐ์ฅ ํฐ ์์ธ์ ์ฌ์ฉ์์ ์์ฒญ ์์ด ๋ถ๋ฌ์ฌ ์ ์๋ ๋ฐ์ดํฐ์ธ๊ฐ. ํ๋จํ๋ ๊ฒ์ด๋ค. ๋ง์ฝ ์ฌ์ฉ์ ์์ฒญ ์์ด ๋ถ๋ฌ์ฌ ์ ์๋ ๋ฐ์ดํฐ๋ผ๋ฉด ๋น๋ ํ์ ๋ ์์ฑํ๋ SSG ์ฌ์ฉ์ ๊ถ์ฅํ๊ณ , ๊ทธ๋ ์ง ์๋ค๋ฉด SSR์ ์ฌ์ฉํด์ผ ํ๋ค.
Layout
pages/_app.js๋ฅผ ํ์ฉํด์ ํ์ด์ง์ ๊ณตํต์ ์ผ๋ก ๋ณด์ฌ์ง๋ ๋ ์ด์์๋ค์ ์ค์ ํ ์ ์๋ค. ๋ฉ์ธ Layout๊ณผ ๋ณ๊ฐ๋ก SubLayout๋ ๋ง๋ค์ด
GetLayout ํจ์๋ฅผ ํตํด ๋ ์ด์์์ ์ง์ ํด์ค ์ ์๋ค.
Routing
React๋ ๋ณ๋๋ก react-router ํจํค์ง๋ฅผ ์ค์นํด์ฃผ์ด์ผ ํ์ง๋ง Next.js๋ file-system ๊ธฐ๋ฐ์ ๋ผ์ฐํฐ๋ฅผ ์ ๊ณตํ๋ค.
/src/pages ๋๋ /pages ๋๋ ํ ๋ฆฌ ๋ด๋ถ์ ๋ผ์ฐํฐ๋ฅผ ์ง์ ํด์ฃผ๋ฉด ๋๋ค.
/src/pages์/pages๊ฐ ๋ชจ๋ ์กด์ฌํ๋ค๋ฉด/pages๊ฐ ์ฐ์ ์์๊ฐ ๋๋ค.[id],[id].js์ ๊ฐ์ ํํ๋ก ์์ผ๋ ์นด๋๋ฅผ ์ง์ ํ ์ ์๋ค. ํ์ผ ๋ฟ๋ง ์๋๋ผ ๋๋ ํ ๋ฆฌ๋ช ์ผ๋ก๋ ์ค์ ๊ฐ๋ฅ.- Slug - ๋ค์ํ ์๊ณ์ Dynamic Paths ์
[...id].jsํํ์ ํ์ผ์ ์์ผ๋ ์นด๋๋ฅผ ์ฌ๋ฌ ๋์ค๋ก ์ ๋ ฅํ ์ ์๋ค.e.g. //localhost:3000/1/2/3[[id]].jsํํ๋ ์์ผ๋ ์นด๋๋ฅผ ๊ตณ์ด ์ ๋ ฅํ์ง ์์๋ ๊ธฐ๋ณธ ํ์ด์ง๋ก ๋ก๋ฉ๋๋ค.e.g. //localhost:3000- router๋ฅผ ๋ณ๊ฒฝํ๋ ์ธ๊ฐ์ง ๋ฐฉ๋ฒ
location.replace("url")- ๋ก์ปฌ state๊ฐ ์ ์ง๋์ง ์์ (๋ฆฌ๋ ๋๋ง)router.push(url)- ๋ก์ปฌ state ์ ์ง / data fetching ์๋ก ์ผ์ด๋จrouter.push(url, as, { shallow: true })- ๋ก์ปฌ state ์ ์ง / data fetching ์ผ์ด๋์ง ์์
- SSG๋ก ์์ฑํ ๋ชฉ๋ก์
getStaticPathsํ ์ ํตํด ๊ฐ์ ธ์จ๋ค. getStaticPaths์fallback์ญํ ์ ๋น๋ ํ์ ๋ ์์ฑ๋์ง ์์ page์ ๋ํ ์ฒ๋ฆฌ๋ฅผ ์ ํ๋ค.blocking: ์๊ทธ๋ฆฌ๊ณ ์๋ค๊ฐ ๋ฐ์ดํฐ๊ฐ ์์๋ ๊ธฐ๋ค๋ ธ๋ค๊ฐ ์คํfalse: ์ฒ๋ฆฌํ์ง ์๊ณ 404true: fallback ๋์์ผ๋ก ๋ก๋ ๋ฑ์ ๋ณด์ฌ์คฌ๋ค๊ฐ ์คํ
Shallow Routing
- Dynamic Routes: Slug๋ฅผ ์ฌ์ฉํด ๊ตฌํ
- ๋ค์ค slug: [user]/[info].js / [โฆslug].js
- ์ต์ ๋ slug: [[โฆslug]].js
- Shallow Routing: router.push(url, undefined, { shallow: true })
API Routes
- API Routes๋ Routing๊ณผ ๋์ผํ๊ฒ ํ์ผ๊ธฐ๋ฐ์ด๊ณ ๋ค์ด๋๋ฏน ํจ์ค๋ฅผ ์ฌ์ฉํ ์ ์๋ค. (์์ผ๋์นด๋)
- Response
- res.status(code) - API ์๋ต ๊ฒฐ๊ณผ๋ฅผ ์ฝ๋๋ก ๋ฆฌํดํ ์ ์๋ค.
- res.json(body) - ์๋ต ๊ฒฐ๊ณผ๋ก ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค.
- res.redirect(code, url) - ์๋ต ๊ฒฐ๊ณผ์ ๋ํ ์ฝ๋๋ฅผ ์ฒซ ๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก ์ฃผ๊ณ , ๋๋ฒ์งธ ํ๋ผ๋ฏธํฐ๋ก ๋ค์์ผ๋ก ํธ์ถํ API ์ฃผ์๋ฅผ ์ ๋ ฅํ ์ ์๋ค.
- res.send(body) -
json()๊ณผ ์ ์ฌํ์ง๋ง string/object/Buffer ๋ฑ ๋ค์ํ ํํ์ ๊ฐ์ ๋ฆฌํดํ ์ ์๋ค.
์กฐ๊ธ ๋ ์ฌํ ๋ด์ฉ
Next.js๋ Rust๋ก ๋ง๋ค์ด์ง SWC ์ปดํ์ผ๋ฌ๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค. SWC ์ปดํ์ผ๋ฌ๋ javascript ์ฝ๋๋ฅผ transformํ๊ณ minifyํ๋ ์ญํ ์ ํ๋ค. ํธ๋์คํ์ผ๋ฌ๋ฅผ ํ๋ Babel๊ณผ minify์ Terser๋ฅผ ๋์ฒดํ๊ณ ์๋ค.
๋ฐ๋ฒจ์ด๋?
๋ฐ๋ฒจ์ ํธ๋์คํ์ผ๋ฌ๋ก ์๋ฐ์คํฌ๋ฆฝํธ ์ต์ ๋ฌธ๋ฒ์ ๊ตฌ ๋ฒ์ ๋ธ๋ผ์ฐ์ ์์๋ ๋์ํ ์ ์๋๋ก ์นํํด์ฃผ๋ ์ญํ
Preview Mode
getStaticProps๋ ๋น๋ ํ์์ ์คํ๋๋ ํ
์ด์ง๋ง Preview Mode๋ก ๋ ๊ฐ์ง ์ฟ ํค๊ฐ ์์ฑ๋๋ค๋ฉด Request time์๋
getStaticProps ํ
์ ์คํํ ์ ์๋ค.
Dynamic Import
React.lazy ๊ธฐ๋ฅ์ ํ์ฅํ์ฌ Next.js์์ ์ปดํฌ๋ํธ๋ฅผ Lazy loadํ๋ ๋ฐฉ๋ฒ์ด๋ค.
// good
import Button from 'components/Button';
// better
import dynamic from 'next/dynamic';
const Button = dynamic(() => { import('components/Button') }, {
loading: () => <div>Loading...</div>
})Automatic Static Optimization
์๋์ ์ผ๋ก ์ ์ ์ธ ๊ฒ์ ์ต์ ํ๋ฅผ ์งํํ๋ ๊ธฐ๋ฅ, ์ ์ ํ์ด์ง๋ .html ํ์ผ๋ก ์์ฑํ๊ณ ์์ฒญ์ ๋ง์ถฐ ๋์ํ๋ ํ์ด์ง๋ .js ํ์ผ๋ก ๋น๋ํ๋ค.
getInitialProps๋ getServerSideProps๊ฐ ์๋ค๋ฉด .jsํ์ผ๋ก ๋น๋
Router์ query๊ฐ
Router์ query ๊ฐ์ CSR์ ๊ฒฝ์ฐ ์ด๊ธฐ์ undefined์ผ ์ ์๋ค. ์๋ฒ ์ฌ์ด๋ ๋ ๋๋ง์ ์ฌ์ฉํ ๊ฒฝ์ฐ hydration ์ดํ
์ค์ ์
๋ ฅ๋ query ๊ฐ๋ง ์ฌ์ฉํ ์ ์๋ค.
Static HTML Export
next export ๋ช
๋ น์ด๋ฅผ ํตํด ์๋์ ์ผ๋ก ์ ์ ํ์ผ๋ก export ํ ์ ์๋ค. ์ด ๊ธฐ๋ฅ์ ์ฌ์ฉํ ๊ฒฝ์ฐ Next.js์์ ์ ๊ณตํ๋
๊ธฐ๋ฅ ์ค Node ์๋ฒ๊ฐ ์์ด์ผ๋ง ํ๋ ๊ฒ๋ค(Image, API Routes)์ ์ฌ์ฉํ์ง ๋ชปํ๋ค.
Custom App
- Persisting layout between page changes
- ํ์ด์ง ๋ณ๊ฒฝ ์์๋ ๊ณ ์ ๋ ๋ ์ด์์์ ์ฌ์ฉํ ๋
- Keeping state when navigating pages
- ํ์ด์ง๊ฐ navigate ๋์ด๋ ์ ์งํ๊ณ ์ถ์ ์ํ๊ฐ ์์ ๋
- Inject additional data into pages
- ํ์ด์ง์ ์ถ๊ฐ์ ์ธ ๋ฐ์ดํฐ๋ฅผ ์ฃผ์ ํ๊ณ ์ถ์ ๋
- [Add global CSS](https://nextjs.org/docs/basic-features/built-in-css-support#adding-a-global-stylesheet
์น ์ฑ๋ฅ ์ธก์ (Web Vitals)
- Largest Contentful Paint(์ต๋ ์ฝํ ์ธ ํ ํ์ธํธ, LCP): ๋ก๋ฉ ์ฑ๋ฅ ์ธก์ , ์ฌ์ฉ์๊ฐ ์๋ฏธ์๋ ์ฝํ ์ธ ๋ฅผ ๋ณผ ๋๊น์ง ์ผ๋ง๋งํผ์ ์๊ฐ์ด ๊ฑธ๋ฆฌ๋๊ฐ, ์ฐ์ํ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ๋ ค๋ฉด 2.5์ด ์ด๋ด์ LCP๊ฐ ๋ฐ์ํด์ผ ํ๋ค. (์ ์์๋ก ์ข์)
- First Input Delay(์ต์ด ์ ๋ ฅ ์ง์ฐ, FID): ์ํธ์์ฉ ์ธก์ , ์ฐ์ํ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ๋ ค๋ฉด ํ์ด์ง ๋น 100๋ฐ๋ฆฌ์ด ์ดํ (์ ์์๋ก ์ข์)
- Cumulative Layout Shift(๋์ ๋ ์ด์์ ์ํํธ, CLS): ์๊ฐ์ ์์ ์ฑ ์ธก์ , ์ฐ์ํ ์ฌ์ฉ์ ๊ฒฝํ์ ์ ๊ณตํ๋ ค๋ฉด ํ์ด์ง์์ 0.1 ์ดํ ์ ์ง (์ ์์๋ก ์ข์)
- (์ถ๊ฐ) Total Block Time(์ด ์ฐจ๋จ ์๊ฐ, TBT): ์ฌ์ฉ์๊ฐ ์ธํฐ๋์ ํ๊ธฐ ๊น์ง ๋ธ๋ญํ์์ด ์ด๋์ ๋ ๋ฐ์ํ๋์ง ์ธก์