๐Ÿก ์ˆ™๋ฐ• ์˜ˆ์•ฝ ํ”Œ๋žซํผ: Next.js 13 ํ”„๋กœ์ ํŠธ ์„ค๊ณ„ ๋ฐ ํ™˜๊ฒฝ ๊ตฌ์„ฑ (1)

ฮต( ฮต ห™ยณห™)ะท โ—‹ยบยท2025๋…„ 7์›” 13์ผ
0
post-thumbnail

๋ณธ ๊ธ€์€ ํŒจ์ŠคํŠธ์บ ํผ์Šค โ€“ Next.js ์‹ค๋ฌด ๊ฐ•์˜ ์ค‘ Part 8. Next.js 13์œผ๋กœ ์ˆ™๋ฐ• ์˜ˆ์•ฝ ํ”Œ๋žซํผ ๋งŒ๋“ค๊ธฐ๋ฅผ ์ˆ˜๊ฐ•ํ•˜๋ฉฐ ํ•™์Šตํ•œ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๐Ÿ™๐Ÿป


๐Ÿ  ํ”„๋กœ์ ํŠธ ๊ฐœ์š”

์ˆ™๋ฐ• ์˜ˆ์•ฝ ํ”Œ๋žซํผ์„ ์ง์ ‘ ๊ตฌ์ถ•ํ•˜๋ฉฐ Next.js 13์˜ App Router ๊ธฐ๋ฐ˜ ๊ตฌ์กฐ,SSR/ISR/CSR ๋“ฑ ๋‹ค์–‘ํ•œ ๋ Œ๋”๋ง ๋ฐฉ์‹, React Query, Prisma, Supabase ๋“ฑ์˜ ๊ธฐ์ˆ ์„ ์‹ค๋ฌด ํ๋ฆ„์— ๋งž๊ฒŒ ์ ์šฉํ•˜๋Š” ๊ฒƒ์„ ๋ชฉํ‘œ๋กœ ํ•œ๋‹ค.


๐Ÿ“‹ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์š”๊ตฌ์‚ฌํ•ญ ๋ถ„์„

โ–ช๏ธ ์š”๊ตฌ์‚ฌํ•ญ ๋ถ„์„

์‚ฌ์šฉ์ž ๊ด€์ ์—์„œ ํ”Œ๋žซํผ์ด ์ œ๊ณตํ•ด์•ผํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ •์˜ํ•˜๊ณ , ๊ธฐ์ˆ ์ ์œผ๋กœ ์–ด๋–ค ์„ฑ๋Šฅ ๊ธฐ์ค€๊ณผ ์ „๋žต์ด ํ•„์š”ํ•œ์ง€๋ฅผ ๋„์ถœํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ฃผ์š” ๊ธฐ๋Šฅ ์š”๊ตฌ์‚ฌํ•ญ

  • ๋ฉ”์ธ ํŽ˜์ด์ง€: ์ „์ฒด ์ˆ™์†Œ ๋ฆฌ์ŠคํŠธ ๋…ธ์ถœ, ๋ฌดํ•œ ์Šคํฌ๋กค, ํ•„ํ„ฐ๋ง ๊ธฐ๋Šฅ
  • ์ƒ์„ธ ํŽ˜์ด์ง€: ์ˆ™์†Œ ์ƒ์„ธ ์ •๋ณด, ๋ฉ”์ธ ํ•„ํ„ฐ ์œ ์ง€
  • ์ง€๋„ ํŽ˜์ด์ง€: ์นด์นด์˜ค ์ง€๋„ ์—ฐ๋™, ๋งˆ์ปค ๊ธฐ๋ฐ˜ ์ˆ™์†Œ ํ‘œ์‹œ
  • ์ธ์ฆ: SNS ๊ฐ„ํŽธ ๋กœ๊ทธ์ธ, ์ ‘๊ทผ ๊ถŒํ•œ ์ œ์–ด
  • ์˜ˆ์•ฝ/๊ฒฐ์ œ: ์ˆ™์†Œ ์˜ˆ์•ฝ/์ทจ์†Œ, ํ† ์ŠคํŽ˜์ด๋จผ์ธ  ๊ฒฐ์ œ ์—ฐ๋™
  • ๊ฒ€์ƒ‰: ์ˆ™์†Œ ๋“ฑ๋ก/์กฐํšŒ ์‹œ ๊ฒ€์ƒ‰ ๋ฐ ํ•„ํ„ฐ ๊ธฐ๋Šฅ ์ œ๊ณต

์„ฑ๋Šฅ ๋ฐ ๋น„์ฆˆ๋‹ˆ์Šค ์š”๊ตฌ์‚ฌํ•ญ

  • ๋ Œ๋”๋ง ์„ฑ๋Šฅ ๋ถ„์„: Lighthouse ๊ธฐ์ค€ ๋ถ„์„, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํฌ๊ธฐ ํ™•์ธ (@next/bundle-analyzer)
  • ํŽ˜์ด์ง€ ๋ Œ๋”๋ง ์ตœ์ ํ™”: SSR/CSR/ISR ์ „๋žต ์ˆ˜๋ฆฝ
  • ํ…Œ์ŠคํŠธ: Cypress๋ฅผ ํ™œ์šฉํ•œ E2E ํ…Œ์ŠคํŠธ ์ž‘์„ฑ
  • ์‚ฌ์šฉ์ž ํ–‰๋™ ๋ถ„์„: Google Analytics, SEO ์ตœ์ ํ™” ๋„๊ตฌ ํ™œ์šฉ

โ–ช๏ธ ์š”๊ตฌ์‚ฌํ•ญ์— ๋”ฐ๋ฅธ ์„ธ๋ถ€ ๊ธฐ๋Šฅ ์„ค๊ณ„

๊ธฐ๋Šฅ, ์„ฑ๋Šฅ ๋ฐ ๋น„์ฆˆ๋‹ˆ์Šค ์š”๊ตฌ์‚ฌํ•ญ์„ ์‚ฌ์šฉ์ž ์ค‘์‹ฌ์˜ ์Šคํ† ๋ฆฌ๋กœ ์žฌ๊ตฌ์„ฑํ•˜๊ณ , ๊ฐ ์š”๊ตฌ์— ๋งž๋Š” ๊ธฐ์ˆ ์  ๋Œ€์‘ ๋ฐฉ์‹์„ ์„ค๊ณ„๋ฅผ ํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์œ ์ € ์Šคํ† ๋ฆฌ๊ธฐ๋Šฅ ์„ค๊ณ„
์‚ฌ์šฉ์ž๊ฐ€ ์Šคํฌ๋กค์„ ๋‚ด๋ฆด ๋•Œ ์ˆ™์†Œ๊ฐ€ ์ถ”๊ฐ€๋กœ ๋กœ๋“œ๋œ๋‹คReact Query useInfiniteQuery ํ™œ์šฉํ•œ ๋ฌดํ•œ ์Šคํฌ๋กค (CSR ๊ธฐ๋ฐ˜)
ํŽ˜์ด์ง€ ๋ Œ๋”๋ง์ด ๋น ๋ฅด๊ณ  ๊ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํฌ๊ธฐ๊ฐ€ ์ ๋‹นํ•œ์ง€ ๋ถ„์„ํ•œ๋‹ค.Lighthouse์˜ ์‚ฌ์šฉ์ž ๊ธฐ์ค€์˜ ์„ฑ๋Šฅ ์ธก์ • ๊ธฐ์ค€์„ ๋”ฐ๋ผ ์„ฑ๋Šฅ ์ธก์ •, @next/bundle-analyzer๋กœ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํฌ๊ธฐ๋ฅผ ๋ถ„์„
์ƒ์„ธ ํŽ˜์ด์ง€ ์ง„์ž… ์‹œ ์ด์ „ ํ•„ํ„ฐ๊ฐ€ ์œ ์ง€๋œ๋‹ค.Recoil์„ ํ™œ์šฉํ•œ ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ์ตœ์ ํ™”
Next.js13์˜ ๋‹ค์–‘ํ•œ ์„ฑ๋Šฅ ๊ฐœ์„  ๋ฐฉ๋ฒ•์„ ์ด์šฉํ•ด์„œ ๊ฐ ํŽ˜์ด์ง€๋ณ„ ๋ Œ๋”๋ง ๋ฐฉ์‹์„ ์ตœ์ ํ™”ํ•œ๋‹ค.CSR, ISR, SSR, SSG ๋“ฑ ๊ฐ ๋ Œ๋”๋ง ๋ฐฉ์‹์˜ ํŠน์ง•์„ ์•Œ์•„๋ณด๊ณ , ํŽ˜์ด์ง€๋ณ„๋กœ ๊ฐ€์žฅ ์ตœ์ ํ™”๋œ ๋ Œ๋”๋ง ๋ฐฉ์‹์„ ์ ์šฉ
์˜ˆ์•ฝ ๋ฐ ๊ฒฐ์ œ๋Š” ๋งค ์š”์ฒญ๋งˆ๋‹ค ์ •ํ™•ํ•œ ์ •๋ณด๊ฐ€ ํ•„์š”ํ•˜๋‹คSSR์„ ํ†ตํ•ด ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ๋ฐ˜์˜

๐Ÿ› ๏ธ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž์ถฐ ์•„ํ‚คํ…์ฒ˜ ์„ค๊ณ„ํ•˜๊ธฐ

โ–ช๏ธ ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜ ํ๋ฆ„๋„

  • ์ถœ์ฒ˜: ๊ฐ•์˜ ์ž๋ฃŒ

ํ•ด๋‹น ๋‹ค์ด์–ด๊ทธ๋žจ์€ ์ˆ™๋ฐ• ์˜ˆ์•ฝ ์„œ๋น„์Šค์˜ ์ „๋ฐ˜์ ์ธ ์‚ฌ์šฉ์ž ํ–‰๋™ ํ๋ฆ„์— ๋”ฐ๋ผ ์‹œ์Šคํ…œ์ด ์–ด๋–ป๊ฒŒ ๋ฐ˜์‘ํ•˜๋Š”์ง€๋ฅผ ์‹œ๊ฐํ™”ํ•œ ๊ฒƒ์ด๋‹ค.์‚ฌ์šฉ์ž์˜ ์•ก์…˜(๋กœ๊ทธ์ธ, ์ˆ™์†Œ ์„ ํƒ, ๊ฒฐ์ œ ๋“ฑ)์— ๋”ฐ๋ผ ์–ด๋–ค ํŽ˜์ด์ง€๊ฐ€ ๋ Œ๋”๋ง๋˜๊ณ  ์–ด๋–ค ๊ธฐ๋Šฅ(API ํ˜ธ์ถœ, ์ธ์ฆ ์ฒ˜๋ฆฌ ๋“ฑ)์ด ์ˆ˜ํ–‰๋˜๋Š”์ง€๋ฅผ ํ”Œ๋กœ์šฐ ์ฐจํŠธ ํ˜•ํƒœ๋กœ ํ•œ๋ˆˆ์— ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿง ์š”๊ตฌ์‚ฌํ•ญ ๋ถ„์„ ๋‹จ๊ณ„์—์„œ ์‚ฌ์šฉ์ž ํ๋ฆ„์„ ์‹œ๊ฐ์ ์œผ๋กœ ์ •๋ฆฌํ•ด๋‘๋ฉด ๊ธฐ๋Šฅ๋ณ„ ํ™”๋ฉด ๊ตฌ์„ฑ๊ณผ ํŽ˜์ด์ง€ ๊ฐ„ ์—ญํ• ์„ ๋ช…ํ™•ํžˆ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๊ณ , ๋ Œ๋”๋ง ๋ฐฉ์‹์ด๋‚˜ ์ƒํƒœ ๊ด€๋ฆฌ ์ „๋žต์„ ์„ค๊ณ„ํ•˜๋Š” ๋ฐ ๊ธฐ์ค€์ด ๋  ์ˆ˜ ์žˆ์„ ๊ฑฐ ๊ฐ™๋‹ค


โ–ช๏ธ ํ”„๋กœ์ ํŠธ ์„ค๊ณ„ (ํด๋” ๊ตฌ์กฐ)

app/
  (home)/                 // ํ™ˆ ํŽ˜์ด์ง€ ๋ผ์šฐํŠธ ๊ทธ๋ฃน
  api/                    // Route Handlers (Next.js 13 API ์—”๋“œํฌ์ธํŠธ)
  layout.tsx             // ๊ณตํ†ต ๋ ˆ์ด์•„์›ƒ
  global-error.tsx       // ์ „์ฒด ์—๋Ÿฌ ์ฒ˜๋ฆฌ
  not-found.tsx          // 404 ํŽ˜์ด์ง€
  providers.tsx          // ์ „์—ญ Provider ์„ค์ •
components/              // ๊ณตํ†ต UI ์ปดํฌ๋„ŒํŠธ
hooks/                   // ์ปค์Šคํ…€ ํ›… (ex. useIntersectionObserver)
interface/               // TypeScript ํƒ€์ž…/์ธํ„ฐํŽ˜์ด์Šค ์ •์˜
constants/               // ์ƒ์ˆ˜
atom/                    // Recoil ์ƒํƒœ ๊ด€๋ฆฌ
utils/                   // ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜
db/                      // Prisma ํด๋ผ์ด์–ธํŠธ ์ •์˜

โ–ช๏ธ ์‚ฌ์šฉ ๊ธฐ์ˆ  ์ •๋ฆฌ

  • ํ”„๋กœ์ ํŠธ ์„ธํŒ… ๋ฐ ๊ฐœ๋ฐœ: Next.js 13, React, ESLint, Prettier, Supabase, Prisma, TailwindCSS, react-calendar, recoil, React Query, Next-auth, react-hook-form, firebase storage
  • ๋„๋ฉ”์ธ ์„ค์ • ๋ฐ ๋ฐฐํฌ: Godaddy, Vercel
  • ์„ฑ๋Šฅ ์ธก์ • ๋ฐ ๋ถ„์„: Lighthouse, @next/bundle-analyzer, Google Analytics, Google Search Console, Naver Search Advisor
  • ํ…Œ์ŠคํŠธ ์ฝ”๋“œ ๋ฐ ๋””์ž์ธ ์‹œ์Šคํ…œ: Cypress, Storybook

โ–ช๏ธ ํŽ˜์ด์ง€ ๋ณ„ ๋ Œ๋”๋ง ๋ฉ”์„œ๋“œ ์„ค๊ณ„

๊ฐ ํŽ˜์ด์ง€์˜ ๊ธฐ๋Šฅ, ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์ฃผ๊ธฐ, SEO ์š”๊ตฌ์‚ฌํ•ญ ๋“ฑ์— ๋”ฐ๋ผ ๊ฐ€์žฅ ์ ํ•ฉํ•œ ๋ Œ๋”๋ง ๋ฐฉ์‹์„ ์„ ํƒํ•ด ์ ์šฉํ•œ๋‹ค. Next.js 13์—์„œ๋Š” SSG, SSR, ISR, CSR์„ ํ˜ผํ•ฉ์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ํŽ˜์ด์ง€์˜ ๋ชฉ์ ๊ณผ ๋ฐ์ดํ„ฐ์˜ ํŠน์„ฑ์„ ๊ณ ๋ คํ•œ ์ „๋žต์ ์ธ ๋ Œ๋”๋ง ๋ฐฉ์‹ ๊ตฌ์„ฑ์ด ์„ฑ๋Šฅ๊ณผ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์— ์˜ํ–ฅ์„ ์ค€๋‹ค.

  • SSG (Static Site Generation)
    ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ๋นˆ๋„๊ฐ€ ๋‚ฎ๊ณ , ๋น ๋ฅธ ์ดˆ๊ธฐ ๋กœ๋”ฉ ๋ฐ SEO๊ฐ€ ์ค‘์š”ํ•œ ํŽ˜์ด์ง€์— ์‚ฌ์šฉ (ex. ์ž์ฃผ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š๋Š” ์ •์  ์ฝ˜ํ…์ธ ์ธ FAQ ํŽ˜์ด์ง€)
  • SSR (Server-Side Rendering)
    ํŽ˜์ด์ง€ ์ ‘๊ทผ ์‹œ๋งˆ๋‹ค ์ตœ์‹  ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์‚ฌ์šฉ. ์„œ๋ฒ„์—์„œ HTML์„ ๋™์ ์œผ๋กœ ๋ Œ๋”๋ง
    (ex. ์˜ˆ์•ฝ ํ”„๋กœ์„ธ์Šค์™€ ๊ฐ™์ด ์‚ฌ์šฉ์ž ์ž…๋ ฅ์— ๋”ฐ๋ผ ๋ฐ์ดํ„ฐ๊ฐ€ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋ณ€๊ฒฝ๋˜๋Š” ์ˆ™๋ฐ• ์˜ˆ์•ฝํ•˜๊ธฐ ํŽ˜์ด์ง€)
  • ISR (Incremental Static Regeneration)
    ์ •์  ํŽ˜์ด์ง€ ๊ธฐ๋ฐ˜์ด์ง€๋งŒ, ์ผ์ • ๊ฐ„๊ฒฉ์œผ๋กœ ์ž๋™ ์—…๋ฐ์ดํŠธ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ ํ•ฉ (ex. ์ˆ™์†Œ ์ƒ์„ธ ํŽ˜์ด์ง€์ฒ˜๋Ÿผ ๋ณ€๊ฒฝ์€ ๋“œ๋ฌผ์ง€๋งŒ ์—…๋ฐ์ดํŠธ๊ฐ€ ํ•„์š”ํ•œ ์ฝ˜ํ…์ธ )
  • CSR (Client-Side Rendering)
    ํด๋ผ์ด์–ธํŠธ์—์„œ JavaScript๋กœ ํŽ˜์ด์ง€๋ฅผ ๋™์ ์œผ๋กœ ๋ Œ๋”๋ง. ์ดˆ๊ธฐ ๋กœ๋”ฉ ์ดํ›„ ์‚ฌ์šฉ์ž ์ƒํ˜ธ์ž‘์šฉ ์ค‘์‹ฌ์˜ ํŽ˜์ด์ง€์— ์ ํ•ฉ (ex. ๊ฒฐ์ œ ํŽ˜์ด์ง€, ๋ฌดํ•œ ์Šคํฌ๋กค์ด ์ ์šฉ๋œ ๋ฆฌ์ŠคํŠธ, ๋กœ๊ทธ์ธ ๊ธฐ๋ฐ˜ ๋งˆ์ดํŽ˜์ด์ง€ ๋“ฑ)

โ–ช๏ธ ์š”๊ตฌ์‚ฌํ•ญ์— ๋งž์ถฐ API ์„ค๊ณ„ํ•˜๊ธฐ

์Šคํ‚ค๋งˆ ๋‹ค์ด์–ด๊ทธ๋žจ์„ ํ†ตํ•ด ์ฃผ์š” ๋„๋ฉ”์ธ ๋ชจ๋ธ ๊ฐ„์˜ ๊ด€๊ณ„๋ฅผ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ๋‹ค. ์‚ฌ์šฉ์ž(User)๋Š” ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ˆ™์†Œ(Room)๋ฅผ ์†Œ์œ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ฐ ์ˆ™์†Œ์—๋Š” ์ข‹์•„์š”(Like)์™€ ๋Œ“๊ธ€(Comment)์ด ์—ฐ๊ฒฐ๋œ๋‹ค. ๋Œ“๊ธ€์€ ์ž‘์„ฑ ์‹œ์ , ๋‚ด์šฉ ๋“ฑ ๊ธฐ๋Šฅ์— ๋”ฐ๋ผ ๋‹ค์–‘ํ•œ ์†์„ฑ์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„ํ•œ๋‹ค.

  • ์ถœ์ฒ˜: ๊ฐ•์˜ ์ž๋ฃŒ

๋‹ค์Œ์€ ์ˆ™์†Œ(Room)์— ๋Œ€ํ•œ CRUD ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๊ธฐ ์œ„ํ•œ API ์—”๋“œํฌ์ธํŠธ ์„ค๊ณ„์ด๋‹ค. Next.js 13์˜ Route Handler ๊ธฐ๋Šฅ์„ ํ†ตํ•ด /app/api/rooms/route.ts์— ๊ฐ ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ Prisma Client๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์™€ ์ง์ ‘ ์—ฐ๋™ํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•  ์˜ˆ์ •์ด๋‹ค.

  • ์ˆ™์†Œ ๋“ฑ๋ก POST /api/rooms
  • ์ˆ™์†Œ ๋ชฉ๋ก ์กฐํšŒ GET /api/rooms
  • ์ˆ™์†Œ ์ƒ์„ธ ์กฐํšŒ GET /api/rooms?id={id}
  • ์ˆ™์†Œ ์ˆ˜์ • PATCH /api/rooms?id={id}
  • ์ˆ™์†Œ ์‚ญ์ œ DELETE /api/rooms?id={id}

โ–ช๏ธ ์‚ฌ์šฉ ๊ธฐ์ˆ  ์•Œ์•„๋ณด๊ธฐ

์ด๋ฒˆ ํ”„๋กœ์ ํŠธ์—์„œ ์‚ฌ์šฉํ•  ๊ธฐ์ˆ ์˜ ์ฃผ์š” ํŠน์ง•์„ ์•Œ์•„ ๋ณด์ž

Next.js 13 ์ฃผ์š” ์—…๋ฐ์ดํŠธ ์‚ฌํ•ญ (2022๋…„ 10์›” 25์ผ Next.js Conf ์—์„œ Next.js 13 ๊ณต์‹ ๋ฐœํ‘œ)


  • App Router ๋„์ž… (/app ๋””๋ ‰ํ„ฐ๋ฆฌ) ๊ธฐ์กด Pages ๋ผ์šฐํŒ… ๋Œ€์‹ , ๋” ์œ ์—ฐํ•œ ๋ผ์šฐํŒ… ๊ตฌ์กฐ๋ฅผ ์ œ๊ณต (๋ ˆ์ด์•„์›ƒ ๊ด€๋ฆฌ, ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ, ์ŠคํŠธ๋ฆฌ๋ฐ UI ๊ตฌ์„ฑ ๊ฐ€๋Šฅ)
  • Route Handlers /app/api/route.ts ํŒŒ์ผ์—์„œ GET, POST ๋“ฑ ๋ฉ”์„œ๋“œ๋ฅผ ์ง์ ‘ ์ •์˜ํ•˜์—ฌ API ๋กœ์ง ๊ตฌํ˜„ ๊ฐ€๋Šฅ
  • Turbopack Rust ๊ธฐ๋ฐ˜์œผ๋กœ ๋งŒ๋“  ์ƒˆ๋กœ์šด ๋ฒˆ๋“ค๋Ÿฌ(Webpack๋ณด๋‹ค ํ›จ์”ฌ ๋น ๋ฆ„)
  • next/image ๊ฐœ์„  ๋ธŒ๋ผ์šฐ์ €์˜ lazy loading์„ ํ™œ์šฉํ•ด ์ด๋ฏธ์ง€ ๋กœ๋”ฉ ์†๋„ ํ–ฅ์ƒ
  • @next/font ๋„์ž… ํฐํŠธ๋ฅผ ์ง์ ‘ ํ˜ธ์ŠคํŒ…ํ•˜์—ฌ FOUT(๋ ˆ์ด์•„์›ƒ ๊นจ์ง) ์—†์ด ์•ˆ์ •์ ์ธ ๊ธ€๊ผด ๋กœ๋”ฉ ๊ฐ€๋Šฅ
  • next/link ๊ฐœ์„  <a> ํƒœ๊ทธ๋ฅผ ์ž๋™์œผ๋กœ ํฌํ•จ์‹œ์ผœ ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ ๋งํฌ ๊ตฌ์„ฑ ๊ฐ€๋Šฅ

์ฃผ์š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฐ ํ”Œ๋žซํผ

  • Prisma
    ํƒ€์ž… ์•ˆ์ „์„ฑ๊ณผ ์ƒ์‚ฐ์„ฑ์„ ๊ฒธ๋น„ํ•œ ํ˜„๋Œ€์ ์ธ ORM ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ ์ •์˜, ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜, ํƒ€์ž… ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ ์ƒ์„ฑ์„ ํ†ตํ•ด ์•ˆ์ •์ ์ธ ๋ฐ์ดํ„ฐ ์—ฐ๋™์„ ์ง€์›

  • TailwindCSS
    ์œ ํ‹ธ๋ฆฌํ‹ฐ ํผ์ŠคํŠธ CSS ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ํด๋ž˜์Šค ๊ธฐ๋ฐ˜์œผ๋กœ ๋น ๋ฅด๊ณ  ์ผ๊ด€๋œ ์Šคํƒ€์ผ๋ง์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ ๋ฐ˜์‘ํ˜• UI ๊ตฌํ˜„์— ์œ ๋ฆฌ

  • Reocil
    Facebook์—์„œ ๊ฐœ๋ฐœํ•œ ์ „์—ญ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ๋ณต์žกํ•œ ์ƒํƒœ๋ฅผ ํšจ์œจ์ ์œผ๋กœ ๊ตฌ์กฐํ™”ํ•˜๊ณ  ์ปดํฌ๋„ŒํŠธ ๊ฐ„ ์ƒํƒœ ๊ณต์œ ๋ฅผ ๋‹จ์ˆœํ•˜๊ฒŒ ๊ด€๋ฆฌ ๊ฐ€๋Šฅ

  • React Query (TanStack Query)
    ์„œ๋ฒ„ ์ƒํƒœ๋ฅผ ํด๋ผ์ด์–ธํŠธ์—์„œ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ฐ์ดํ„ฐ ํŽ˜์นญ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
    ์ž๋™ ์บ์‹ฑ, ๋ฆฌํŽ˜์นญ, ์—๋Ÿฌ ํ•ธ๋“ค๋ง ๋“ฑ์„ ์ œ๊ณตํ•˜์—ฌ API ํ†ต์‹  ํ๋ฆ„์„ ๊ฐ„๊ฒฐํ•˜๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ

  • Cypress
    E2E ํ…Œ์ŠคํŠธ ๋„๊ตฌ๋กœ ์‹ค์ œ ๋ธŒ๋ผ์šฐ์ € ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉ์ž์˜ ํ–‰๋™์„ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ํ•˜๋ฉฐ ์ฃผ์š” ๊ธฐ๋Šฅ ํ๋ฆ„์„ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋กœ ๊ฒ€์ฆ ๊ฐ€๋Šฅ

  • Vercel
    Next.js ๊ณต์‹ ํ˜ธ์ŠคํŒ… ํ”Œ๋žซํผ์œผ๋กœ GitHub ์—ฐ๋™ ๋ฐ ์ž๋™ ๋ฐฐํฌ, ์„œ๋ฒ„๋ฆฌ์Šค ํ•จ์ˆ˜ ์ง€์› ๋“ฑ ๋น ๋ฅธ ๊ฐœ๋ฐœ๊ณผ ๋ฐฐํฌ ์›Œํฌํ”Œ๋กœ์šฐ์— ์ตœ์ ํ™”


โš™๏ธ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ค์ •ํ•˜๊ธฐ

โ–ช๏ธ Eslint ๋ฐ Prettier ์ ์šฉ

ESLint์™€ Prettier๋ฅผ ํ•จ๊ป˜ ์„ค์ •ํ•˜๋ฉด ํŒ€ ๋‚ด ์ฝ”๋“œ ์Šคํƒ€์ผ์„ ํ†ต์ผํ•˜๊ณ  ์‚ฌ์†Œํ•œ ํฌ๋งทํŒ… ์ฐจ์ด๋กœ ์ธํ•œ ๋ฆฌ๋ทฐ ๋‚ญ๋น„๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์–ด ํ˜‘์—… ํšจ์œจ์— ํฌ๊ฒŒ ๊ธฐ์—ฌํ•œ๋‹ค.

  • ESLint: ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ์˜ ๋ฌธ๋ฒ• ์˜ค๋ฅ˜๋ฅผ ์‚ฌ์ „์— ๊ฒ€์ถœํ•˜๊ณ  ์ •ํ•ด์ง„ ์ฝ”๋“œ ์Šคํƒ€์ผ ๊ฐ€์ด๋“œ๋ฅผ ๊ฐ•์ œํ•˜๊ธฐ ์œ„ํ•œ ์ •์  ๋ถ„์„ ๋„๊ตฌ

  • Prettier: ์ฝ”๋“œ ํฌ๋งทํŒ…์„ ์ž๋™์œผ๋กœ ์ผ๊ด€๋˜๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋„๊ตฌ

{
  "extends": ["next/core-web-vitals", "plugin:prettier/recommended"],
  "plugins": ["prettier"],
  "rules": {
    "prettier/prettier": "error",
    "react-hooks/rules-of-hooks": "warn",
    "react/display-name": "warn"
  }
}
  • next/core-web-vitals
    Next.js์˜ ๊ณต์‹ ESLint ์„ค์ •์œผ๋กœ, Core Web Vitals ๊ธฐ์ค€์˜ ์„ฑ๋Šฅ ๊ด€๋ จ ๊ทœ์น™๋„ ํฌํ•จ
  • plugin:prettier/recommended
    Prettier์™€ ESLint๋ฅผ ์—ฐ๋™ํ•˜์—ฌ ์ถฉ๋Œ ์—†์ด ์Šคํƒ€์ผ ๊ฒ€์‚ฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋„๋ก ์„ค์ • (์ฝ”๋“œ ํฌ๋งทํŒ… ์˜ค๋ฅ˜๊ฐ€ ESLint ์˜ค๋ฅ˜๋กœ ์ฒ˜๋ฆฌ๋จ)
  • prettier/prettier: error
    Prettier ํฌ๋งท์— ๋งž์ง€ ์•Š๋Š” ์ฝ”๋“œ๋ฅผ ESLint ์—๋Ÿฌ๋กœ ๊ฐ„์ฃผํ•˜์—ฌ ๋นŒ๋“œ๋‚˜ ์ปค๋ฐ‹ ์ฐจ๋‹จ ๊ฐ€๋Šฅ
  • react-hooks/rules-of-hooks: warn
    React Hooks๋Š” ์กฐ๊ฑด๋ฌธ, ๋ฐ˜๋ณต๋ฌธ ๋“ฑ์—์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†์œผ๋ฉฐ ํ•ญ์ƒ ์ตœ์ƒ์œ„์—์„œ ํ˜ธ์ถœํ•ด์•ผ ํ•จ์„ ๊ฒ€์‚ฌ
  • react/display-name: warn
    ์ต๋ช… ์ปดํฌ๋„ŒํŠธ์— displayName์ด ์—†์„ ๊ฒฝ์šฐ ๊ฒฝ๊ณ ํ•˜์—ฌ ๋””๋ฒ„๊น… ํŽธ์˜์„ฑ์„ ํ™•๋ณดํ•จ

โ–ช๏ธ Supabase ๋ฐ Prisma ํ™˜๊ฒฝ ๊ตฌ์„ฑ

  • Supabase๋Š” ์˜คํ”ˆ ์†Œ์Šค ๊ธฐ๋ฐ˜์˜ ๋ฐฑ์—”๋“œ ํ”Œ๋žซํผ์œผ๋กœ PostgreSQL์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค, ์ธ์ฆ ์‹œ์Šคํ…œ, ์Šคํ† ๋ฆฌ์ง€, ์‹ค์‹œ๊ฐ„ ์›น์†Œ์ผ“ ๋“ฑ ๋‹ค์–‘ํ•œ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.
    ๋ณต์žกํ•œ ๋ฐฑ์—”๋“œ ์ธํ”„๋ผ๋ฅผ ์ง์ ‘ ๊ตฌ์ถ•ํ•˜์ง€ ์•Š๊ณ ๋„, ๋น ๋ฅด๊ฒŒ ๋ฐ์ดํ„ฐ ์ค‘์‹ฌ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€๋‹ค.

  • Prisma๋Š” Node.js ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ORM(Object-Relational Mapping) ๋„๊ตฌ๋กœ,
    ์ง๊ด€์ ์ธ ์Šคํ‚ค๋งˆ ๋ฌธ๋ฒ•๊ณผ ํƒ€์ž… ๊ธฐ๋ฐ˜ ์ฟผ๋ฆฌ ์ƒ์„ฑ์„ ํ†ตํ•ด ์ƒ์‚ฐ์„ฑ๊ณผ ์•ˆ์ •์„ฑ์„ ๋ชจ๋‘ ๊ฐ–์ถ˜ ๊ฐœ๋ฐœ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•œ๋‹ค.

  • Prisma Client: TypeScript ๊ธฐ๋ฐ˜์œผ๋กœ ์•ˆ์ „ํ•˜๊ณ  ์ž๋™์™„์„ฑ ๊ฐ€๋Šฅํ•œ ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” ํด๋ผ์ด์–ธํŠธ
  • Prisma Migrate: DB ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜์„ ๊ด€๋ฆฌํ•˜๊ณ , ๋ณ€๊ฒฝ ์ด๋ ฅ์„ ์ฝ”๋“œ๋กœ ์ถ”์  ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ด์ฃผ๋Š” ๋„๊ตฌ
  • Prisma Studio: ๋กœ์ปฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋ฐ์ดํ„ฐ๋ฅผ GUI ํ™˜๊ฒฝ์—์„œ ์‹œ๊ฐ์ ์œผ๋กœ ํ™•์ธํ•˜๊ณ  ํŽธ์ง‘ํ•  ์ˆ˜ ์žˆ๋Š” ์ธํ„ฐํŽ˜์ด์Šค

โ–ช๏ธ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ชจ๋ธ๋ง ๋ฐ ์Šคํ‚ค๋งˆ ๊ตฌ์„ฑ

ํ”„๋กœ์ ํŠธ์˜ ๋ฐฑ์—”๋“œ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋Š” Supabase์™€ Prisma๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์„ค๊ณ„ํ–ˆ๋‹ค. ์ดˆ๊ธฐ ์•„ํ‚คํ…์ฒ˜ ์„ค๊ณ„ ๋‹จ๊ณ„์—์„œ ์‚ฌ์šฉ์ž(User)์™€ ์ˆ™์†Œ(Room)๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ๋„๋ฉ”์ธ ๋ชจ๋ธ์˜ ๊ด€๊ณ„๋ฅผ ์ •์˜ํ•˜๊ณ , ์ด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ Prisma ์Šคํ‚ค๋งˆ๋ฅผ ๊ตฌ์„ฑํ–ˆ๋‹ค.

Prisma๋Š” ์ง๊ด€์ ์ธ ๋ฌธ๋ฒ•์„ ํ†ตํ•ด ๊ด€๊ณ„ํ˜• ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ตฌ์กฐ๋ฅผ ์ฝ”๋“œ ๊ธฐ๋ฐ˜์œผ๋กœ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ์–ด ์Šคํ‚ค๋งˆ ์„ค๊ณ„์™€ ๊ด€๋ฆฌ๊ฐ€ ํšจ์œจ์ ์ด๋‹ค. ๐Ÿคฉ

๐Ÿคช CLI๋ฅผ ํ†ตํ•ด ์Šคํ‚ค๋งˆ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ช…๋ น์„ ์‹คํ–‰ํ•ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•˜์ง€๋งŒ ์ดˆ๊ธฐ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๊ณผ์ •์—์„œ ์ถฉ๋Œ ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ Supabase์˜ SQL Editor๋ฅผ ์ด์šฉํ•ด ํ…Œ์ด๋ธ”์„ ์ง์ ‘ ์ƒ์„ฑํ•œ ํ›„, Prisma ์Šคํ‚ค๋งˆ์™€ ๋™๊ธฐํ™”ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ดˆ๊ธฐ ์„ค์ •์„ ๋งˆ๋ฌด๋ฆฌํ–ˆ๋‹ค.

Prisma ์Šคํ‚ค๋งˆ๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ SQL ๋ฌธ์œผ๋กœ ๋ณ€ํ™˜๋˜์–ด ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ๋ชจ๋ธ๋กœ ์ €์žฅ๋˜๋ฉฐ ์ด๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ”์ด ์ƒ์„ฑ๋˜๊ณ  ๊ด€๋ฆฌ๋œ๋‹ค! (์•„๋ž˜๋Š” Supabase SQL Editor์— ์ง์ ‘ ์ž…๋ ฅํ•œ ๋ชจ๋ธ ๊ตฌ์„ฑ์ด๋ฉฐ ์‹ค์ œ๋กœ ํ…Œ์ด๋ธ”์ด ์ •์ƒ์ ์œผ๋กœ ์ƒ์„ฑ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.)

๐Ÿ‘€ Prisma์—์„œ ์ œ๊ณตํ•˜๋Š” ์‹œ๊ฐํ™” ๋„๊ตฌ์ธ Prisma Studio๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ๋„ ํ…Œ์ด๋ธ” ๊ตฌ์กฐ์™€ ๋ฐ์ดํ„ฐ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. (์•„๋ž˜๋Š” mock ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฝ์ž…ํ•œ ๋’ค Studio์—์„œ ํ™•์ธํ•œ ํ™”๋ฉด์ด๋‹ค.)

profile
์ฐจ๊ณก์ฐจ๊ณก ์Œ“์•„๋‘๊ธฐ ๐Ÿ’ญ

0๊ฐœ์˜ ๋Œ“๊ธ€