Skip to content

rlacodud/front_7th_chapter4-1

ย 
ย 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

28 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

๊ณผ์ œ ์ฒดํฌํฌ์ธํŠธ

๋ฐฐํฌ ๋งํฌ

๊ธฐ๋ณธ๊ณผ์ œ (Vanilla SSR & SSG) ์‹ฌํ™”๊ณผ์ œ (React SSR & SSG)

๊ธฐ๋ณธ๊ณผ์ œ (Vanilla SSR & SSG)

Express SSR ์„œ๋ฒ„

  • Express ๋ฏธ๋“ค์›จ์–ด ๊ธฐ๋ฐ˜ ์„œ๋ฒ„ ๊ตฌํ˜„
  • ๊ฐœ๋ฐœ/ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ ๋ถ„๊ธฐ ์ฒ˜๋ฆฌ
  • HTML ํ…œํ”Œ๋ฆฟ ์น˜ํ™˜ (<!--app-html-->, <!--app-head-->)

์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง

  • ์„œ๋ฒ„์—์„œ ๋™์ž‘ํ•˜๋Š” Router ๊ตฌํ˜„
  • ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ ํ”„๋ฆฌํŽ˜์นญ (์ƒํ’ˆ ๋ชฉ๋ก, ์ƒํ’ˆ ์ƒ์„ธ)
  • ์„œ๋ฒ„ ์ƒํƒœ๊ด€๋ฆฌ ์ดˆ๊ธฐํ™”

ํด๋ผ์ด์–ธํŠธ Hydration

  • window.__INITIAL_DATA__ ์Šคํฌ๋ฆฝํŠธ ์ฃผ์ž…
  • ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ ๋ณต์›
  • ์„œ๋ฒ„-ํด๋ผ์ด์–ธํŠธ ๋ฐ์ดํ„ฐ ์ผ์น˜

Static Site Generation

  • ๋™์  ๋ผ์šฐํŠธ SSG (์ƒํ’ˆ ์ƒ์„ธ ํŽ˜์ด์ง€๋“ค)
  • ๋นŒ๋“œ ํƒ€์ž„ ํŽ˜์ด์ง€ ์ƒ์„ฑ
  • ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ธฐ๋ฐ˜ ๋ฐฐํฌ

์‹ฌํ™”๊ณผ์ œ (React SSR & SSG)

React SSR

  • renderToString ์„œ๋ฒ„ ๋ Œ๋”๋ง
  • TypeScript SSR ๋ชจ๋“ˆ ๋นŒ๋“œ
  • Universal React Router (์„œ๋ฒ„/ํด๋ผ์ด์–ธํŠธ ๋ถ„๊ธฐ)
  • React ์ƒํƒœ๊ด€๋ฆฌ ์„œ๋ฒ„ ์ดˆ๊ธฐํ™”

React Hydration

  • Hydration ๋ถˆ์ผ์น˜ ๋ฐฉ์ง€
  • ํด๋ผ์ด์–ธํŠธ ์ƒํƒœ ๋ณต์›

Static Site Generation

  • ๋™์  ๋ผ์šฐํŠธ SSG (์ƒํ’ˆ ์ƒ์„ธ ํŽ˜์ด์ง€๋“ค)
  • ๋นŒ๋“œ ํƒ€์ž„ ํŽ˜์ด์ง€ ์ƒ์„ฑ
  • ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ธฐ๋ฐ˜ ๋ฐฐํฌ

์•„ํ•˜! ๋ชจ๋จผํŠธ (A-ha! Moment)

1. SSR VS SSG VS CSR

SSR, SSG, CSR์˜ ๋ณธ์งˆ์ ์ธ ์ฐจ์ด๋Š” HTML์„ ๋ˆ„๊ฐ€, ์–ธ์ œ, ์–ด๋–ค ์ฑ…์ž„์œผ๋กœ ์ƒ์„ฑํ•˜๋А๋ƒ์ด๋‹ค.

(1) ์„œ๋ฒ„ VS ํด๋ผ์ด์–ธํŠธ

(1-1) ์„œ๋ฒ„

  • ์š”์ฒญ์„ ๋ฐ›๋Š” ์ฃผ์ฒด
  • ๋ฐ์ดํ„ฐ ์กฐํšŒ ๊ฐ€๋Šฅ
  • HTML ๋ฌธ์ž์—ด์„ ๋งŒ๋“ค์–ด์„œ ๋‚ด๋ ค์ค„ ์ˆ˜ ์žˆ์Œ
  • ๊ฒฐ๊ณผ๋ฌผ์— ์ฑ…์ž„์„ ์ง

(1-2) ํด๋ผ์ด์–ธํŠธ

  • ์„œ๋ฒ„๊ฐ€ ์ค€ ๊ฑธ ๋ฐ›์•„์„œ ์‹คํ–‰
  • DOM์„ ๋งŒ๋“ค๊ณ  JS๋ฅผ ์‹คํ–‰
  • ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์ฒ˜๋ฆฌ
  • HTML์„ ์กฐ๋ฆฝํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •

(2) HTML ์ƒ์„ฑ ์‹œ์ ์œผ๋กœ ๋น„๊ต

(2-1) SSG

  • ๋นŒ๋“œ ํƒ€์ž„
  • HTML ํŒŒ์ผ ์ƒ์„ฑ
  • CDN / ์„œ๋ฒ„์— ์ €์žฅ
  • ์š”์ฒญ ์‹œ ํŒŒ์ผ ์ „๋‹ฌ HTML์€ ์ด๋ฏธ ๋งŒ๋“ค์–ด์ ธ์žˆ๊ณ  => ์„œ๋ฒ„๋Š” ํด๋ผ์ด์–ธํŠธํ•œํ…Œ ํŒŒ์ผ์„ ์ „๋‹ฌํ•˜์—ฌ => ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฐ›์•„์„œ ๊ทธ๋ฆฌ๊ธฐ๋งŒ ํ•œ๋‹ค. ์ฆ‰, SSG๋Š” ๋นŒ๋“œ ํƒ€์ž„์— ๋๋‚œ SSR์ด๋ผ๊ณ  ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค!

(2-2) SSR

  • ์š”์ฒญ ๋ฐœ์ƒ
  • ์„œ๋ฒ„๊ฐ€ ๋ฐ์ดํ„ฐ ์กฐํšŒ
  • HTML ๋ฌธ์ž์—ด ์ƒ์„ฑ
  • ์‘๋‹ต์œผ๋กœ ์ „๋‹ฌ HTML์„ ์š”์ฒญ ์‹œ์ ์— ์„œ๋ฒ„๊ฐ€ ์ƒ์„ฑํ•ด์„œ => ์„œ๋ฒ„๋Š” ๋งค ์š”์ฒญ๋งˆ๋‹ค ๊ณ„์‚ฐํ•˜๊ธฐ ๋•Œ๋ฌธ์— => ์‚ฌ์šฉ์ž๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋‹ค.

(2-3) CSR

  • ์š”์ฒญ ๋ฐœ์ƒ
  • ๋นˆ HTML + JS ๋‹ค์šด๋กœ๋“œ
  • ๋ธŒ๋ผ์šฐ์ €์—์„œ JS ์‹คํ–‰
  • DOM ์ƒ์„ฑ
  • ์„œ๋ฒ„๋Š” ํ™”๋ฉด์˜ ์‹ค์ œ ์ฝ˜ํ…์ธ  HTML ์ƒ์„ฑ์—๋Š” ๊ด€์—ฌํ•˜์ง€ ์•Š๊ณ  => ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ง์ ‘ HTML ๊ตฌ์กฐ๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ๋ฐ์ดํ„ฐ fetch๋„ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ•œ๋‹ค.

(3) ๋น„์œ  ์‹œ๊ฐ„

SSG๋Š” ํŽธ์˜์  ๋„์‹œ๋ฝ์œผ๋กœ, ์ „์ž๋ ˆ์ธ์ง€์— ๋ฐ์šฐ๋ฉด ๋ฐ”๋กœ ๋จน์„ ์ˆ˜ ์žˆ๊ณ  ์š”๋ฆฌํ•˜๋Š” ๊ณผ์ •์€ ์ด๋ฏธ ์™„๋ฃŒ๋˜์–ด์žˆ๋‹ค. SSR์€ ์‹ค๋น„์ง‘์œผ๋กœ, ์ฃผ๋ฌธ์ด ๋“ค์–ด์˜ค๋ฉด ๊ทธ ๋•Œ ๋ฐ”๋กœ ์š”๋ฆฌ๋ฅผ ํ•˜๋Š”๋ฐ ์š”์ฒญ๋งˆ๋‹ค ๋‹ค๋ฅธ ๋ฉ”๋‰ด๋ฅผ ์ œ๊ณตํ•ด์ค€๋‹ค. CSR์€ ์ง์ ‘ ์š”๋ฆฌํ•˜๋Š” ๊ฒƒ์œผ๋กœ, ์žฌ๋ฃŒ๋งŒ ๋งˆํŠธ์—์„œ ์‚ฌ์˜ค๊ณ  ์ง‘์—์„œ ์ง์ ‘ ์กฐ๋ฆฌํ•œ๋‹ค. CDN์€ ๋„์‹ฌ ๊ณณ๊ณณ์— ๋ฐฐ์น˜๋œ ํŽธ์˜์ ๊ฐ™์€ ์ค‘๊ฐ„ ํ”ฝ์—… ํ—ˆ๋ธŒ๋‹ค.

์ˆ˜๋ฒ”๋‹˜์ด๋ž‘ ์–˜๊ธฐํ•˜๋ฉด์„œ ๋น„์œ ์˜ ํ™•์žฅ์„ ์ง„ํ–‰ํ•ด๋ณด์•˜๋‹ค.

(3-1) SSG ํŽธ์˜์  ๋„์‹œ๋ฝ์˜ ์žฅ์ ์€ ์ด๋ฏธ ๋งŒ๋“ค์–ด์ ธ์žˆ์–ด์„œ(๋นŒ๋“œ ํƒ€์ž„ + HTML ํŒŒ์ผ ์ƒ์„ฑ) ํŽธ์˜์ ์— ๋น„์น˜๋˜์–ด์žˆ๊ณ (CDN / ์„œ๋ฒ„์— ์ €์žฅ) ๋จน๊ณ ์‹ถ์„ ๋•Œ ๊ตฌ๋งคํ•˜๊ณ (์š”์ฒญ ๋ฐœ์ƒ) ๊ทธ๋ƒฅ ๊ทธ๋Œ€๋กœ ์ „์ž๋ ˆ์ธ์ง€์— ๋ฐ์›Œ๋จน์œผ๋ฉด ์ข‹๋‹ค(ํŒŒ์ผ ์ „๋‹ฌ)๋Š” ์ ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋‚ด๊ฐ€ ๋งŒ์•ฝ ํŽธ์˜์  ๋„์‹œ๋ฝ์— ๊ณ„๋ž€๋ง์ด๋ฅผ ์›ํ•œ๋‹ค ํ•ด๋„ ๊ทธ๊ฑด ์ถ”๊ฐ€๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. ์ฆ‰, ์ƒˆ๋กœ์šด ์š”์ฒญ์€ ๋ฐ›์„ ์ˆ˜ ์žˆ์ง€๋งŒ ์š”์ฒญ๋งˆ๋‹ค ๋‹ค๋ฅธ ๊ฒฐ๊ณผ๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜๋Š” ์—†๋‹ค.

(3-2) SSR ์‹ค๋น„์ง‘์€ ๋‚ด๊ฐ€ ๊น€์น˜๋ณถ์Œ๋ฐฅ์ด ๋จน๊ณ  ์‹ถ๋‹ค๊ณ  ์ฃผ๋ฌธํ•˜๋ฉด(์š”์ฒญ ๋ฐœ์ƒ) ์‚ฌ์žฅ๋‹˜์ด ์ฃผ๋ฌธ์„ ๋ฐ›๊ณ (์„œ๋ฒ„๊ฐ€ ๋ฐ์ดํ„ฐ ์กฐํšŒ) ๊น€์น˜๋ณถ์Œ๋ฐฅ์„ ๋งŒ๋“ค์–ด์ฃผ์‹œ๊ณ (HTML ๋ฌธ์ž์—ด ์ƒ์„ฑ) ๋‚ด ํ…Œ์ด๋ธ”๋กœ ๊ฐ–๋‹ค์ฃผ์‹ ๋‹ค.(์‘๋‹ต์œผ๋กœ ์ „๋‹ฌ) ์ฃผ๋ฌธํ•˜๋Š”๋Œ€๋กœ ๋จน์„ ์ˆ˜ ์žˆ์–ด์„œ ์ข‹๋‹ค!! ํ•˜์ง€๋งŒ ์‚ฌ์žฅ๋‹˜์ด ์š”์ฒญ์„ ๋ฐ›๊ณ  ์š”๋ฆฌ๋ฅผ ํ•ด์ฃผ์‹œ๋Š” ๋ฐ์— ์‹œ๊ฐ„์ด ๊ฑธ๋ ค์„œ ๊ทธ๋งŒํผ์˜ ๋”œ๋ ˆ์ด๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฑด ์•„์‰ฝ๋‹คใ…œ

(3-3) CSR ์š”๋ฆฌ๋Š” ๋‚ด๊ฐ€ ๊น€์น˜๋ณถ์Œ๋ฐฅ์„ ๋จน๊ณ  ์‹ถ์œผ๋ฉด(์š”์ฒญ ๋ฐœ์ƒ) ํ•„์š”ํ•œ ์žฌ๋ฃŒ์ธ ๊น€์น˜, ๋ฐฅ, ๊ฐ„์žฅ, ์„คํƒ• ๋“ฑ์„ ๋งˆํŠธ์—์„œ ์‚ฌ์„œ(๋นˆ HTML + JS ๋‹ค์šด๋กœ๋“œ) ์ง‘์—์„œ ๋ ˆ์‹œํ”ผ๋Œ€๋กœ ์š”๋ฆฌํ•˜๊ณ (๋ธŒ๋ผ์šฐ์ €์—์„œ JS ์‹คํ–‰) ๊น€์น˜๋ณถ์Œ๋ฐฅ์„ ์™„์„ฑ(DOM ์ƒ์„ฑ)ํ•ด์„œ ๋จน์„ ์ˆ˜ ์žˆ๋‹ค. ๋Œ€์‹  ๋งˆํŠธ์—์„œ ์žฅ๋ณด๊ณ  ์š”๋ฆฌํ•˜๋Š” ๋ฐ ์‹œ๊ฐ„์ด ๊ฝค ์†Œ์š”๋œ๋‹คใ…œ

(3-4) CDN ํ”ฝ์—… ํ—ˆ๋ธŒ๋Š” ์™„์ œํ’ˆ์ด๋‚˜ ์žฌ๋ฃŒ๋ฅผ ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ๊ณณ์—์„œ ๋น ๋ฅด๊ฒŒ ์ „๋‹ฌํ•ด์ฃผ๋Š” ์ค‘๊ฐ„ ๊ฑฐ์ ์ด๋‹ค.

2. Hydration์˜ ์ค‘์š”์„ฑ

์ด๋ฒˆ ๊ณผ์ œ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉฐ ๊ฐ€์žฅ ํฌ๊ฒŒ ์ฒด๊ฐํ•œ ๋˜ ํ•˜๋‚˜์˜ ํฌ์ธํŠธ๋Š” SSR/SSG์—์„œ ํ™”๋ฉด์„ โ€œ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒโ€๋ณด๋‹ค, ๊ทธ ์ดํ›„์˜ Hydration์ด ํ›จ์”ฌ ์ค‘์š”ํ•˜๋‹ค๋Š” ์ ์ด์—ˆ๋‹ค.

์„œ๋ฒ„์—์„œ HTML์„ ๋‚ด๋ ค์ฃผ๋ฉด ์‚ฌ์šฉ์ž๋Š” ์ฆ‰์‹œ ์ฝ˜ํ…์ธ ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด ์ƒํƒœ์˜ ํ™”๋ฉด์€ ์•„์ง ์ •์ ์ธ HTML์ผ ๋ฟ, ์‹ค์ œ ์‚ฌ์šฉ์ž ์ƒํ˜ธ์ž‘์šฉ์€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค.

์ดํ›„ ํด๋ผ์ด์–ธํŠธ์—์„œ Javascript๊ฐ€ ์‹คํ–‰๋˜๋ฉฐ ์„œ๋ฒ„์—์„œ ๋‚ด๋ ค์˜จ HTML๊ณผ ๋™์ผํ•œ ์ƒํƒœ๋กœ React/Vainlla ์•ฑ์ด ๋ณต์›๋˜๋Š” ๊ณผ์ •์„ Hydration์ด๋ผ๊ณ  ํ•œ๋‹ค.

์ด ๊ณผ์ •์—์„œ ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ์˜ ์ƒํƒœ๋‚˜ ๋งˆํฌ์—…์ด ์กฐ๊ธˆ์ด๋ผ๋„ ์–ด๊ธ‹๋‚˜๋ฉด

  • ํ™”๋ฉด ๊นœ๋นก์ž„
  • ์ด๋ฒคํŠธ ๋ฐ”์ธ๋”ฉ ์‹คํŒจ
  • ์ฝ˜์†” ๊ฒฝ๊ณ (hydration mismatch) ์™€ ๊ฐ™์€ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋ฒˆ ๊ณผ์ œ์—์„œ window.__INITIAL_DATA__๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„ ์ƒํƒœ๋ฅผ ์ „๋‹ฌํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ์—์„œ ๋™์ผํ•œ ์ดˆ๊ธฐ ์ƒํƒœ๋กœ ๋ณต์›ํ•˜๋Š” ์ž‘์—…์„ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋ฉด์„œ SSR/SSG์˜ ํ•ต์‹ฌ์€ โ€œHTML์„ ๋นจ๋ฆฌ ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒโ€์ด ์•„๋‹ˆ๋ผ โ€œ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ์˜ ์ƒํƒœ๋ฅผ ์ •ํ™•ํžˆ ์ผ์น˜์‹œํ‚ค๋Š” ๊ฒƒโ€์ด๋ผ๋Š” ์ ์„ ๋ช…ํ™•ํžˆ ์ดํ•ดํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

3. ์ „์ฒด์ ์ธ ํ๋ฆ„

์ „ํ†ต์ ์ธ ์›น ๊ฐœ๋ฐœ ๋ฐฉ์‹์€ SSR์ด์—ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ Javascript๊ฐ€ ์ ์  ๋ฐœ์ „ํ•˜๋ฉด์„œ Javascript๋กœ ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์ด ๋งŽ์•„์ง€๊ฒŒ ๋˜์—ˆ๊ณ  ๊ทธ๋Ÿฌ๋ฉด์„œ ํŒŒ์ƒ๋œ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ๋“ฑ์žฅํ•˜๋ฉด์„œ ๋ชจ๋“  ๋ Œ๋”๋ง์„ ์ „๋ถ€ ๋ธŒ๋ผ์šฐ์ €(ํด๋ผ์ด์–ธํŠธ)์—๊ฒŒ ์œ„์ž„ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

๊ทธ๋กœ ์ธํ•ด ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋“ค์ด CSR์„ ์ฃผ๋กœ ๋‹ค๋ฃจ๊ฒŒ ๋˜์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ CSR์€ ์œ„์—์„œ ๋‹ค๋ค˜๋“ฏ SEO ์ตœ์ ํ™” ๋ฌธ์ œ๋กœ ์ธํ•ด ์„œ๋น„์Šค์ ์ธ ํ•œ๊ณ„๊ฐ€ ์กด์žฌํ–ˆ๊ณ  ๋‹ค์‹œ SSR์ด ํ•„์š”ํ•ด์ง€๊ฒŒ ๋˜์—ˆ๋‹ค.

์ฆ‰, ์ง€๊ธˆ๊นŒ์ง€์˜ ํ๋ฆ„์€ SSR => CSR => SSR+CSR์ธ ๊ฒƒ์ด๋‹ค.

๋‹จ, ๋ชจ๋“  ์ƒํ™ฉ์— SSR์„ ์ ์šฉํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ๊ฒ€์ƒ‰์—”์ง„์˜ ์ตœ์ ํ™”๊ฐ€ ํ•„์š”ํ•  ๋•Œ, ์‚ฌ์šฉ์ž์—๊ฒŒ ๋น„์–ด์žˆ๋Š” ํ™”๋ฉด์—†์ด ๋น ๋ฅด๊ฒŒ ํŽ˜์ด์ง€๋ฅผ ๋ณด์—ฌ์ค˜์•ผํ•  ๋•Œ์—๋งŒ SSR์„ ์ ์šฉํ•˜๋ฉด ๋œ๋‹ค.

4. ๊ทธ ์™ธ์— ์ฒ˜์Œ ์ ‘ํ•œ ๊ฐœ๋…๋“ค

(1) ISR (Incremental Static Regeneration)

  • Next.js ๋“ฑ ์ตœ์‹  ํ”„๋ ˆ์ž„์›Œํฌ์—์„œ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์œผ๋กœ, ์ •์  ํŽ˜์ด์ง€๋ฅผ ํ•„์š”ํ•  ๋•Œ๋งŒ ๊ฐฑ์‹ ํ•œ๋‹ค.
  • ์ „์ฒด ์‚ฌ์ดํŠธ๋ฅผ ๋‹ค์‹œ ๋นŒ๋“œํ•˜์ง€ ์•Š๊ณ  ํŠน์ • ํŽ˜์ด์ง€๋งŒ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ์–ด, SSG์˜ ๋‹จ์ (์ •์ ์ด๋ผ ์—…๋ฐ์ดํŠธ ์–ด๋ ค์›€)์„ ๋ณด์™„ํ•œ๋‹ค.

(2) Edge Computing / Serverless

  • SSR์„ ๊ธ€๋กœ๋ฒŒ ๊ทœ๋ชจ๋กœ ๋น ๋ฅด๊ฒŒ ์ œ๊ณตํ•˜๋ ค๋ฉด ์„œ๋ฒ„๋ฅผ ์ค‘์•™์— ๋‘๊ธฐ๋ณด๋‹ค๋Š” ์‚ฌ์šฉ์ž ๊ฐ€๊นŒ์šด ์—ฃ์ง€ ์œ„์น˜์—์„œ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.
  • AWS Lambda@Edge, Vercel Edge Functions, Cloudflare Workers ๋“ฑ์ด ๋Œ€ํ‘œ์ ์ด๋‹ค. (์œ„ ๊ฐœ๋…์€ ์–ด๋ ดํ’‹์ด ๋“ค์–ด๋ด์™”๊ณ  ์ •ํ™•ํ•œ ์ด๋ฆ„์€ ์ฒ˜์Œ ์•ˆ ๊ฒƒ ๊ฐ™๋‹ค.)

(3) Streaming SSR

  • ์„œ๋ฒ„๊ฐ€ HTML์„ ํ•œ ๋ฒˆ์— ๋‹ค ๊ทธ๋ ค์„œ ๋ณด๋‚ด๋Š” ๋Œ€์‹ , ์กฐ๊ฐ ๋‹จ์œ„๋กœ ์ŠคํŠธ๋ฆฌ๋ฐํ•ด ์‚ฌ์šฉ์ž์—๊ฒŒ ๋” ๋น ๋ฅด๊ฒŒ ์ฒซ ํ™”๋ฉด์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ธฐ๋ฒ•.
  • React 18, Next.js, Remix ๋“ฑ์ด ์ง€์›. ํŠนํžˆ ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฌด๊ฒ๊ฑฐ๋‚˜ ๋น„๋™๊ธฐ ํ˜ธ์ถœ์ด ๋งŽ์€ ๊ฒฝ์šฐ ์œ ๋ฆฌ.

์ž์œ ๋กญ๊ฒŒ ํšŒ๊ณ ํ•˜๊ธฐ

๐Ÿ˜Ž ๊ณผ์ œ ์ง„ํ–‰ ๊ณผ์ •

์ผ๋‹จ ๊ณผ์ œ์˜ ๋ณธ์งˆ์— ๋Œ€ํ•ด ์ดํ•ดํ•˜๋Š” ์‹œ๊ฐ„๋ถ€ํ„ฐ ๊ฐ€์กŒ๋‹ค. ๋ฐœ์ œ ๋…ธ์…˜๊ณผ ์ค€์ผ ์ฝ”์น˜๋‹˜์˜ ์ด์ „ ๋ธ”๋กœ๊ทธ ๊ธ€์„ ๋ณด์•˜์„ ๋•Œ ์ด๋ฒˆ ๊ณผ์ œ์—์„œ ์š”๊ตฌํ•˜๋Š” ๋ฐ”๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.

์„œ๋ฒ„๋ฅผ ์ง์ ‘ ๊ตฌ์ถ•ํ•œ ๋’ค, ์ด ํŽ˜์ด์ง€๋Š” SSR, ์ด ํŽ˜์ด์ง€๋Š” SSG, ์–ด๋–ค ์˜์—ญ์€ CSR์ด๋ผ๋Š” ํŒ๋‹จ ๊ทผ๊ฑฐ๋ฅผ ๊ฐ€์ง€๊ณ 
๊ฐ ๋ Œ๋”๋ง ๋ฐฉ์‹์„ ์‹ค์ œ๋กœ ๊ตฌํ˜„ํ•˜๊ณ  ์—ฐ๊ฒฐ

์ฆ‰, ๊ตฌํ˜„ ์ž์ฒด๋„ ์ค‘์š”ํ•˜์ง€๋งŒ ๊ทธ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์™œ ๊ฐ ์˜์—ญ์— ๊ฐ ๋ฐฉ์‹์„ ๋„์ž…ํ•˜๊ณ ์ž ํ–ˆ๋Š”์ง€์— ๋Œ€ํ•ด ์‚ฌ๊ณ ํ•˜๊ณ  ํŒ๋‹จํ•  ์ค„ ์•„๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค.

(1) ๊ฐœ๋… ์ •๋ฆฌ

๋Š˜ ๊ทธ๋ ‡๋“ฏ ๊ฐ ๊ฐœ๋…์— ๋Œ€ํ•ด ๋น„์œ ๊นŒ์ง€ ๊ฐ€๋Šฅํ•  ์ •๋„๋กœ ์ดํ•ดํ•˜๊ณ  ์ •๋ฆฌํ•˜๋Š” ์‹œ๊ฐ„์„ ๊ฐ€์กŒ๋‹ค. ์ด ๋•Œ ์ˆ˜๋ฒ”๋‹˜๊ณผ ๋น„์œ  ๋‚ด์šฉ์„ ๊ณต์œ ํ•˜๋ฉฐ ์ƒ๊ฐ์˜ ํ™•์žฅ๊ณผ ํ”ผ๋“œ๋ฐฑ์„ ์ฃผ๊ณ ๋ฐ›์€ ๊ฒŒ ๋„์›€๋˜์—ˆ๋‹ค.

(2) ์„œ๋ฒ„ ๊ตฌํ˜„

๊ณผ์ œ TODO๋ฅผ ์ˆœ์ฐจ์ ์œผ๋กœ ์ง„ํ–‰ํ•˜์—ฌ ์„œ๋ฒ„ ๊ตฌํ˜„์„ ์ฒซ๋ฒˆ์งธ๋กœ ์ง„ํ–‰ํ–ˆ๋‹ค.

์ฝ”์น˜๋‹˜์ด ๋ผ์ด๋ธŒ ์ฝ”๋”ฉ์œผ๋กœ ๋ณด์—ฌ์ฃผ์…จ๋˜ ๋ฐฉ์‹์„ ํ™œ์šฉํ•˜์—ฌ ์„œ๋ฒ„ ๊ตฌํ˜„์„ ํ–ˆ๋Š”๋ฐ vite์—์„œ ์ œ๊ณตํ•œ SSR ๊ด€๋ จ ์ฝ”๋“œ๋ฅผ ๋ณต๋ถ™ํ•˜๋‹ค๋ณด๋‹ˆ ๋ชจ๋ฅด๋Š” ํ‚ค์›Œ๋“œ๋„ ์žˆ์–ด์„œ ์ฐพ์•„๋ณด๊ณ  ์ •๋ฆฌํ–ˆ๋‹ค.

(2-1) compression ๋ง ๊ทธ๋Œ€๋กœ HTTP ์‘๋‹ต์„ ์••์ถ•ํ•˜๋Š” ์šฉ๋„๋กœ ์‚ฌ์šฉ๋˜๋Š” Express ๋ฏธ๋“ค์›จ์–ด๋‹ค. HTML, JS, CSS๋Š” ํ…์ŠคํŠธ ํŒŒ์ผ์ด๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ๋Œ€๋กœ ๋ณด๋‚ด๋ฉด ์šฉ๋Ÿ‰์ด ์ปค์„œ ์ „์†ก ์ตœ์ ํ™”๋ฅผ ์œ„ํ•ด ์‚ฌ์šฉํ•œ๋‹ค.

const compression = (await import("compression")).default;
app.use(compression());

๊ทธ๋Ÿผ ์™œ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋Š” ์‚ฌ์šฉํ•˜์ง€ ์•Š์„๊นŒ? ๊ฐœ๋ฐœ ์„œ๋ฒ„๋Š” ๋น ๋ฅธ ์žฌ๋นŒ๋“œ, ๋””๋ฒ„๊น…, ์†Œ์Šค ํ™•์ธ์ด ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์••์ถ•ํ•˜๋Š” ๊ณผ์ •์€ ์˜คํžˆ๋ ค ๋””๋ฒ„๊น…์„ ๋ฐฉํ•ดํ•˜๊ฒŒ ๋˜์–ด ๋ฐฐํฌ ํ™˜๊ฒฝ์—์„œ๋งŒ ์‚ฌ์šฉํ•œ๋‹ค.

(2-2) sirv ์ •์  ํŒŒ์ผ์„ ์ „๋‹ฌํ•˜๋Š” ์ดˆ๊ฒฝ๋Ÿ‰ ์„œ๋ฒ„ ๋ฏธ๋“ค์›จ์–ด๋กœ, ./dist/vanilla์—์„œ ํŒŒ์ผ์„ ์ฐพ์•„์„œ ํŒŒ์ผ์ด ์žˆ์œผ๋ฉด ๊ทธ๋Œ€๋กœ ์‘๋‹ต์„ ๋ณด๋‚ธ๋‹ค.

app.use(base, sirv("./dist/vanilla", { extensions: [] }));

์˜ˆ๋ฅผ ๋“ค์–ด ์•„๋ž˜์™€ ๊ฐ™์ด ์š”์ฒญ์ด ์˜ค๋ฉด ์ง€์ •ํ•œ ๊ฒฝ๋กœ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํŒŒ์ผ์„ ์ฐพ์•„์„œ ์‘๋‹ต์„ ๋ณด๋‚ธ๋‹ค.

GET /assets/main.js  โ†’ dist/vanilla/assets/main.js
GET /style.css      โ†’ dist/vanilla/style.css

๋ฌด์—‡์˜ ์•ฝ์ž์ผ์ง€ ๊ถ๊ธˆํ•ด์„œ ์ฐพ์•„๋ณด๋‹ˆ ๋”ฑํžˆ ์•ฝ์ž๋Š” ์•„๋‹ˆ๊ณ  serve์™€ ๊ฐ™์€ ์˜๋ฏธ๋กœ, ๋นŒ๋“œ๋œ ์ •์  ํŒŒ์ผ ์„œ๋ฒ„๋ผ๊ณ  ์ƒ๊ฐํ•ด์ฃผ๋ฉด ๋  ๊ฒƒ ๊ฐ™๋‹ค.

(3) ํ…Œ์ŠคํŠธ ์ง€์˜ฅ-๊ฐ€์žฅ ๊นจ๋‹ฌ์Œ์ด ์ปธ๋˜ ์ง€์ 

(3-1) ๋ฌธ์ œ์˜ ๋ฐœ๋‹จ ์‹œ์ž‘๋๋‹ค..ํ…Œ์ŠคํŠธ ์ง€์˜ฅ

๋™์ผํ•œ ํ…Œ์ŠคํŠธ๋ฅผ ์—ฌ๋Ÿฌ ํฌํŠธ์—์„œ ๋™์‹œ์— ์‹คํ–‰ํ•˜๋ฉด ํŠน์ • ํฌํŠธ์—์„œ๋Š” ๊ธฐ๋Œ€ํ•œ "์ด 340๊ฐœ" ๊ฐ™์€ ๋ฌธ์ž์—ด ๋Œ€์‹  TypeError, fetch ์—๋Ÿฌ, ํ˜น์€ MSW ๊ด€๋ จ ์—๋Ÿฌ ์Šคํƒ์ด HTML์— ๊ทธ๋Œ€๋กœ ์„ž์—ฌ ๋‚ด๋ ค์˜ค๊ณ , ๊ฒฐ๊ตญ expect(...).toContain("์ด") ๊ฐ™์€ assertion์ด ์‹คํŒจํ•˜๋Š” ํ˜„์ƒ์ด ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ฐœ์ƒํ–ˆ๋‹ค..

ํŠนํžˆ ํ…Œ์ŠคํŠธ๋ฅผ ํ•œ ๋ฒˆ๋งŒ ์ˆœ์ฐจ์ ์œผ๋กœ ๋Œ๋ฆด ๋•Œ๋Š” ์ž˜ ํ†ต๊ณผํ•˜๋Š”๋ฐ, Playwright๊ฐ€ ๋ณ‘๋ ฌ๋กœ ๋Œ๋ฆด ๋•Œ, ์—ฌ๋Ÿฌ ํฌํŠธ ์กฐํ•ฉ์„ ํ•จ๊ป˜ ๋Œ๋ฆด ๋•Œ ๋ถˆ์•ˆ์ •ํ•˜๊ฒŒ ๊นจ์ง€๋Š” ๊ฒƒ์ด ํŠน์ง•์ด์—ˆ๋‹ค.

  await this.page.waitForFunction(() => {
    const text = document.body.textContent;
    return text?.includes("์ด") && text?.includes("๊ฐœ");
  });

(3-2) ํ™˜๊ฒฝ ๊ตฌ์กฐ ์ดํ•ด ๏ปฟ๋ฌธ์ œ๋ฅผ ์ œ๋Œ€๋กœ ๋ณด๋ ค๋ฉด ํ™˜๊ฒฝ ๊ตฌ์„ฑ์„ ๋จผ์ € ์ดํ•ดํ•  ํ•„์š”๊ฐ€ ์žˆ์—ˆ๋‹ค.

Vanilla:
CSR: http://localhost:5173/
SSR: http://localhost:5174/
SSG: http://localhost:4173/front_7th_chapter4-1/vanilla/, 4174, 4178 ๋“ฑ
React:
CSR: http://localhost:5175/
SSR: http://localhost:5176/
SSG: http://localhost:4175/front_7th_chapter4-1/react/, 4176, 4179 ๋“ฑ

E2E ์ŠคํŽ™์€ ๊ฐ ํฌํŠธ๋ฅผ ๋ชจ๋‘ ํƒ€๊ฒŸ์œผ๋กœ ๊ฐ™์€ ์‚ฌ์šฉ์ž ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋ฐ˜๋ณต ์‹คํ–‰ํ•˜๋ฉฐ, ์‹ค์ œ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋Š” ์—†๊ณ  MSW๋กœ API๋ฅผ ๋ชจํ‚นํ•˜๊ณ  ์žˆ๋‹ค.

ํด๋ผ์ด์–ธํŠธ:
browser.ts + mockServiceWorker.js
์„œ๋ฒ„:
nodeServer.js / nodeServer.ts + msw/node์˜ setupServer(...handlers)

(3-3) MSW ์„œ๋ฒ„ ์ดˆ๊ธฐํ™”/๋ชจํ‚น ๋ฌธ์ œ?? ์ฆ์ƒ์„ ๋ณด๋ฉด ๊ณตํ†ต์ ์€ ๋‹ค์Œ๊ณผ ๊ฐ™์•˜๋‹ค.

  • ์‹คํŒจํ•  ๋•Œ HTML ์•ˆ์— ์ˆœ์ˆ˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์•„๋‹ˆ๋ผ ์—๋Ÿฌ ์Šคํƒ์ด ๋“ค์–ด ์žˆ์Œ
  • ํŠนํžˆ SSR/SSG ์—”๋“œํฌ์ธํŠธ(417x, 5174, 5176)์—์„œ ๋” ์ž์ฃผ ๋ฐœ์ƒ
  • MSW๊ฐ€ ์ œ๋Œ€๋กœ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š” ์ˆœ๊ฐ„์—๋Š” ๋ชจ๋“  ์ƒํ’ˆ/์นดํ…Œ๊ณ ๋ฆฌ ์š”์ฒญ์ด ์‹คํŒจ => E2E์˜ ํ…์ŠคํŠธ ๋งค์นญ ์‹คํŒจ

(3-4) Node ํ™˜๊ฒฝ์—์„œ์˜ MSW ๋™์ž‘ ๋ฐฉ์‹ ๊ฐ™์€ Node ํ”„๋กœ์„ธ์Šค ์•ˆ์—์„œ ์—ฌ๋Ÿฌ ์„œ๋ฒ„๊ฐ€ ๋Œ์•„๊ฐ€๋”๋ผ๋„ MSW๋Š” ์ „์—ญ์ ์œผ๋กœ ๋„คํŠธ์›Œํฌ ๊ณ„์ธต(fetch/http)์„ ํŒจ์น˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๋Ÿฌ ์„œ๋ฒ„์˜ ์š”์ฒญ์„ ๋™์ผํ•œ MSW ์ƒํƒœ๊ฐ€ ๊ณต์œ ํ•˜๊ฒŒ ๋œ๋‹ค.

ํ…Œ์ŠคํŠธ๋ฅผ ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ํ•˜๋ฉด ๊ฐ ์„œ๋ฒ„๊ฐ€ ์„œ๋กœ ๋‹ค๋ฅธ ํƒ€์ด๋ฐ์— MSW์˜ listen()์„ ํ˜ธ์ถœํ•˜๊ฒŒ ๋˜๊ณ  ์ผ๋ถ€ ์š”์ฒญ์€ MSW๊ฐ€ ํ™œ์„ฑํ™”๋˜๊ธฐ ์ด์ „์— ๋ฐœ์ƒํ•˜์—ฌ ์‹ค์ œ ๋„คํŠธ์›Œํฌ ์š”์ฒญ์œผ๋กœ ๋น ์งˆ ์ˆ˜ ์žˆ๋‹ค.

์ด ํƒ€์ด๋ฐ/์ „์—ญ ์ƒํƒœ ๋ฌธ์ œ ๋•Œ๋ฌธ์—, ํฌํŠธ/๋ชจ๋“œ(CSR, SSR, SSG) ์กฐํ•ฉ์— ๋”ฐ๋ผ ๊ฒฐ๊ณผ๊ฐ€ ๋“ค์ญ‰๋‚ ์ญ‰ํ–ˆ๋˜ ๊ฒƒ์ด๋‹ค.

(3-5) onUnhandledRequest: "bypass" ์ถ”๊ฐ€

mswServer.listen({
  onUnhandledRequest: "bypass",
});

์ด ์„ค์ •์ด ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

1. MSW๋Š” ํ•ญ์ƒ ์ผœ๋‘”๋‹ค

  • SSR/SSG ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์„œ๋ฒ„๊ฐ€ ๋œจ๋Š” ์‹œ์ ์— MSW๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ listen()
  • ์ตœ์†Œํ•œ โ€œ์„œ๋ฒ„๊ฐ€ ์ค€๋น„๋œ ํ›„ ๋“ค์–ด์˜ค๋Š” SSR ์š”์ฒญโ€์— ๋Œ€ํ•ด์„œ๋Š” ๋ชจํ‚น ์ผ๊ด€์„ฑ์ด ์˜ฌ๋ผ๊ฐ

2. ๋ชจํ‚นํ•˜์ง€ ์•Š์€ ์š”์ฒญ์€ ์‹ค ์„œ๋ฒ„๋กœ ๊ทธ๋ƒฅ ํ˜๋ ค๋ณด๋‚ธ๋‹ค

  • ๋“ฑ๋ก๋˜์ง€ ์•Š์€ ์—”๋“œํฌ์ธํŠธ, ์ •์  ๋ฆฌ์†Œ์Šค, ์˜ˆ์™ธ์ ์ธ ์š”์ฒญ๋“ค์ด ์žˆ์–ด๋„
  • ํ…Œ์ŠคํŠธ๋ฅผ ๊นจ๋œจ๋ฆฌ๋Š” ์—๋Ÿฌ๋ฅผ ๋˜์ง€์ง€ ์•Š๋Š”๋‹ค
  • SSR ๊ฒฐ๊ณผ HTML์— ๊ฐœ๋ฐœ์šฉ ์—๋Ÿฌ ํ…์ŠคํŠธ๊ฐ€ ์„ž์—ฌ ๋“ค์–ด์˜ค๋Š” ์ผ์„ ๋ฐฉ์ง€

๊ฒฐ๊ณผ์ ์œผ๋กœ SSR/SSG ํ…Œ์ŠคํŠธ์—์„œ API ์‘๋‹ต์ด ์•ˆ์ •์ ์œผ๋กœ ๋ชจํ‚น๋˜๊ธฐ ์‹œ์ž‘ํ–ˆ๊ณ  ์˜ˆ์™ธ์ ์ธ ์š”์ฒญ์ด ์—๋Ÿฌ๋ฅผ ์œ ๋ฐœํ•ด ํŽ˜์ด์ง€ ์ „์ฒด๋ฅผ ๋ง๊ฐ€๋œจ๋ฆฌ๋Š” ์ผ์ด ์ค„์–ด๋“ค๋ฉด์„œ createTests.ts๊ฐ€ ๊ธฐ๋Œ€ํ•˜๋Š” "์ด 340๊ฐœ" ๊ฐ™์€ ๋ฌธ๊ตฌ๋ฅผ ๋ชจ๋“  ํฌํŠธ ์กฐํ•ฉ์—์„œ ์ผ๊ด€๋˜๊ฒŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค.

(4) Vanilla VS React - ๊ฐ™์€ SSR, ์ „ํ˜€ ๋‹ค๋ฅธ ์ฑ…์ž„

๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋งŒ๋“ค์–ด๋‚ด์ง€๋งŒ, ๊ตฌํ˜„ ๊ณผ์ •์—์„œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ์ฑ…์ž„์ ธ์•ผ ํ•˜๋Š” ๋ฒ”์œ„๋Š” ์™„์ „ํžˆ ๋‹ฌ๋ž๋‹ค.

(4-1) SSR ๊ตฌํ˜„ ๋ฐฉ์‹์˜ ์ฐจ์ด

1๏ธโƒฃ Vanilla

Vanilla ํ™˜๊ฒฝ์—์„œ๋Š” SSR ๊ณผ์ •์ด ๋งค์šฐ ์ง๊ด€์ ์ด๋ฉด์„œ๋„, ๊ทธ๋งŒํผ ๋ชจ๋“  ์ฑ…์ž„์ด ๋ช…ํ™•ํžˆ ๋“œ๋Ÿฌ๋‚ฌ๋‹ค.

const result = await router.target(params);
return {
  html: result.html,
  __INITIAL_DATA__: result.data ?? {},
};
  • ํŽ˜์ด์ง€ ํ•จ์ˆ˜๊ฐ€ HTML ๋ฌธ์ž์—ด์„ ์ง์ ‘ ๋ฐ˜ํ™˜
  • ํ…œํ”Œ๋ฆฟ ๋ฆฌํ„ฐ๋Ÿด์„ ์ด์šฉํ•ด ๋ฌธ์ž์—ด ๊ธฐ๋ฐ˜ HTML ์ƒ์„ฑ
  • ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ๋Š” hydrateStoreFromSSR()๋ฅผ ํ†ตํ•ด ์Šคํ† ์–ด์— ์ง์ ‘ dispatch => HTML ์ƒ์„ฑ, ๋ฐ์ดํ„ฐ ์ฃผ์ž…, ์ƒํƒœ ์ „๋‹ฌ์„ ๋ชจ๋‘ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘ ๊ด€๋ฆฌ

2๏ธโƒฃ React

React SSR์—์„œ๋Š” renderToString์„ ํ†ตํ•ด ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ ์ „์ฒด๊ฐ€ ๊ทธ๋Œ€๋กœ ์„œ๋ฒ„์—์„œ ์‹คํ–‰๋œ๋‹ค.

htmlString = renderToString(
  <RouterProvider router={router}>
    <ProductProvider productStore={createProductStore(result || {})}>
      <App />
    </ProductProvider>
  </RouterProvider>
);
  • renderToString์œผ๋กœ ์ปดํฌ๋„ŒํŠธ ํŠธ๋ฆฌ๋ฅผ HTML ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜
  • JSX ๊ธฐ๋ฐ˜ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์„œ๋ฒ„/ํด๋ผ์ด์–ธํŠธ์—์„œ ๋™์ผํ•˜๊ฒŒ ์‚ฌ์šฉ
  • ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ๋Š” createProductStore(initData)๋ฅผ ํ†ตํ•ด Context์— ์ฃผ์ž… => SSR ํ๋ฆ„ ์ž์ฒด๊ฐ€ ์ปดํฌ๋„ŒํŠธ ๊ตฌ์กฐ ์•ˆ์œผ๋กœ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋…น์•„ ์žˆ์Œ

(4-2) Hydration ๋ฐฉ์‹์˜ ์ฐจ์ด

1๏ธโƒฃ Vanilla

Vanilla์—์„œ๋Š” hydration ์—ญ์‹œ ์ „์ ์œผ๋กœ ์ˆ˜๋™์ด๋‹ค.

productStore.dispatch({
  type: PRODUCT_ACTIONS.SETUP,
  payload: {
    products: initialData.products ?? [],
    categories: initialData.categories ?? {},
  },
});
  • ์„œ๋ฒ„ HTML์„ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜, ํ•„์š” ์‹œ ๋‹ค์‹œ ๋ Œ๋”๋ง
  • ๊ฐ ์Šคํ† ์–ด์— ์ดˆ๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ dispatch
  • ์ƒํƒœ ๋ณต์›๊ณผ DOM ์‚ฌ์šฉ ๋ฐฉ์‹ ๋ชจ๋‘ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ œ์–ด => hydration์€ โ€œ์ž๋™ ๊ณผ์ •โ€์ด ์•„๋‹ˆ๋ผ ๋ช…์‹œ์ ์œผ๋กœ ์„ค๊ณ„ํ•ด์•ผ ํ•˜๋Š” ๋‹จ๊ณ„๋ผ๋Š” ๊ฑธ ์ฒด๊ฐํ–ˆ๋‹ค.

2๏ธโƒฃ React

React์—์„œ๋Š” hydration ๊ณผ์ •์ด ์ƒ๋Œ€์ ์œผ๋กœ ๋‹จ์ˆœํ•ด์ง„๋‹ค.

const initData = window.__INITIAL_DATA__;
<ProductProvider productStore={createProductStore(initData || {})}>
  <App />
</ProductProvider>
  • hydrateRoot๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„ DOM์— ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋งŒ ์—ฐ๊ฒฐ
  • Context ์ดˆ๊ธฐํ™”๋กœ ์ƒํƒœ๊ฐ€ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ๋ณต์›
  • ํด๋ผ์ด์–ธํŠธ์—์„œ๋Š” ๋ฐ์ดํ„ฐ ์ •๋ฆฌ๋งŒ ์ˆ˜ํ–‰ => React๊ฐ€ hydration์˜ ๋ณต์žก์„ฑ์„ ํ”„๋ ˆ์ž„์›Œํฌ ์ฐจ์›์—์„œ ํก์ˆ˜ํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฑธ ์‹ค๊ฐํ–ˆ๋‹ค.

(4-3) ๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ ๋ฐฉ์‹์˜ ์ฐจ์ด

1๏ธโƒฃ Vanilla

// Vanilla ๋ผ์šฐํŒ…
import { router } from "./router";
const PageComponent = router.target;
rootElement.innerHTML = PageComponent();
  • ์ „์—ญ router ์ธ์Šคํ„ด์Šค๋ฅผ ์ง์ ‘ import
  • router.target, router.params์— ์ง์ ‘ ์ ‘๊ทผ
  • ๋ผ์šฐํ„ฐ ๋ณ€๊ฒฝ ์‹œ render ํ•จ์ˆ˜๋ฅผ ์ˆ˜๋™ ํ˜ธ์ถœ => ํ๋ฆ„์€ ๋ช…ํ™•ํ•˜์ง€๋งŒ, ๊ด€๋ฆฌ ํฌ์ธํŠธ๊ฐ€ ๋งŽ์Œ

2๏ธโƒฃ React

// React ๋ผ์šฐํŒ…
const router = useRouterContext();
const PageComponent = useCurrentPage();
return PageComponent ? <PageComponent /> : null;
  • RouterProvider๋กœ ๋ผ์šฐํ„ฐ๋ฅผ Context์— ์ฃผ์ž…
  • useRouterContext, useCurrentPage ๊ฐ™์€ Hook ์‚ฌ์šฉ
  • ๋ผ์šฐํ„ฐ ๋ณ€๊ฒฝ ์‹œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž๋™ ๋ฆฌ๋ Œ๋”๋ง => ๋ผ์šฐํŒ… ๋˜ํ•œ ์„ ์–ธ์ ์ธ ๊ตฌ์กฐ๋กœ ์ถ”์ƒํ™”๋จ

[๊นจ๋‹ฌ์€ ์ ]

๊ฐ™์€ SSR/SSG๋ผ๋„ Vanilla์—์„œ๋Š” SSR์ด ๋ฌด์—‡์ธ์ง€๋ฅผ ๋ชธ์œผ๋กœ ์ดํ•ดํ•˜๊ฒŒ ๋˜์—ˆ๊ณ , React์—์„œ๋Š” ์™œ ์ด๋Ÿฐ ์ถ”์ƒํ™”๊ฐ€ ํ•„์š”ํ•œ์ง€๋ฅผ ์ดํ•ดํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

์ด ๋น„๊ต๋ฅผ ํ†ตํ•ด hydration์ด ๋‹จ์ˆœํ•œ ํ›„์ฒ˜๋ฆฌ๊ฐ€ ์•„๋‹ˆ๋ผ, SSR ๊ตฌ์กฐ์—์„œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์—ฐ๊ฒฐ ์ง€์ ์ด๋ผ๋Š” ๊ฑธ ๋ช…ํ™•ํžˆ ๊นจ๋‹ฌ์•˜๋‹ค.


๋ฆฌ๋ทฐ ๋ฐ›๊ณ  ์‹ถ์€ ๋‚ด์šฉ

1. MSW ๋™์‹œ์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ ๋ฐฉ์‹ ๊ฒ€ํ† 

ํ˜„์žฌ ๊ตฌํ˜„

// packages/vanilla/server.js:28-30
// packages/react/server.ts:31-33
mswServer.listen({
  onUnhandledRequest: "bypass", // ๋ชจํ‚นํ•˜์ง€ ์•Š์€ ์š”์ฒญ์€ ๊ทธ๋Œ€๋กœ ํ†ต๊ณผ
});

์งˆ๋ฌธ

  1. ํ˜„์žฌ ํ•ด๊ฒฐ์ฑ…์˜ ํ•œ๊ณ„

    • onUnhandledRequest: "bypass"๋กœ ํ•ด๊ฒฐํ–ˆ์ง€๋งŒ, ์—ฌ๋Ÿฌ ์„œ๋ฒ„๊ฐ€ ๋™์‹œ์— MSW๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ ์ „์—ญ ์ƒํƒœ ๊ณต์œ  ๋ฌธ์ œ๊ฐ€ ์™„์ „ํžˆ ํ•ด๊ฒฐ๋˜์—ˆ๋Š”์ง€ ํ™•์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
    • ๊ฐ ์„œ๋ฒ„๋งˆ๋‹ค ๋…๋ฆฝ์ ์ธ MSW ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์ด ๋” ๋‚˜์€ ๋ฐฉ๋ฒ•์ผ๊นŒ์š”?
  2. ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ ๊ณ ๋ ค

    • ํ˜„์žฌ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋„ MSW๊ฐ€ ์‹คํ–‰๋˜๋Š”๋ฐ (packages/vanilla/server.js:28, packages/react/server.ts:31), ํ”„๋กœ๋•์…˜์—์„œ๋Š” MSW๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ๋ถ„๊ธฐํ•˜๋Š” ๊ฒƒ์ด ์ข‹์„๊นŒ์š”?
    // ์ œ์•ˆ: ํ”„๋กœ๋•์…˜์—์„œ๋Š” MSW ๋น„ํ™œ์„ฑํ™”
    if (process.env.NODE_ENV !== "production") {
      mswServer.listen({ onUnhandledRequest: "bypass" });
    }
  3. ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ์˜ ์•ˆ์ •์„ฑ

    • E2E ํ…Œ์ŠคํŠธ์—์„œ ์—ฌ๋Ÿฌ ํฌํŠธ๋ฅผ ๋™์‹œ์— ํ…Œ์ŠคํŠธํ•  ๋•Œ, MSW์˜ ์ „์—ญ ์ƒํƒœ๊ฐ€ ์—ฌ์ „ํžˆ ๊ฐ„์„ญํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š”์ง€ ๊ฒ€ํ† ๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ž์„ธํ•œ ๊ตฌํ˜„ ๊ณผ์ •๊ณผ ํšŒ๊ณ ๋Š” ์•„๋ž˜ ๋ธ”๋กœ๊ทธ์— ์ •๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค! ๐Ÿ˜Š

9์ฃผ์ฐจ_์„ฑ๋Šฅ์ตœ์ ํ™”: SSR(Server Side Rendering), SSG(Static Site Generation), Infra

WIL 9์ฃผ์ฐจ_Chapter 4-1. ์„ฑ๋Šฅ์ตœ์ ํ™”: SSR, SSG, Infra

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • TypeScript 61.3%
  • JavaScript 37.2%
  • CSS 1.2%
  • HTML 0.3%