7 min read

React Router 7๋กœ SSG + SPA ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๊ตฌํ˜„ํ•˜๊ธฐ (์„œ๋ฒ„ ์—†์ด ์ •์  ์‚ฌ์ดํŠธ๋กœ๋งŒ ์šด์˜ํ•˜๊ธฐ)

Table of Contents

๋“ค์–ด๊ฐ€๋ฉฐ

์„œ๋น„์Šค ์†Œ๊ฐœ ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค ๋•Œ ๊ณ ๋ฏผ์ด ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค. ๋ฉ”์ธ ํŽ˜์ด์ง€์™€ ํšŒ์‚ฌ ์†Œ๊ฐœ ๊ฐ™์€ ์ •์  ํŽ˜์ด์ง€๋Š” SEO๋„ ์ค‘์š”ํ•˜๊ณ  ๋น ๋ฅธ ๋กœ๋”ฉ์ด ํ•„์š”ํ•œ๋ฐ, ๋‚˜๋จธ์ง€ ํŽ˜์ด์ง€๋“ค์€ ๊ทธ๋ƒฅ SPA๋กœ ๋™์ž‘ํ•ด๋„ ๊ดœ์ฐฎ์•˜๊ฑฐ๋“ ์š”. ํ•˜์ง€๋งŒ ์„œ๋ฒ„๋ฅผ ์šด์˜ํ•˜๊ธฐ์—” ๋น„์šฉ ๋ถ€๋‹ด์ด ์žˆ์—ˆ๊ณ , ์ •์  ํ˜ธ์ŠคํŒ…๋งŒ์œผ๋กœ ํ•ด๊ฒฐํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜๋ฉด, React Router 7์˜ ssr: false + prerender ์กฐํ•ฉ์œผ๋กœ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค. ์ผ๋ถ€ ํŽ˜์ด์ง€๋Š” ๋นŒ๋“œ ํƒ€์ž„์— ๋ฏธ๋ฆฌ ๋ Œ๋”๋ง(SSG)ํ•˜๊ณ , ๋‚˜๋จธ์ง€๋Š” SPA๋กœ ๋™์ž‘ํ•˜๋Š” ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

์ด ๊ธ€์—์„œ๋Š” ์ œ๊ฐ€ ๊ฒฝํ—˜ํ•œ ์‹œํ–‰์ฐฉ์˜ค์™€ ํ•ด๊ฒฐ ๊ณผ์ •, ๊ทธ๋ฆฌ๊ณ  ์ถ”๊ฐ€๋กœ ๋ฐœ๊ฒฌํ•œ SEO ํŒ๊นŒ์ง€ ๊ณต์œ ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ชฉํ‘œ: ์„œ๋ฒ„ ์—†๋Š” ์ •์  ํ˜ธ์ŠคํŒ…

์ œ๊ฐ€ ์›ํ–ˆ๋˜ ๊ฒƒ

  • /, /about ๊ฐ™์€ ์ฃผ์š” ํŽ˜์ด์ง€๋Š” SSG๋กœ ๋นŒ๋“œ ํƒ€์ž„์— HTML ์ƒ์„ฑ (SEO๋ฅผ ์œ„ํ•ด)
  • ๋‚˜๋จธ์ง€ ํŽ˜์ด์ง€๋Š” SPA๋กœ ๋™์ž‘
  • ์„œ๋ฒ„ ์—†์ด ์ •์  ํŒŒ์ผ๋งŒ์œผ๋กœ ์šด์˜ (๋น„์šฉ ์ ˆ๊ฐ์„ ์œ„ํ•ด)

React Router 7์€ ์ด๋Ÿฐ ์š”๊ตฌ์‚ฌํ•ญ์„ ์ •ํ™•ํžˆ ์ถฉ์กฑ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์„ค์ •: ssr: false + prerender

๊ฐ€์žฅ ํ•ต์‹ฌ์ด ๋˜๋Š” ์„ค์ •์€ react-router.config.ts์ž…๋‹ˆ๋‹ค:

// react-router.config.ts
import type { Config } from "@react-router/dev/config";

export default {
  // SSR ๋น„ํ™œ์„ฑํ™” = ์„œ๋ฒ„ ํ•„์š” ์—†์Œ
  ssr: false,
  // ํŠน์ • ๊ฒฝ๋กœ๋งŒ ๋ฏธ๋ฆฌ ๋ Œ๋”๋ง
  prerender: ["/", "/about"],
} satisfies Config;

์ด ์„ค์ •์ด ์˜๋ฏธํ•˜๋Š” ๊ฒƒ:

  • ssr: false: ๋Ÿฐํƒ€์ž„ ์„œ๋ฒ„ ๋ Œ๋”๋ง์„ ๋น„ํ™œ์„ฑํ™”ํ•ฉ๋‹ˆ๋‹ค. ๋™์  ๋ Œ๋”๋ง์„ ์œ„ํ•œ ์„œ๋ฒ„๊ฐ€ ํ•„์š” ์—†์Šต๋‹ˆ๋‹ค.
  • prerender: ["/", "/about"]: ๋นŒ๋“œ ํƒ€์ž„์— ์ด ๊ฒฝ๋กœ๋“ค์„ ๋ฏธ๋ฆฌ HTML๋กœ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ œ ๋ฐœ์ƒ: ๋นˆ ํŽ˜์ด์ง€๊ฐ€ ๋ Œ๋”๋ง๋˜๋‹ค

์ฒ˜์Œ ์„ค์ •ํ•˜๊ณ  ๋นŒ๋“œํ–ˆ์„ ๋•Œ, ์ด์ƒํ•œ ํ˜„์ƒ์ด ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

npm run build

๋นŒ๋“œ๋Š” ์„ฑ๊ณตํ–ˆ๊ณ , build/client/index.html๊ณผ build/client/about/index.html ํŒŒ์ผ๋„ ์ƒ์„ฑ๋์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ํŒŒ์ผ์„ ์—ด์–ด๋ณด๋‹ˆ ๋‚ด์šฉ์ด ๋น„์–ด์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. HydrateFallback์˜ โ€œLoadingโ€ฆโ€ ๋ฉ”์‹œ์ง€๋งŒ ์žˆ๊ณ , ์‹ค์ œ ์ปจํ…์ธ ๋Š” ์—†์—ˆ์–ด์š”.

<!-- ์ƒ์„ฑ๋œ index.html -->
<!DOCTYPE html>
<html>
  <head>
    ...
  </head>
  <body>
    <div id="root">Loading...</div>
    <script src="/assets/entry.client.js"></script>
  </body>
</html>

์ œ๊ฐ€ ์•„๋Š” ์ •์  ๋ Œ๋”๋ง(SSG)์€ ์ด๋Ÿฐ๊ฒŒ ์•„๋‹Œ๋ฐ ๋ง์ด์ฃ โ€ฆ HeroSection, ์†Œ๊ฐœ ๋ฌธ๊ตฌ, ์ด๋ฏธ์ง€โ€ฆ ๋ชจ๋“  ์ปจํ…์ธ ๊ฐ€ ๋น ์ ธ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์›์ธ: loader๊ฐ€ ์—†์œผ๋ฉด prerender๋ฅผ ๊ฑด๋„ˆ๋›ด๋‹ค

๊ณต์‹ ๋ฌธ์„œ์™€ AI ๋Œ€ํ™” ํ•‘ํ์„ ํ†ตํ•ด ์›์ธ์„ ์ฐพ์•˜์Šต๋‹ˆ๋‹ค. React Router 7์˜ prerendering์€ loader์˜ ์กด์žฌ ์—ฌ๋ถ€๋กœ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋งํ• ์ง€ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

loader๊ฐ€ ์—†๋‹ค๋ฉด?

// app/pages/home/index.tsx
export default function HomePage() {
  return (
    <div>
      <h1>Welcome!</h1>
      <p>This is our homepage</p>
    </div>
  );
}

์ด ์ฝ”๋“œ๋กœ ๋นŒ๋“œํ•˜๋ฉด React Router๋Š” ์ด๋ ‡๊ฒŒ ํŒ๋‹จํ•ฉ๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๋Š” ์„œ๋ฒ„(๋นŒ๋“œ ํƒ€์ž„)์—์„œ ๊ฐ€์ ธ์˜ฌ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋„ค? ๊ทธ๋Ÿผ ๊ตณ์ด ๋ฏธ๋ฆฌ ๋ Œ๋”๋งํ•˜์ง€ ์•Š๊ณ , ๋ธŒ๋ผ์šฐ์ €์—์„œ JavaScript๊ฐ€ ์‹คํ–‰๋  ๋•Œ ๋ Œ๋”๋งํ•˜๋ฉด ๋˜๊ฒ ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ ๋นŒ๋“œ ์‹œ์ ์—๋Š” HydrateFallback๋งŒ ๋ Œ๋”๋ง๋˜๊ณ , ์‹ค์ œ ์ปจํ…์ธ ๋Š” ๋นŒ๋“œ ๊ฒฐ๊ณผ๋ฌผ html์— ํฌํ•จ๋˜์ง€ ์•Š์•˜๋˜ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

loader๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด?

// app/pages/home/index.tsx

// ๋นˆ loader๋ผ๋„ ์ถ”๊ฐ€
export function loader() {}

export default function HomePage() {
  return (
    <div>
      <h1>Welcome!</h1>
      <p>This is our homepage</p>
    </div>
  );
}

์ด์ œ React Router๋Š” ๋‹ค๋ฅด๊ฒŒ ๋ฐ˜์‘ํ•ฉ๋‹ˆ๋‹ค.

loader๊ฐ€ ์žˆ๋„ค? ์ด ํŽ˜์ด์ง€๋Š” ์„œ๋ฒ„(๋นŒ๋“œ ํƒ€์ž„)์—์„œ ์‹คํ–‰๋˜์–ด์•ผ ํ•˜๋Š” ๋กœ์ง์ด ์žˆ๊ตฌ๋‚˜. ๋นŒ๋“œ ์‹œ์ ์— ๋ Œ๋”๋งํ•ด์„œ HTML์— ํฌํ•จ์‹œํ‚ค์ž.

๋นŒ๋“œ ๊ฒฐ๊ณผ:

<!-- ์ƒ์„ฑ๋œ index.html -->
<!DOCTYPE html>
<html>
  <head>
    ...
  </head>
  <body>
    <div id="root">
      <div>
        <h1>Welcome!</h1>
        <p>This is our homepage</p>
      </div>
    </div>
    <script src="/assets/entry.client.js"></script>
  </body>
</html>

๋“œ๋””์–ด ์‹ค์ œ ์ปจํ…์ธ ๊ฐ€ HTML์— ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ํœด..

ํ•ด๊ฒฐ์ฑ…์€ ๋นˆ loader๋ผ๋„ ์ถ”๊ฐ€ํ•ด์ฃผ๊ธฐ

prerenderํ•˜๊ณ  ์‹ถ์€ ๋ชจ๋“  ํŽ˜์ด์ง€์— loader๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š” ์—†์–ด๋„ ๋นˆ ํ•จ์ˆ˜๋กœ๋ผ๋„ ์ถ”๊ฐ€ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

// app/pages/home/index.tsx
export function loader() {}

export default function HomePage() {
  return (
    <div>
      <HeroSection />
      <Features />
      <CallToAction />
    </div>
  );
}
// app/pages/about/index.tsx
export function loader() {}

export default function AboutPage() {
  return (
    <div>
      <h1>About Us</h1>
      <CompanyHistory />
      <TeamMembers />
    </div>
  );
}

์ด์ œ ๋นŒ๋“œํ•˜๋ฉด

> react-router build

Prerender: Generated build/client/index.html
Prerender: Generated build/client/index.data
Prerender: Generated build/client/about/index.html
Prerender: Generated build/client/about/index.data
Prerender: Generated build/client/__spa-fallback.html

์™„๋ฒฝํ•ฉ๋‹ˆ๋‹ค! ๊ฐ ํŽ˜์ด์ง€๋งˆ๋‹ค:

  • index.html: ์ดˆ๊ธฐ ๋ฌธ์„œ ์š”์ฒญ์„ ์œ„ํ•œ ์™„์ „ํ•œ HTML
  • index.data: ํด๋ผ์ด์–ธํŠธ ๋„ค๋น„๊ฒŒ์ด์…˜์„ ์œ„ํ•œ ๋ฐ์ดํ„ฐ ํŒŒ์ผ
  • __spa-fallback.html: prerender๋˜์ง€ ์•Š์€ ๊ฒฝ๋กœ๋ฅผ ์œ„ํ•œ SPA fallback (403, 404 ์—๋Ÿฌ fallback๋กœ ์‚ฌ์šฉ)

์ตœ์ข…์ ์œผ๋กœ ๊ธฐ๋Œ€๋˜๋Š” ๋™์ž‘ ์ •๋ฆฌ

๋นŒ๋“œ ํƒ€์ž„

  1. React Router๋Š” prerender ๋ฐฐ์—ด์˜ ๊ฐ ๊ฒฝ๋กœ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค
  2. ๊ฐ ๊ฒฝ๋กœ์— ๋งค์นญ๋˜๋Š” route๋“ค์„ ์ฐพ์Šต๋‹ˆ๋‹ค
  3. loader๊ฐ€ ์žˆ๋Š” route๋“ค์„ ๋นŒ๋“œ ์‹œ์ ์— ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค
  4. ์‹คํ–‰ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜์—ฌ HTML์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค
  5. HTML๊ณผ ๋ฐ์ดํ„ฐ ํŒŒ์ผ์„ build/client์— ์ €์žฅํ•ฉ๋‹ˆ๋‹ค

๋Ÿฐํƒ€์ž„ (๋ธŒ๋ผ์šฐ์ €)

prerender๋œ ํŽ˜์ด์ง€ ์ ‘๊ทผ ์‹œ (/, /about):

  1. ์„œ๋ฒ„(์ •์  ํ˜ธ์ŠคํŒ…)๊ฐ€ index.html์„ ๋ฐ˜ํ™˜
  2. HTML์— ์ด๋ฏธ ์ปจํ…์ธ ๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์–ด ์ฆ‰์‹œ ํ‘œ์‹œ๋จ
  3. JavaScript๊ฐ€ ๋กœ๋“œ๋˜๋ฉด hydration ์ง„ํ–‰
  4. ์ดํ›„ ํด๋ผ์ด์–ธํŠธ ๋ผ์šฐํŒ…์œผ๋กœ ๋™์ž‘

prerender๋˜์ง€ ์•Š์€ ํŽ˜์ด์ง€ ์ ‘๊ทผ ์‹œ (/contact, /pricing ๋“ฑ):

  1. ์„œ๋ฒ„๊ฐ€ 404, 403 ๋“ฑ์„ ๋ฐ˜ํ™˜ํ•˜์ง€๋งŒ __spa-fallback.html๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
  2. SPA fallback HTML์ด ๋กœ๋“œ๋จ (๊ธฐ๋ณธ shell๋งŒ ํฌํ•จ)
  3. JavaScript๊ฐ€ ์‹คํ–‰๋˜๊ณ  ๋ธŒ๋ผ์šฐ์ €์—์„œ ํŽ˜์ด์ง€ ๋ Œ๋”๋ง
  4. SPA๋กœ ๋™์ž‘

์ •์  ํ˜ธ์ŠคํŒ… ์„ค์ •: 404 ์ฒ˜๋ฆฌ

prerender๋˜์ง€ ์•Š์€ ๊ฒฝ๋กœ์— ๋Œ€ํ•œ 404 ์ฒ˜๋ฆฌ๊ฐ€ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ์ •์  ํ˜ธ์ŠคํŒ… ์„œ๋น„์Šค๋Š” ์„ค์ • ํŒŒ์ผ๋กœ ์ด๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

AWS S3 + CloudFront ์กฐํ•ฉ์ด๋ผ๋ฉด ์„ค์ •์— ๋”ฐ๋ผ 403 ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Netlify (_redirects)

# / ๊ฒฝ๋กœ๋ฅผ prerenderํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ
/*    /index.html   200

# / ๊ฒฝ๋กœ๋ฅผ prerenderํ•œ ๊ฒฝ์šฐ
/*    /__spa-fallback.html   200

Vercel (vercel.json)

{
  "rewrites": [
    {
      "source": "/(.*)",
      "destination": "/__spa-fallback.html"
    }
  ]
}

Cloudflare Pages (_redirects)

/*    /__spa-fallback.html   200

์ด ์„ค์ •์ด ์—†์œผ๋ฉด /contact ๊ฐ™์€ ๊ฒฝ๋กœ์— ์ง์ ‘ ์ ‘๊ทผํ–ˆ์„ ๋•Œ 404 ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

SEO ๋ณด๋„ˆ์Šค: Canonical Tag๋กœ ์ค‘๋ณต URL ํ†ตํ•ฉํ•˜๊ธฐ

์ •์  ์‚ฌ์ดํŠธ๋ฅผ ์šด์˜ํ•˜๋‹ค ๋ณด๋ฉด /about๊ณผ /about/ ๊ฐ™์€ trailing slash ๋ฌธ์ œ๋ฅผ ๋งŒ๋‚ฉ๋‹ˆ๋‹ค. ์ด ๋‘˜์€ ๊ธฐ์ˆ ์ ์œผ๋กœ ๋‹ค๋ฅธ URL์ด์ง€๋งŒ, ๊ฐ™์€ ํŽ˜์ด์ง€๋ฅผ ๊ฐ€๋ฆฌํ‚ต๋‹ˆ๋‹ค.

๋ฌธ์ œ๋Š” ๋ถ„์„ ๋„๊ตฌ ์„œ๋น„์Šค(GA, Mixpanel ๋“ฑ)์— ๋”ฐ๋ผ ์ด ๋‘˜์„ ๋ณ„๊ฐœ๋กœ ์ง‘๊ณ„ํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๊ฐ€ ๋ถ„์‚ฐ๋˜๊ณ , SEO ์ธก๋ฉด์—์„œ๋„ ์ข‹์ง€ ์•Š์ฃ .

ํ•ด๊ฒฐ์ฑ…: Canonical Tag

// app/pages/about/index.tsx
export function loader() {}

export default function AboutPage() {
  return (
    <div>
      {/* Canonical tag๋กœ ์ •๊ทœ URL ๋ช…์‹œ */}
      <link rel="canonical" href="https://yourdomain.com/about" />

      <h1>About Us</h1>
      <p>We are a great company...</p>
    </div>
  );
}

2. ๊ธ€๋กœ๋ฒŒ ์ ์šฉ

// app/root.tsx
export function Layout({ children }: { children: React.ReactNode }) {
  const canonicalUrl = useCanonical();

  ...
}

// app/shared/hooks/use-canonical.tsx
import { useLocation } from "react-router";

export const useCanonical = () => {
  const location = useLocation();
  const origin = import.meta.env.VITE_SITE_URL;
  const canonicalPath = location.pathname.replace(/\/+$/, "");
  const canonicalUrl = `${origin}${canonicalPath}`;
  return canonicalUrl;
};

์ด์ œ ์‚ฌ์šฉ์ž๊ฐ€ /about ๋˜๋Š” /about/ ์–ด๋А ์ชฝ์œผ๋กœ ์ ‘๊ทผํ•˜๋”๋ผ๋„, ๊ฒ€์ƒ‰ ์—”์ง„๊ณผ ๋ถ„์„ ํˆด์€ https://yourdomain.com/about์„ ์ •๊ทœ URL๋กœ ์ธ์‹ํ•ฉ๋‹ˆ๋‹ค.

์žฅ์ ๊ณผ ์ฃผ์˜์‚ฌํ•ญ

์žฅ์ 

  1. ๋น„์šฉ ์ ˆ๊ฐ: ์„œ๋ฒ„ ์—†์ด ์ •์  ํ˜ธ์ŠคํŒ…๋งŒ์œผ๋กœ ์šด์˜ (Cloudflare Pages, Netlify, AWS S3 + CloudFront ๋“ฑ ํ™œ์šฉ)
  2. ๋น ๋ฅธ ๋กœ๋”ฉ: ์ฃผ์š” ํŽ˜์ด์ง€๋Š” ๋ฏธ๋ฆฌ ๋ Œ๋”๋ง๋˜์–ด ์žˆ์–ด ์ฆ‰์‹œ ํ‘œ์‹œ
  3. SEO ์ตœ์ ํ™”: prerender๋œ ํŽ˜์ด์ง€๋Š” ๊ฒ€์ƒ‰ ์—”์ง„์ด ์™„์ „ํ•œ HTML์„ ํฌ๋กค๋ง ๊ฐ€๋Šฅ
  4. ์œ ์—ฐ์„ฑ: ํ•„์š”ํ•œ ํŽ˜์ด์ง€๋งŒ ์„ ํƒ์ ์œผ๋กœ SSG ์ ์šฉ
  5. ๊ฐ„๋‹จํ•œ ๋ฐฐํฌ: build/client ํด๋”๋งŒ ์—…๋กœ๋“œํ•˜๋ฉด ๋

์ฃผ์˜์‚ฌํ•ญ

  1. loader ํ•„์ˆ˜: prerenderํ•˜๊ณ  ์‹ถ์€ ๋ชจ๋“  ํŽ˜์ด์ง€์— loader ์ถ”๊ฐ€ (๋นˆ ํ•จ์ˆ˜๋ผ๋„)
  2. ๋นŒ๋“œ ํƒ€์ž„ ์ฆ๊ฐ€: prerenderํ•  ํŽ˜์ด์ง€๊ฐ€ ๋งŽ์„์ˆ˜๋ก ๋นŒ๋“œ ์‹œ๊ฐ„ ์ฆ๊ฐ€
  3. ๋™์  ๋ฐ์ดํ„ฐ ์ œํ•œ: ๋นŒ๋“œ ํƒ€์ž„์— ๊ฒฐ์ •๋˜๋ฏ€๋กœ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ๋Š” ํด๋ผ์ด์–ธํŠธ์—์„œ fetch ํ•„์š”
  4. 404 ์„ค์ • ํ•„์ˆ˜: ํ˜ธ์ŠคํŒ… ์„œ๋น„์Šค์˜ fallback ์„ค์ • ๋ฐ˜๋“œ์‹œ ํ•„์š”
  5. ์„œ๋ฒ„ ํ•จ์ˆ˜ ํ™œ์šฉ ๊ธˆ์ง€: ssr: false์ผ ๋•Œ๋Š” prerender๊ฐ€ ์•„๋‹Œ ํŽ˜์ด์ง€์—์„œ ์„œ๋ฒ„ ํ•จ์ˆ˜ ์‚ฌ์šฉ ๋ถˆ๊ฐ€

์–ธ์ œ ์ด ํŒจํ„ด์„ ์‚ฌ์šฉํ• ๊นŒ?

์ด ํŒจํ„ด์ด ์ ํ•ฉํ•œ ๊ฒฝ์šฐ

  • ๋งˆ์ผ€ํŒ… ์‚ฌ์ดํŠธ + ์›น ์•ฑ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ
  • ์ผ๋ถ€ ํŽ˜์ด์ง€๋งŒ SEO๊ฐ€ ์ค‘์š”ํ•œ ๊ฒฝ์šฐ
  • ์„œ๋ฒ„ ์šด์˜์„ ์•ˆํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ
  • ์ •์  ํ˜ธ์ŠคํŒ…์˜ ์žฅ์ (CDN, ์บ์‹ฑ ๋“ฑ)์„ ํ™œ์šฉํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ

๋Œ€์•ˆ์„ ๊ณ ๋ คํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ

  • ๋ชจ๋“  ํŽ˜์ด์ง€๊ฐ€ ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ์— ์˜์กดํ•˜๋Š” ๊ฒฝ์šฐ
  • ํŽ˜์ด์ง€๊ฐ€ ์ˆ˜๋ฐฑ~์ˆ˜์ฒœ ๊ฐœ์ธ ๊ฒฝ์šฐ (๋นŒ๋“œ ์‹œ๊ฐ„ ๋ฌธ์ œ)
  • ์‚ฌ์šฉ์ž ์ธ์ฆ์ด ํ•„์š”ํ•œ ํŽ˜์ด์ง€๊ฐ€ ๋Œ€๋ถ€๋ถ„์ธ ๊ฒฝ์šฐ

๋งˆ์น˜๋ฉฐ

React Router 7์˜ ssr: false + prerender ์กฐํ•ฉ์€ ๊ฐ•๋ ฅํ•œ ํŒจํ„ด์ž…๋‹ˆ๋‹ค. ์„œ๋ฒ„ ์—†์ด๋„ SEO์™€ ์„ฑ๋Šฅ์„ ๋ชจ๋‘ ์žก์„ ์ˆ˜ ์žˆ๊ณ , ํ•„์š”ํ•œ ๊ณณ์—๋งŒ SSG๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์—ฐ์„ฑ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ฒ˜์Œ์—๋Š” โ€œ์™œ prerender๊ฐ€ ์•ˆ ๋˜์ง€?โ€๋ผ๋ฉฐ ์‚ฝ์งˆํ–ˆ์ง€๋งŒ, loader์˜ ์—ญํ• ์„ ์ดํ•ดํ•˜๊ณ  ๋‚˜๋‹ˆ ๋ชจ๋“  ๊ฒŒ ๋ช…ํ™•ํ•ด์กŒ์Šต๋‹ˆ๋‹ค. ๋นˆ loader ํ•˜๋‚˜๋กœ ๋นŒ๋“œ ์‹œ์Šคํ…œ์—๊ฒŒ โ€œ์ด ํŽ˜์ด์ง€๋Š” ๋ฏธ๋ฆฌ ๋ Œ๋”๋งํ•ด์ค˜โ€ ๋ผ๊ณ  ์‹ ํ˜ธ๋ฅผ ๋ณด๋‚ด๋Š” ๊ฒƒ์ด์ฃ .

์—ฌ๊ธฐ์— canonical tag๊นŒ์ง€ ์ถ”๊ฐ€ํ•˜๋ฉด SEO์™€ ๋ถ„์„ ๋ฐ์ดํ„ฐ๊นŒ์ง€ ๊น”๋”ํ•˜๊ฒŒ ์ •๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ํŒจํ„ด์„ ํ™œ์šฉํ•ด๋ณด์„ธ์š”. ํŠนํžˆ ์„œ๋น„์Šค ์†Œ๊ฐœ ํŽ˜์ด์ง€๋‚˜ ๋งˆ์ผ€ํŒ… ์‚ฌ์ดํŠธ๋ฅผ ๋งŒ๋“ค ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค


์ฐธ๊ณ  ์ž๋ฃŒ