๐Ÿ‡ฐ๐Ÿ‡ท
๐Ÿ‡ฌ๐Ÿ‡ง English
๐Ÿ‡ธ๐Ÿ‡ฆ ุงู„ุนุฑุจูŠุฉ
๐Ÿ‡ฉ๐Ÿ‡ช Deutsch
๐Ÿ‡ฌ๐Ÿ‡ท ฮ•ฮปฮปฮทฮฝฮนฮบฮฌ
๐Ÿ‡ช๐Ÿ‡ธ Espaรฑol
๐Ÿ‡ซ๐Ÿ‡ท Franรงais
๐Ÿ‡ฎ๐Ÿ‡น Italiano
๐Ÿ‡ฐ๐Ÿ‡ท ํ•œ๊ตญ์–ด
๐Ÿ‡ต๐Ÿ‡ฑ Polski
๐Ÿ‡ต๐Ÿ‡น Portuguรชs
๐Ÿ‡ท๐Ÿ‡บ ะ ัƒััะบะธะน
๐Ÿ‡ธ๐Ÿ‡ช Svenska
๐Ÿ‡ต๐Ÿ‡ฐ ุงุฑุฏูˆ
๐Ÿ‡จ๐Ÿ‡ณ ไธญๆ–‡
React ๋ฐ NestJS ๋กœ๊ณ 

๐ŸฅŠ Remix vs Next.js โ€” RemixJS๋ฅผ ์„ ํƒํ•ด์•ผ ํ•˜๋Š” ์ด์œ ?

Remix์™€ Next.js๋Š” ๋ชจ๋‘ ์ตœ์‹  ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ตฌ์ถ•ํ•˜๋„๋ก ์„ค๊ณ„๋œ ๊ฐ•๋ ฅํ•œ ํ’€ ์Šคํƒ React ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค. Next.js๊ฐ€ Vercel์˜ ์ง€์›์„ ๋ฐ›๋Š” ์˜ค๋ž˜๋œ ํ”Œ๋ ˆ์ด์–ด์ธ ๋ฐ˜๋ฉด, RemixJS๋Š” ์„ฑ๋Šฅ, ๋‹จ์ˆœ์„ฑ ๋ฐ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๋ชจ๋ธ๋กœ ๋น ๋ฅด๊ฒŒ ์ฃผ๋ชฉ๋ฐ›๊ณ  ์žˆ๋Š” ์ƒˆ๋กœ์šด ์›น ํ‘œ์ค€ ์ค‘์‹ฌ ํ”„๋ ˆ์ž„์›Œํฌ์ž…๋‹ˆ๋‹ค.

์ด ๊ธฐ์‚ฌ์—์„œ๋Š” Remix๊ฐ€ Next.js์™€ ์ฐจ๋ณ„ํ™”๋˜๋Š” ์ ๊ณผ Remix๊ฐ€ ์†๋„, ์œ ์ง€ ๋ณด์ˆ˜์„ฑ ๋ฐ ์›น ๊ธฐ๋ฐ˜ ์ •๋ ฌ์„ ์ถ”๊ตฌํ•œ๋‹ค๋ฉด ๋‹ค์Œ ํ”„๋กœ์ ํŠธ์— ๋” ์ ํ•ฉํ•œ ์ด์œ ๋ฅผ ์‚ดํŽด๋ณผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๐Ÿš€ RemixJS ํ•œ๋ˆˆ์— ๋ณด๊ธฐ

  • ํ’€ ์Šคํƒ React ํ”„๋ ˆ์ž„์›Œํฌ
  • ์›น ๊ธฐ๋ณธ (HTTP ์บ์‹ฑ, ๋„ค์ดํ‹ฐ๋ธŒ ํผ ๋“ฑ)์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๊ตฌ์ถ•๋จ
  • ์ ์ง„์  ํ–ฅ์ƒ์„ ํฌ์šฉํ•จ
  • ์ตœ์†Œํ•œ์˜ JavaScript ์ข…์†์„ฑ์„ ํ†ตํ•ด ๋น ๋ฅธ ์„ฑ๋Šฅ์— ์ค‘์ 
  • ๋ชจ๋“  ๋ฐฐํฌ ๋Œ€์ƒ (Node, Cloudflare, Deno ๋“ฑ)์—์„œ ์ž‘๋™

๐Ÿ” Next.js์— ๋น„ํ•ด Remix์˜ ์ฃผ์š” ์žฅ์ 

์‹ค์ œ ๊ฐœ๋ฐœ์ž์˜ ๊ด€์‹ฌ์‚ฌ์™€ ์•„ํ‚คํ…์ฒ˜์  ์ฐจ์ด์ ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋‘ ๊ฐ€์ง€๋ฅผ ๋น„๊ตํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

1. ๐Ÿง  ๋ฐ์ดํ„ฐ ๋กœ๋”ฉ ๋ชจ๋ธ

โœ… Remix: ์„œ๋ฒ„ ์šฐ์„ , ๊ณต๋™ ๋ฐฐ์น˜ ๋กœ๋” Remix์˜ ๊ฐ ๋ผ์šฐํŠธ๋Š” ๋ Œ๋”๋ง ์ „์— ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋˜๋Š” `loader()` ํ•จ์ˆ˜๋ฅผ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ํ•„์š”ํ•œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ๋ณ‘๋ ฌ๋กœ ๊ฐ€์ ธ์™€ ์‘๋‹ต์˜ ์ผ๋ถ€๋กœ ๋ณด๋ƒ…๋‹ˆ๋‹ค.

// app/routes/posts.tsx
export const loader = async () => {
const posts = await getPosts();
return json(posts);
};

๐Ÿšซ Next.js: getServerSideProps ๋˜๋Š” getStaticProps Next.js๋Š” ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ํŠน๋ณ„ํ•œ ํ•จ์ˆ˜๋กœ ๋ถ„๋ฆฌํ•˜์ง€๋งŒ, ํŽ˜์ด์ง€ ์ˆ˜์ค€์—์„œ๋งŒ ๊ฐ€๋Šฅํ•˜์—ฌ ์ค‘์ฒฉ๋œ ์ปดํฌ๋„ŒํŠธ์˜ ์žฌ์‚ฌ์šฉ์„ฑ ๋ฐ ๊ตฌ์„ฑ ๊ฐ€๋Šฅ์„ฑ์„ ์ œํ•œํ•ฉ๋‹ˆ๋‹ค.

// pages/posts.js
export async function getServerSideProps() {
  const posts = await getPosts();
  return { props: { posts } };
}

๐Ÿ” ํŒ๊ฒฐ: Remix๋Š” ์ค‘์ฒฉ๋œ ๋ผ์šฐํŠธ์—๋„ ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ์—ฐ๊ฒฐํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ๋‹จ์ˆœํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋” ๋‚˜์€ ์„ฑ๋Šฅ๊ณผ ๊ตฌ์กฐ๋กœ ์ด์–ด์ง‘๋‹ˆ๋‹ค.

2. ๐Ÿงญ ์ค‘์ฒฉ ๋ผ์šฐํŒ… ๋ฐ ๋ ˆ์ด์•„์›ƒ

โœ… Remix: ๋„ค์ดํ‹ฐ๋ธŒ ์ค‘์ฒฉ ๋ผ์šฐํŠธ Remix ๋ผ์šฐํŠธ๋Š” ๊ณต๋™ ๋ฐฐ์น˜๋˜๊ณ  ๋ณธ์งˆ์ ์œผ๋กœ ์ค‘์ฒฉ๋ฉ๋‹ˆ๋‹ค. ๋ ˆ์ด์•„์›ƒ๊ณผ ๋ผ์šฐํŠธ๋Š” ํด๋”์ฒ˜๋Ÿผ ๊ตฌ์กฐํ™”๋˜๋ฉฐ, ๋ ˆ์ด์•„์›ƒ ์ˆ˜์ค€ ๋กœ๋”๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

routes/
โ”œโ”€โ”€ dashboard.tsx        --> /dashboard
โ””โ”€โ”€ dashboard/
    โ””โ”€โ”€ settings.tsx     --> /dashboard/settings

๐Ÿšซ Next.js: ์•ฑ ๋ผ์šฐํ„ฐ ๋ฐ ํŒŒ์ผ ๊ทœ์น™ Next.js๋Š” ์ตœ๊ทผ ๋ ˆ์ด์•„์›ƒ์„ ์ง€์›ํ•˜๋Š” ์•ฑ ๋””๋ ‰ํ† ๋ฆฌ ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ…์„ ๋„์ž…ํ–ˆ์ง€๋งŒ, ์ด๋Š” ๋” ์ƒˆ๋กญ๊ณ  ๋ณต์žกํ•˜๋ฉฐ, ๋ ˆ์ด์•„์›ƒ์˜ ์„œ๋ฒ„ ์ธก ๋ฐ์ดํ„ฐ์™€ ๊นŠ์ด ํ†ตํ•ฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๐Ÿ” ํŒ๊ฒฐ: Remix์˜ ์ค‘์ฒฉ ๋ผ์šฐํŠธ๋Š” ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ณ , ๋” ์œ ์—ฐํ•˜๋ฉฐ, ๋ณต์žกํ•œ UI ๊ณ„์ธต ๊ตฌ์กฐ์—์„œ ๋” ์ž˜ ํ™•์žฅ๋ฉ๋‹ˆ๋‹ค.

3. โšก ์„ฑ๋Šฅ: ํด๋ผ์ด์–ธํŠธ ์ธก JavaScript ๊ฐ์†Œ

โœ… Remix: ์ตœ์†Œ JS ์ข…์†์„ฑ Remix๋Š” ํ•„์š”ํ•œ ๋งŒํผ๋งŒ JS๋ฅผ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. ํด๋ผ์ด์–ธํŠธ ์ธก ๋กœ์ง์„ ์ค„์ด๊ธฐ ์œ„ํ•ด ๋„ค์ดํ‹ฐ๋ธŒ ํผ ์ œ์ถœ ๋ฐ ์บ์‹ฑ๊ณผ ๊ฐ™์€ ํ‘œ์ค€ ๋ธŒ๋ผ์šฐ์ € ๋™์ž‘์— ์˜์กดํ•ฉ๋‹ˆ๋‹ค.

๐Ÿšซ Next.js: ํด๋ผ์ด์–ธํŠธ ์ค‘์‹ฌ์˜ ์ƒํ˜ธ ์ž‘์šฉ์„ฑ Next.js๋Š” Hydration ๋ฐ ํด๋ผ์ด์–ธํŠธ ์ธก API์— ๋” ๋งŽ์ด ์˜์กดํ•˜๋ฉฐ, ์ด๋Š” ์ข…์ข… ๋” ๋ฌด๊ฑฐ์šด ๋ฒˆ๋“ค๋กœ ์ด์–ด์ง‘๋‹ˆ๋‹ค.

๐Ÿ” ํŒ๊ฒฐ: Remix ์•ฑ์€ ๋ธŒ๋ผ์šฐ์ €์™€ ์„œ๋ฒ„์— ๋” ๋งŽ์€ ์ž‘์—…์„ ์˜คํ”„๋กœ๋“œํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ์ ์œผ๋กœ ๋” ๋น ๋ฆ…๋‹ˆ๋‹ค.

4. ๐Ÿ“ค ํผ ๋ฐ ์•ก์…˜

โœ… Remix: ์ ์ง„์ , ์„œ๋ฒ„ ๊ธฐ๋ฐ˜ ํผ Remix์˜ ํผ์€ ๋„ค์ดํ‹ฐ๋ธŒ `<form>` ํƒœ๊ทธ๋ฅผ ์„œ๋ฒ„ ์ธก `action()` ํ•จ์ˆ˜์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ ์ œ์ถœ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. JavaScript๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

export const action = async ({ request }) => {
  const formData = await request.formData();
  await savePost(formData);
  return redirect("/success");
};

๐Ÿšซ Next.js: JavaScript + API ๋ผ์šฐํŠธ ํ•„์š” Next.js ํผ์€ ์ผ๋ฐ˜์ ์œผ๋กœ `fetch` ๋˜๋Š” ํด๋ผ์ด์–ธํŠธ ์ธก ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ†ตํ•ด ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค. Remix์™€ ๊ฐ™์€ ๋‚ด์žฅ ํผ ์ฒ˜๋ฆฌ๋Š” ์—†์Šต๋‹ˆ๋‹ค.

๐Ÿ” ํŒ๊ฒฐ: Remix๋Š” ์ „ํ†ต์ ์ธ ์„œ๋ฒ„ ๋ Œ๋”๋ง ์•ฑ์˜ ๋‹จ์ˆœ์„ฑ์„ ๋˜์‚ด๋ ค ์ ์€ ํด๋ผ์ด์–ธํŠธ ์ฝ”๋“œ๋กœ ๋น ๋ฅด๊ณ  ์ ์ง„์ ์ธ ํผ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

5. ๐ŸŒ ์บ์‹ฑ ๋ฐ ์›น ๊ธฐ๋ณธ

โœ… Remix: HTTP ์บ์‹ฑ ๊ธฐ๋ฐ˜ ๋กœ๋” ์ˆ˜์ค€์—์„œ ์บ์‹ฑ์„ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์–ด ๋ธŒ๋ผ์šฐ์ € ๋˜๋Š” CDN์ด ์ €์žฅํ•˜๋Š” ๋‚ด์šฉ์„ ์ง€๋Šฅ์ ์œผ๋กœ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

export const loader: LoaderFunction = async ({ request }) => {
  return new Response(JSON.stringify(data), {
    headers: { "Cache-Control": "max-age=3600" },
  });
};

๐Ÿšซ Next.js: ๋Œ€๋ถ€๋ถ„ Vercel ํŠน์ • ์ตœ์ ํ™”๋กœ ์ฒ˜๋ฆฌ๋จ ํ—ค๋”๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, Vercel์—์„œ ํ˜ธ์ŠคํŒ…๋˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ ๋” ์ถ”์ƒ์ ์ด๊ณ  ์œ ์—ฐ์„ฑ์ด ๋–จ์–ด์ง‘๋‹ˆ๋‹ค.

๐Ÿ” ํŒ๊ฒฐ: Remix๋Š” HTTP ์‘๋‹ต ๋ฐ ์บ์‹œ์— ๋Œ€ํ•œ ์ง์ ‘์ ์ธ ์ œ์–ด๋ฅผ ์ œ๊ณตํ•˜์—ฌ ๋„ค์ดํ‹ฐ๋ธŒ ์›น ์›์น™์„ ํฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

6. ๐Ÿ› ๏ธ ๋ฐฐํฌ ์œ ์—ฐ์„ฑ

  • Remix๋Š” Node.js, Deno, Cloudflare Workers, Vercel, Netlify, Fly.io์—์„œ ์‹คํ–‰๋˜๋ฉฐ, ๋…๋ฆฝํ˜• Express ์•ฑ์œผ๋กœ๋„ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
  • Next.js๋Š” Vercel(์Šคํฐ์„œ)์—์„œ ๊ฐ€์žฅ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ง€์ • ๋ฐฐํฌ๋Š” ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ๋œ ์›ํ™œํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ” ํŒ๊ฒฐ: ๊ณต๊ธ‰์—…์ฒด ์ข…์†์„ ํ”ผํ•ด์•ผ ํ•œ๋‹ค๋ฉด Remix๊ฐ€ ๋” ์œ ์—ฐํ•ฉ๋‹ˆ๋‹ค.

7. ๐Ÿ”ง ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜

๋‹ค์Œ์€ Remix์™€ Next.js ๊ฐ„์˜ ๋น ๋ฅธ ๊ธฐ๋Šฅ ๋น„๊ต์ž…๋‹ˆ๋‹ค.

  • ๋ผ์šฐํŒ… โ€” Remix: ์ค‘์ฒฉ, ๋ ˆ์ด์•„์›ƒ ์šฐ์„  | Next.js: ๊ธฐ๋ณธ์ ์œผ๋กœ ํ‰๋ฉด (ํŽ˜์ด์ง€), ์•ฑ ๋””๋ ‰ํ† ๋ฆฌ๋Š” ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ
  • ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ โ€” Remix: ๋ผ์šฐํŠธ ๊ธฐ๋ฐ˜ ๋กœ๋” | Next.js: getServerSideProps, API ๋ผ์šฐํŠธ
  • ํผ โ€” Remix: ์•ก์…˜๊ณผ ํ•จ๊ป˜ ๋„ค์ดํ‹ฐ๋ธŒ | Next.js: ์‚ฌ์šฉ์ž ์ง€์ • JS + API ์—”๋“œํฌ์ธํŠธ
  • ์บ์‹ฑ โ€” Remix: ์ „์ฒด HTTP ์ œ์–ด | Next.js: Vercel์—์„œ ์ฒ˜๋ฆฌ ๋˜๋Š” ์‚ฌ์šฉ์ž ์ง€์ •
  • ํด๋ผ์ด์–ธํŠธ JS โ€” Remix: ๋” ์ž‘๊ณ  ์ตœ์†Œ | Next.js: ๋” ํฌ๊ณ  Hydration ์ค‘์‹ฌ
  • ๋ฐฐํฌ โ€” Remix: ๋ชจ๋“  ๊ณณ (Cloudflare, Denoโ€ฆ) | Next.js: Vercel์—์„œ ๊ฐ€์žฅ ์ข‹์Œ

๐Ÿงฉ Next.js ๋Œ€์‹  Remix๋ฅผ ์„ ํƒํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ?

  • โœ… ์ ์ง„์  ํ–ฅ์ƒ ๋ฐ ๋น ๋ฅธ ์„ฑ๋Šฅ์„ ์›ํ•  ๋•Œ
  • โœ… ๋ผ์šฐํŒ… ๋ฐ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ์— ๋Œ€ํ•œ ๊นŠ์€ ์ œ์–ด๋ฅผ ์ค‘์š”ํ•˜๊ฒŒ ์ƒ๊ฐํ•  ๋•Œ
  • โœ… ์ตœ์†Œํ•œ์˜ JS ๋ฐ ๋” ๋‚˜์€ SEO๋ฅผ ์„ ํ˜ธํ•  ๋•Œ
  • โœ… JS๊ฐ€ ๋น„ํ™œ์„ฑํ™”๋œ ๊ฒฝ์šฐ์—๋„ ์ž‘๋™ํ•˜๋Š” ์•ฑ์„ ๊ตฌ์ถ•ํ•˜๊ณ  ์‹ถ์„ ๋•Œ
  • โœ… Vercel ์™ธ์— ์œ ์—ฐํ•œ ๋ฐฐํฌ ์˜ต์…˜์ด ํ•„์š”ํ•  ๋•Œ

๐Ÿ ๋งˆ์ง€๋ง‰ ์ƒ๊ฐ

Remix์™€ Next.js๋Š” ๋ชจ๋‘ ํ›Œ๋ฅญํ•œ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Remix๋Š” ๊ณ ์ „์ ์ธ ์„œ๋ฒ„ ๋ Œ๋”๋ง ์•ฑ์˜ ๋‹จ์ˆœ์„ฑ๊ณผ ์„ฑ๋Šฅ์„ ๋˜์‚ด๋ฆฌ๋ฉด์„œ๋„ ์ตœ์‹  React ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ์ถ”์ƒํ™”๋ณด๋‹ค ์›น ํ‘œ์ค€์„ ์„ ํ˜ธํ•˜์—ฌ ์•ฑ์„ ๋น ๋ฅด๊ณ  ํƒ„๋ ฅ์ ์ด๋ฉฐ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ๋งŒ๋“ญ๋‹ˆ๋‹ค.

Next.js์—์„œ Remix๋กœ ์•ฑ์„ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๊ฑฐ๋‚˜ ์ƒˆ๋กœ์šด Remix ์•ฑ์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ๊ตฌ์ถ•ํ•˜๋Š” ๋ฐ ๋„์›€์ด ํ•„์š”ํ•˜์‹ญ๋‹ˆ๊นŒ? ์•Œ๋ ค์ฃผ์„ธ์š”! ๐Ÿš€