Rendering Patterns - team-yaza/mozi-client GitHub Wiki

๋ฐœํ‘œ ์˜์ƒ

์•ˆ๋…•ํ•˜์„ธ์š” ์†Œํ”„ํŠธ์›จ์–ด ๋งˆ์—์ŠคํŠธ๋กœ ์—ฐ์ˆ˜์ƒ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž ์ดํ˜„์ง„ ์ž…๋‹ˆ๋‹ค. ์›น ํŽ˜์ด์ง€๋ฅผ ๊ทธ๋ฆฌ๋Š” ๋‹ค์–‘ํ•œ ๋ Œ๋”๋ง ๋ฐฉ์‹ ์ฆ‰ Rendering Pattern๋“ค์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋ Œ๋”๋ง์€ ๋ธŒ๋ผ์šฐ์ € ํ™”๋ฉด์— ์›น ํŽ˜์ด์ง€๋ฅผ ๊ทธ๋ฆฌ๋Š” ๊ฒƒ์„ ๋งํ•ฉ๋‹ˆ๋‹ค. ๋จผ์ € ์œ ์ €๊ฐ€ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ†ตํ•ด ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ , ์„œ๋ฒ„๋Š” ์ด์— ์‘๋‹ต์œผ๋กœ HTML, CSS, JavaScript๋ฅผ ๋ณด๋‚ด์ค๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋Š” ์ด๋ฅผ ํ•ด์„ํ•˜์—ฌ ์›น ํŽ˜์ด์ง€๋ฅผ ๊ทธ๋ฆฝ๋‹ˆ๋‹ค. (๋ Œ๋”๋ง์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ ํ”„๋กœ์„ธ์Šค๋ฅผ ๋ Œ๋”๋Ÿฌ ํ”„๋กœ์„ธ์Šค๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.)

๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ™”๋ฉด์— HTML, CSS, JavaScript๋ฅผ ๊ทธ๋ฆฌ๋Š” ๊ณผ์ •(์ ˆ์ฐจ)๋ฅผ CRP(Critical Rendering Path)๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์€ ์šฐ์„  DOM Tree์™€ CSSOM Tree๋ฅผ ๋งŒ๋“ค๊ณ , ์ด ๋‘˜์„ ๊ฒฐํ•ฉํ•˜์—ฌ Render Tree๋ฅผ ๋งŒ๋“ญ๋‹ˆ๋‹ค. ๋‹ค์Œ์—๋Š” Render Tree๋ฅผ ๋ฐฐ์น˜ํ•˜๋Š” Layout๊ณผ์ •, ํ™”๋ฉด์— ์ง์ ‘ ๊ทธ๋ฆฌ๋Š” Paint ๊ณผ์ •์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค. ์œ„ ๊ทธ๋ฆผ์—์„œ DOM Tree ๋ถ€ํ„ฐ Render Tree๋ฅผ ๋งŒ๋“ค๊ธฐ๊นŒ์ง€๋ฅผ Construction ๊ณผ์ •, Layout๊ณผ Paint๋ฅผ Operation ๊ณผ์ •์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

CRP๋ฅผ ์•Œ์•„์•ผํ•˜๋Š” ์ด์œ ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์ž‘์„ฑํ•œ ์ฝ”๋“œ๊ฐ€ ๋ Œ๋”๋ง์— ์ง์ ‘์ ์œผ๋กœ ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ํŠน์ • ์š”์†Œ๋ฅผ ์•ˆ๋ณด์ด๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ณ  ์‹ถ์„ ๋•Œ display: none์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด Tree๋“ค์„ ๋งŒ๋“œ๋Š” Construction ๊ณผ์ •๋ถ€ํ„ฐ Operation๊ณผ์ •๊นŒ์ง€ ๋‹ค์‹œ ์ง„ํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ Œ๋”๋ง ๊ณผ์ •์— ์žˆ์–ด์„œ ๋น„ํšจ์œจ์„ฑ์„ ์ดˆ๋ž˜ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ opacity๋‚˜ visibility์†์„ฑ์„ ์‚ฌ์šฉํ•˜๋Š”๊ฒƒ์ด ๋” ํšจ์œจ์ ์ž…๋‹ˆ๋‹ค.

์ด์ „ ์˜ˆ์‹œ์—์„œ ์•Œ ์ˆ˜ ์žˆ๋Š” ์‚ฌ์‹ค์€ ๋ Œ๋”๋ง์€ UX(User Experience)์™€ DX(Developer Experience)์— ์ง์ ‘์ ์œผ๋กœ ์˜ํ–ฅ์„ ๋ฏธ์นœ๋‹ค๋Š” ๊ฒƒ ์ž…๋‹ˆ๋‹ค. ๊ฐœ๋ฐœ์ž๊ฐ€ ์ž‘์„ฑํ•˜๋Š” ์ฝ”๋“œ์— ๋”ฐ๋ผ ๋ Œ๋”๋ง์˜ ์†๋„๊ฐ€ ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ๊ณ  ๊ฐœ๋ฐœ์ž๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ฒซ ์‚ฌ์šฉ์ž(First User)์ด๊ธฐ๋„ ํ•˜๋ฏ€๋กœ DX์— ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค. ๋˜ํ•œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ฑ„ํƒํ•œ ๋ Œ๋”๋ง ํŒจํ„ด์€ ์ตœ์ดˆ ์œ ์ €์ธ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์˜ํ–ฅ์„ ๋ฏธ์น˜๊ณ  ์ด๋Š” ๊ฒฐ๊ตญ UX์— ์˜ํ–ฅ์„ ๋ฏธ์นฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ๋Š” ์˜ฌ๋ฐ”๋ฅธ ๋ Œ๋”๋ง ๋ฐฉ๋ฒ•์„ ์ฑ„ํƒํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡๋‹ค๋ฉด ์–ด๋–ค ๋ Œ๋”๋ง ํŒจํ„ด์ด ์˜ฌ๋ฐ”๋ฅธ ๊ฒƒ ์ผ๊นŒ์š”? ๋˜, ์˜ฌ๋ฐ”๋ฅด๋‹ค๋Š” ๊ธฐ์ค€์€ ๋ฌด์—‡์ผ๊นŒ์š”?

์˜ฌ๋ฐ”๋ฅธ ๋ Œ๋”๋ง ํŒจํ„ด์ด๋ž€, ์šฐ๋ฆฌ์˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํŠน์„ฑ์— ๋งž๊ณ , UX์™€ DX๋ฅผ ๋ชจ๋‘ ๋†’์—ฌ์ฃผ๋Š” ํŒจํ„ด์„ ๋งํ•ฉ๋‹ˆ๋‹ค.

์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค ๋•Œ ๊ณ ๋ คํ•ด์•ผ ํ•  ์š”์†Œ๋Š” ๊ฒ€์ƒ‰์—”์ง„ ์ตœ์ ํ™”, Web Performance๋“ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฒ€์ƒ‰์—”์ง„ ์ตœ์ ํ™”๋Š” SSR(Server Side Rendering) ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Web Performance์—์„œ ๊ณ ๋ คํ•  ์ ์€ ๊ตฌ๊ธ€์—์„œ ์ œ์•ˆํ•˜๋Š” ์›น ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์— ๋Œ€ํ•œ ์ง€ํ‘œ์ธ Core Web Vitals์ž…๋‹ˆ๋‹ค.

  • TTFB(Time To First Byte): ์›น ํŽ˜์—์ง€ ์ปจํ…์ธ ์˜ ์ฒซ byte๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์— ๋„๋‹ฌํ•˜๋Š”๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„
  • FCP(First Contentful Paint): ์ดˆ๊ธฐ DOM ์ปจํ…์ธ ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š”๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„
  • LCP(Largest Contentful Paint): ๊ฐ€์žฅ ํฐ ์ปจํ…์ธ (๋ณดํ†ต ์ค‘์š”ํ•œ ์ปจํ…์ธ ์ผ์ˆ˜๋ก ํฌ๊ธฐ๊ฐ€ ํผ)๋ฅผ ํŽ˜์ด์ง€์— ๋ Œ๋”๋งํ•˜๋Š”๋ฐ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„
  • TTI(Time To Interactive): ์ปจํ…์ธ ์™€ ์ƒํ˜ธ์ž‘์šฉ๊นŒ์ง€์˜ ์‹œ๊ฐ„(CSR์—์„œ๋Š” TTV(Time To View)์™€ TTI๊ฐ€ ๊ฐ™๊ณ  SSR์—์„œ๋Š” TTV์™€ TTI๊ฐ€ ๋‹ค๋ฅด๋‹ค.)
  • CLS(Cumulative Layout Shift): ๋ˆ„์  ๋ ˆ์ด์•„์›ƒ ์ด๋™์œผ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ ˆ์ด์•„์›ƒ ์ด๋™์„ ๊ฒฝํ—˜ํ•˜๋Š” ๋นˆ๋„๋ฅผ ์ˆ˜๋Ÿ‰ํ™”. ์‹œ๊ฐ์  ์•ˆ์ •์„ฑ์„ ์ธก์ •ํ•  ๋•Œ ์ค‘์š”ํ•œ ์‚ฌ์šฉ์ž ์ค‘์‹ฌ ๋ฉ”ํŠธ๋ฆญ
  • FID(First Input Delay): ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€์™€ ์ฒ˜์Œ ์ƒํ˜ธ ์ž‘์šฉํ•  ๋•Œ(๋ฒ„ํŠผ ํด๋ฆญ ๋“ฑ) ๋ถ€ํ„ฐ ํ•ด๋‹น ์ƒํ˜ธ ์ž‘์šฉ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์‹ค์ œ๋กœ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์ฒ˜๋ฆฌ๋ฅผ ์‹œ์ž‘ํ•˜๊ธฐ๊นŒ์ง€์˜ ์‹œ๊ฐ„์„ ์ธก์ ํ•˜๋Š” ์ง€ํ‘œ.

์ด Core Web Vitals๋Š” '์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ๋ Œ๋”๋ง์„ ํ•˜๋ƒ'์— ๋”ฐ๋ผ ์ˆ˜์น˜๊ฐ€ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

'์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ๋ Œ๋”๋ง์„ ํ•˜๋ƒ'๋Š” ์–ด๋–ค ๋ Œ๋”๋ง ํŒจํ„ด์œผ๋กœ ํŽ˜์ด์ง€๋ฅผ ๋ Œ๋”๋ง ํ•  ๊ฒƒ์ธ๊ฐ€๋กœ ๊ท€๊ฒฐ๋ฉ๋‹ˆ๋‹ค.

Core Web Vitals๋ฅผ ๊ธฐ์ค€์œผ๋กœ ๋ Œ๋”๋ง ํŒจํ„ด๋“ค์˜ ํŠน์ง•์„ ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

CSR์˜ ๋ Œ๋”๋ง ๊ณผ์ •์€ ๋จผ์ € ์œ ์ €์˜ ์š”์ฒญ์— ์˜ํ•ด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋ฒ„๋กœ HTML์„ ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. ์„œ๋ฒ„๋Š” ๋นŒ๋“œ ํƒ€์ž„์— ๋ฏธ๋ฆฌ ์ƒ์„ฑํ•ด ๋‘” HTML์„ ์‘๋‹ตํ•ฉ๋‹ˆ๋‹ค. ์ด HTML์—๋Š” ๋กœ๋”๋‚˜ skeleton UI๊ฐ€ ๋“ค์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ ํ›„์— head ํƒœ๊ทธ์— ์ •์˜๋œ CSS์™€ ๊ฐ™์€ ๋ Œ๋”๋ง ์ฐจ๋‹จ ๋ฆฌ์†Œ์Šค(๋‹ค์šด๋กœ๋“œ๋˜๊ธฐ ์ „๊นŒ์ง€ ๋ Œ๋”๋ง์„ ๋ง‰์Œ)๋ฅผ ๋‹ค์šด ๋ฐ›๋Š”๋ฐ, ๋ณดํ†ต ์ด๋Ÿฐ ๋ฆฌ์†Œ์Šค๋Š” ๋ธŒ๋ผ์šฐ์ €์— ์บ์‹œ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ์œผ๋กœ body ํƒœ๊ทธ์˜ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์— ์œ„์น˜ํ•œ React์•ฑ์ด ๋“ค์–ด์žˆ๋Š” bundle์„ ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋ฒ„์— ์š”์ฒญํ•ฉ๋‹ˆ๋‹ค. bundle์„ bodyํƒœ๊ทธ์˜ ๊ฐ€์žฅ ์•„๋ž˜์— ์œ„์น˜์‹œํ‚ค๋Š” ์ด์œ ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋Š” ๋ฌธ์„œ๋ฅผ ํŒŒ์‹ฑํ•˜๋‹ค๊ฐ€ JavaScript๋ฅผ ๋งŒ๋‚˜๋ฉด ํŒŒ์‹ฑ์„ ์ค‘์ง€ํ•˜๊ณ  JavaScript ์—”์ง„์—๊ฒŒ ๊ถŒํ•œ์„ ๋„˜๊ฒจ์„œ JS๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.(Parse Blocking Resource)

React์•ฑ์ด ์‹คํ–‰๋˜๋ฉด ์ด์ œ ์ปจํ…์ธ (๋ฐ์ดํ„ฐ)๋ฅผ ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•ด API ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ  ์‘๋‹ต์„ ๋ฐ›์•„์„œ ์œ ์ €์—๊ฒŒ ์ปจํ…์ธ ๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

์œ„ ๋‚ด์šฉ์„ ์ •๋ฆฌํ•˜๋ฉด ์œ ์ €๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ์š”์ฒญ์„ ๊ธฐ๋‹ค๋ ค์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  1. HTML ํŒŒ์ผ์„ ์š”์ฒญํ•ด์„œ ์‘๋‹ต์„ ๋ฐ›๊ณ 
  2. JavaScript ๋ฒˆ๋“ค์„ ์š”์ฒญํ•ด์„œ ์‘๋‹ต์„ ๋ฐ›๊ณ 
  3. ๋ฒˆ๋“ค์„ ์‹คํ–‰ํ•˜๊ณ 
  4. API ์„œ๋ฒ„๋กœ ๋ถ€ํ„ฐ ์‘๋‹ต์„ ๋ฐ›๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ๋ Œ๋”๋ง

CSR์„ Core Web Vitals ๊ด€์ ์œผ๋กœ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์šฐ์„  ์˜ค๋ฅธ์ชฝ ์•„๋ž˜์— ํ‘œ์‹œ๋œ ํŒŒ๋ž€์ƒ‰ ํ‘œ์‹œ๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ผ์–ด๋‚˜๋Š” ๊ณผ์ •์„, ๋นจ๊ฐ„์ƒ‰ ํ‘œ์‹œ๋Š” ์„œ๋ฒ„์—์„œ ์ผ์–ด๋‚˜๋Š” ๊ณผ์ •์„ ๋œปํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ Network ๋ถ€๋ถ„๊ณผ Main Thread ๋ถ€๋ถ„์„ ๋‚˜๋ˆด์Šต๋‹ˆ๋‹ค.(Main Thread๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ ๋ Œ๋”๋Ÿฌ ํ”„๋กœ์„ธ์Šค์˜ Main Thread๋ฅผ ๋งํ•ฉ๋‹ˆ๋‹ค.) ์œ ์ €๊ฐ€ HTML์„ ์š”์ฒญํ•˜๊ณ  ์„œ๋ฒ„๊ฐ€ ์ด์— ์‘๋‹ตํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ €์— ์ปจํ…์ธ ์˜ ์ฒซ byte๊ฐ€ ๋„๋‹ฌํ•˜๋Š” ์ˆœ๊ฐ„์„ TTFB๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค. ์ดํ›„์—๋Š” HTML์„ ํŒŒ์‹ฑํ•˜๊ณ  bodyํƒœ๊ทธ ๋งจ ์•„๋ž˜์— script ํƒœ๊ทธ์— ๋„๋‹ฌํ•˜๋ฉด bundle.jsํŒŒ์ผ์„ ์„œ๋ฒ„์—์„œ ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•ด ์š”์ฒญ์„ ๋ณด๋ƒ…๋‹ˆ๋‹ค. ์ด ๋•Œ ๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” Operation๊ณผ์ •์ด ์ˆ˜ํ–‰๋˜๊ณ  bundle์„ ๊ฐ€์ ธ์˜ค๋ฉด ์ด์ œ JavaScript๋ฅผ Evaluationํ•˜๋ฉด์„œ ๋‹ค์‹œ Operation์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์„ ๋งˆ์น˜๋ฉด HTML์— JavaScript๊ฐ€ ์—ฐ๊ฒฐ๋˜์–ด์„œ ์œ ์ €๊ฐ€ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด ์—ฐ๊ฒฐ๋œ ๋กœ์ง์ด ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.(TTI)

์ด์ œ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๊ธฐ ์œ„ํ•ด /api/buildings๋ผ๋Š” ์—”๋“œํฌ์ธํŠธ์— ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ , ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ต๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋ฉด ๋ธŒ๋ผ์šฐ์ €๋Š” ๋ฐ”๋€ ๋ถ€๋ถ„์„ ๋‹ค์‹œ ๊ทธ๋ฆฌ๋Š”๋ฐ ์ด ๊ณผ์ •์„ hydration์ด๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

hydration์ด ์™„๋ฃŒ๋˜๋Š” ์‹œ๊ฐ„์ด LCP(Largest ContentFul Paint)๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. LCP๋Š” ๋ณดํ†ต ํŽ˜์ด์ง€์—์„œ ์ค‘์š”ํ•œ ์š”์†Œ๋ฅผ ๋กœ๋“œํ•˜๋Š”๋ฐ ๊นŒ์ง€ ๊ฑธ๋ฆฌ๋Š” ์‹œ๊ฐ„์ธ๋ฐ CSR์—์„œ๋Š” ์ƒ๋Œ€์ ์œผ๋กœ ๋Š๋ฆฌ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

hydration์„ ์‹œ๊ฐ์ ์œผ๋กœ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ๋ฐ๋ชจ ํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

DEMO

hydrate์€ ์ˆ˜๋ถ„์„ ๊ณต๊ธ‰ํ•˜๋‹ค๋ผ๋Š” ๋œป์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์™ผ์ชฝ ๋ธŒ๋ผ์šฐ์ €์—๋Š” skeleton UI๊ฐ€ ์žˆ๊ณ  ์˜ค๋ฅธ์ชฝ ๋ธŒ๋ผ์šฐ์ €์—๋Š” ๋นŒ๋”ฉ ๋ฐ์ดํ„ฐ๊ฐ€ ์ฑ„์›Œ์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰hydration์ด๋ž€, API์š”์ฒญ์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ผ๋Š” ์ˆ˜๋ถ„์„ ํŽ˜์ด์ง€์— ๊ณต๊ธ‰ํ•ด์ฃผ๋Š” ๊ฒƒ ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

hydration ํŽ˜์ด์ง€๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์— ๋กœ๋“œ๋˜๊ณ  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋˜๋ฉด์„œ ํŽ˜์ด์ง€๊ฐ€ ์ธํ„ฐ๋ ‰ํ‹ฐ๋ธŒํ•˜๊ฒŒ ๋™์ž‘ํ•˜๋Š” ์ƒํƒœ๊ฐ€ ๋˜๋Š” ๊ณผ์ •

๋‹ค์Œ์œผ๋กœ SSR(Server Side Rendering)์ž…๋‹ˆ๋‹ค. ์œ ์ €๊ฐ€ ํ”„๋ก ํŠธ์—”์Šค ์„œ๋ฒ„์— HTML ํŒŒ์ผ์„ ์š”์ฒญํ•˜๋ฉด ์„œ๋ฒ„๋Š” API ์„œ๋ฒ„์— ์š”์ฒญ์„ ๋ณด๋‚ด์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์™€ ์ปจํ…์ธ ๋ฅผ ์ฑ„์šฐ๊ณ  ์™„์„ฑ๋œ HTML ํŒŒ์ผ์„ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ณด๋‚ด์ค๋‹ˆ๋‹ค.

๊ธฐ์กด React์•ฑ์ด ์‹คํ–‰๋œ ํ›„์— ๋ณด๋‚ด๋˜ API ์š”์ฒญ์„ ์„œ๋ฒ„์—์„œ ๋ฏธ๋ฆฌ ๋ณด๋‚ด๋Š” ๊ฒƒ ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์œ ์ €๋Š” ํ•œ๋ฒˆ์˜ ์š”์ฒญ๋งŒ์œผ๋กœ ๋ณด๊ณ  ์‹ถ์€ ์ปจํ…์ธ ๋ฅผ ๋ฐ”๋กœ ๋ณด๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

SSR์„ Core Web Vitals ๊ด€์ ์œผ๋กœ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. SSR์ด ์ด๋ฃจ์–ด์ง„ ํ›„ ์ฒซ ๋ฐ”์ดํŠธ๊ฐ€ ์œ ์ €์—๊ฒŒ ๋„์ฐฉํ•˜๊ณ , ์œ ์ €์—๊ฒŒ ๋„์ฐฉํ•œ HTML์€ ์ปจํ…์ธ ๋ฅผ ํฌํ•จํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๊ทธ HTML์„ ๋ Œ๋”ํ•˜๋Š” ์ˆœ๊ฐ„ FCP(First Contentful Paint), LCP(Largest Contentful Paint)๊ฐ€ ๋™์‹œ์— ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰์œผ๋กœ JS๋ฅผ ๋กœ๋”ฉํ•˜๋ฉด ์œ ์ €๊ฐ€ ์ธํ„ฐ๋ ‰์…˜ ๊ฐ€๋Šฅํ•œ ํŽ˜์ด์ง€๊ฐ€ ๋˜๋ฏ€๋กœ TTI๋Š” ๋งˆ์ง€๋ง‰์— ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ๋ถ„์˜ ์ปจํ…์ธ ๊ฐ€ ๋นˆ๋ฒˆํ•˜๊ฒŒ ๋ฐ”๋€๋‹ค๋ฉด CSR๊ณผ SSR์„ ๊ฐ™์ด ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ, SSR์„ ๋งˆ์นœ๋’ค์— hydration๊ณผ์ •์ด ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค. hydration ๊ณผ์ •์—๋Š” react-query๋‚˜ swr๊ฐ™์€ data-fetching ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ฃผ๋กœ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค.

React์—์„œ๋Š” SSR์„ ๊ตฌํ˜„ํ•˜๊ธฐ์œ„ํ•ด React ํ”„๋ ˆ์ž„์›Œํฌ์ธ Next.js๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

Next.js๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  ํŽ˜์ด์ง€๋ฅผ pre-render(๋ฏธ๋ฆฌ ๋ Œ๋”๋ง)ํ•ฉ๋‹ˆ๋‹ค. Client Side JavaScript๊ฐ€ ํŽ˜์ด์ง€์˜ HTML์„ ๋‹ค ๊ทธ๋ฆฌ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ฏธ๋ฆฌ ๊ฐ ํŽ˜์ด์ง€๋ฅผ ์œ„ํ•œ HTML์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๊ฐ๊ฐ ์ƒ์„ฑ๋œ HTML ํŽ˜์ด์ง€์—๋Š” ์ตœ์†Œํ•œ์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์—ฐ๊ฒฐ๋˜๊ณ  Client Side์—์„œ๋Š” ์ด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ hydration๊ณผ์ •์ด ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค.

Next.js์˜ pre-rendering ํ˜•ํƒœ๋Š” SSG(Static Site Generation)๊ณผ SSR(Server Side Rendering)์œผ๋กœ ๋‚˜๋‰˜๋ฉฐ ๊ฐ ํŽ˜์ด์ง€๋ณ„๋กœ ๋‹ค๋ฅด๊ฒŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด Page A๋Š” SSG๋กœ, Page B๋Š” SSR๋กœ, Page C๋Š” CSR + SSR๋กœ, Page D๋Š” CSR๋กœ ๋ Œ๋”๋ง ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Next.js์˜ pre-rendering ํ˜•ํƒœ์ค‘ SSG์— ๋Œ€ํ•ด์„œ ๋จผ์ € ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. SSG๋Š” ๋นŒ๋“œ ํƒ€์ž„์— HTML ํŽ˜์ด์ง€๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„์˜ค๋Š” API ์š”์ฒญ ๋˜ํ•œ ๋นŒ๋“œ ํƒ€์ž„์—๋งŒ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ API ์„œ๋ฒ„์˜ ๋ถ€ํ•˜๊ฐ€ ์ค„์–ด๋“ญ๋‹ˆ๋‹ค. ๋˜ํ•œ, ๋งŒ๋“ค์–ด์ง„ ์ปจํ…์ธ ๋ฅผ CDN์— ์บ์‹œํ•จ์œผ๋กœ์จ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ปจํ…์ธ ๋ฅผ ๋งค์šฐ ๋น ๋ฅด๊ฒŒ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹จ์ ์œผ๋กœ๋Š” ๋นŒ๋“œ ํƒ€์ž„์— ์ปจํ…์ธ ๋ฅผ ๋งŒ๋“ค๊ธฐ ๋•Œ๋ฌธ์— ๋ณ€ํ•˜๋Š” ๋ฐ์ดํ„ฐ์— ์ทจ์•ฝํ•ฉ๋‹ˆ๋‹ค.

SSG์— CSR์„ ๊ณ๋“ค์ด๋ฉด ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„์€ ๋ณ€ํ•˜์ง€ ์•Š๊ฒŒ ๊ณ ์ •ํ•˜๊ณ , ์œ ๋™์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ fetching ํ•ด์•ผํ•˜๋Š” ๋ถ€๋ถ„์€ CSR๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.(hydration) ๋˜ํ•œ, ๋‘ ๋ Œ๋”๋ง ๋ฐฉ์‹์„ ํ•ฉ์ณค๊ธฐ ๋•Œ๋ฌธ์— ์žฅ์  ๋˜ํ•œ ํ•ฉ์ณ์ง‘๋‹ˆ๋‹ค.

ISR(Incremental Static ReGeneration)์€ SSG์—์„œ revalidation ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•œ ๊ฒƒ ์ž…๋‹ˆ๋‹ค. ๋นŒ๋“œ ํƒ€์ž„์— HTML์„ ์ƒ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋™์ผํ•˜๋‚˜ ์ผ์ • ์ฃผ๊ธฐ๋งˆ๋‹ค ๋ฐ์ดํ„ฐ์˜ ์ตœ์‹  ์—ฌ๋ถ€๋ฅผ ๊ฒ€์‚ฌํ•ด์„œ ์—…๋ฐ์ดํŠธ๋œ ๋ฐ์ดํ„ฐ๋กœ ํŽ˜์ด์ง€๋ฅผ ๋‹ค์‹œ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ CSR์„ ๊ณ๋“ค์ด๋ฉด ๋ฐ”๋€Œ๊ธด ํ•˜๋Š”๋ฐ ์ž์ฃผ ๋ณ€ํ•˜์ง€ ์•Š๋Š” ๋ฐ์ดํ„ฐ๋Š” ISR์˜ ๋ Œ๋”๋ง ๋ฐฉ๋ฒ•์„, ๋™์ ์œผ๋กœ ๊ณ„์† ๋ฐ”๋€Œ๋Š” ๋ฐ์ดํ„ฐ๋“ค์€ CSR๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค๋ฉด ๋ธ”๋กœ๊ทธ ๊ธ€(์ž์ฃผ ์•ˆ๋ฐ”๋€œ)๊ณผ ๋Œ“๊ธ€(์ž์ฃผ ๋ฐ”๋€œ)์„ ์ด ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ SSG ๋˜ํ•œ Core Web Vitals ๊ด€์ ์œผ๋กœ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. SSG๋กœ ๋งŒ๋“ค์–ด์ง„ ์‚ฌ์ดํŠธ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋นŒ๋“œ ํƒ€์ž„์— ์ด๋ฏธ HTML์ด ์™„์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ์„œ๋ฒ„์—์„œ๋Š” ๋งˆ๋•…ํžˆ ํ•  ์ผ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— HTML์„ ๋ฐ”๋กœ ์ฃผ๊ณ  ํด๋ผ์ด์–ธํŠธ๋Š” ๊ทธ HTML์„ ๋ฐ”๋กœ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค. CSR์„ ๊ณ๋“ค์ธ๋‹ค๋ฉด ๋’ค์— hydration ๊ณผ์ •์ด ์ถ”๊ฐ€๋˜๊ฒ ์ฃ .

๋‹ค์‹œ SSR์ž…๋‹ˆ๋‹ค. SSR์ด์•ผ๊ธฐ๋ฅผ ๋‹ค์‹œ ๊บผ๋‚ธ ์ด์œ ๋Š” Next.jsSSR์˜ Page๋‹จ์œ„ data fetching์— ์žˆ์Šต๋‹ˆ๋‹ค.

getServerSideProps๋ผ๋Š” ํ•จ์ˆ˜๋Š” API์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ ํ›„์— ํ•ด๋‹น ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•œ props๋ฅผ ๋ฆฌํ„ดํ•ด์ฃผ๋ฉด ํŽ˜์ด์ง€ ์ปดํฌ๋„ŒํŠธ๋Š” ๊ทธ props๋ฅผ ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋งŒ์•ฝ CSR์—์„œ SSR๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ•œ๋‹ค๊ณ ํ•˜๋ฉด ๊ธฐ์กด ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ์˜ data fetching ๋กœ์ง์„ getServerSideProps๋กœ ์˜ฎ๊ธฐ๋ฉด ๋ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ์—์„œ ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ fetching ํ•œ๋‹ค๋ฉด ์ฒ˜๋ฆฌ๊ฐ€ ์–ด๋ ค์›Œ์ง‘๋‹ˆ๋‹ค. ๋˜ํ•œ props drilling์„ ํ•˜๋ฉด ๊ด€์‹ฌ์‚ฌ์˜ ๋ถ„๋ฆฌ๊ฐ€ ๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ(์œ„ ์˜ˆ์ œ์—์„œ A์ปดํฌ๋„ŒํŠธ๋Š” data์— ๊ด€์‹ฌ์ด ์—†์Œ) ์ข‹์ง€ ์•Š์€ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์ด RSC(React Server Component)์ž…๋‹ˆ๋‹ค. RSC๋Š” ์ปดํฌ๋„ŒํŠธ ๊ฐœ๋ณ„ ๋‹จ์œ„๋ณ„๋กœ ์„œ๋ฒ„์—์„œ data fetching์„ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์„œ๋ฒ„์˜ ๋ฆฌ์†Œ์Šค์— ์ž์œ ๋กญ๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์„œ๋ฒ„์ปดํฌ๋„ŒํŠธ๋Š” ํด๋ผ์ด์–ธํŠธ๋กœ ์ „์†ก๋˜๋Š” ๋ฒˆ๋“ค์— ํฌํ•จ๋˜์ง€ ์•Š์œผ๋ฉฐ, ํด๋ผ์ด์–ธํŠธ์˜ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋ฉฐ refetchํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ ์ด๋Ÿฐ ๋ Œ๋”๋ง ํŒจํ„ด๋“ค์„ ์•Œ์•„์•ผํ•˜๋Š” ์ด์œ ๋Š” ๋ Œ๋”๋ง ํŒจํ„ด์ด UX์™€ DX์— ์ง์ ‘์ ์œผ๋กœ ์—ฐ๊ด€์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ํ”ํžˆ ์ด๋Ÿฐ ๊ฐœ๋ฐœ ์‚ฌ์ดํด์„ ๋Œ๊ณค ํ•ฉ๋‹ˆ๋‹ค. ์—„์ฒญ๋‚œ ์•„์ด๋””์–ด๊ฐ€ ๋– ์˜ค๋ฅด๊ณ , ๊ฐœ๋ฐœ์„ ํ•œ ํ›„ ๋ฐฐํฌ๋ฅผ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ์ด ๊ณผ์ •์—์„œ ๋ Œ๋”๋ง ํŒจํ„ด์€ ์–ธ์ œ ๊ณ ๋ ค๋˜์–ด์•ผ ํ• ๊นŒ์š”?

์ •๋‹ต์€ ์—†์Šต๋‹ˆ๋‹ค. ์–ด๋””์„œ๋“ ์ง€ ๋ Œ๋”๋ง ํŒจํ„ด์„ ๊ณ ๋ คํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์–ด๋–ค ์ปจํ…์ธ ๋ฅผ ๋ Œ๋”๋งํ•˜๋ƒ์— ๋”ฐ๋ผ ์ ์šฉํ•  ํŒจํ„ด์ด ๋ฐ”๋€” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ €๋Š” ํŠน์ • ํŒจํ„ด์ด ์ข‹๊ณ  ๋‚˜์˜๊ณ ๋ฅผ ์ฃผ์žฅํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค. ๋‹จ์ง€ ์›น์„ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐฉ๋ฒ•์—๋Š” ๋‹ค์–‘ํ•œ ๋ Œ๋”๋ง ํŒจํ„ด์ด ์กด์žฌํ•˜๊ณ , ์ด ํŒจํ„ด๋“ค์€ ๋ชจ๋‘ trade-off๊ฐ€ ์žˆ์„ ๋ฟ ์ž…๋‹ˆ๋‹ค.

์ด ๋ฐœํ‘œ๊ฐ€ ํšจ์œจ์ ์ธ ๋ Œ๋”๋ง ํŒจํ„ด์„ ์ฐพ๋Š”๋ฐ ๋„์›€์ด ๋˜์—ˆ์œผ๋ฉด ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค.

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋ฐœํ‘œ REPO