[TECH-QA] ๋ชจ๋‹ฌ์„ ํ†ตํ•ด ์•Œ์•„๋ณด๋Š” ๋™์  ์ž„ํฌํŠธ(Dynamic Import)์™€ ์ง€์—ฐ ๋กœ๋”ฉ(Lazy Loading)์„ ํ™œ์šฉ ๋ฐ ํŒฉํ† ๋ฆฌํŒจํ„ด

lazyLoading_1 ๋‹จ์ 
Lazy loading์‹œ ํ™”๋ฉด์—์„œ ํด๋ฝํ•œ ์ˆœ๊ฐ„ ๋ชจ๋‹ฌ์— ๊ด€๋ จ๋œ ํŒŒ์ผ๋“ค์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ  ๋ชจ๋‹ฌ์— ๊ด€๋ จ๋œ ํŒŒ์ผ๋“ค์ด ๋ชจ๋‘ ๋ถˆ๋Ÿฌ์™€์ง€๋ฉด Javascript๋ฅผ Evaluateํ•˜๊ณ  ๋ชจ๋‹ฌ์ด ๋œจ๋„๋ก ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๋ชจ๋‹ฌ์ด ์˜คํ”ˆ๋œ๋‹ค. ์ฆ‰ ์ตœ์ดˆ ๋กœ๋”ฉ ์‹œ์ ์—์„œ๋Š” ํŽ˜์ด์ง€ ๋กœ๋”ฉ์ด ๋นจ๋ผ์กŒ์ง€๋งŒ ๋ชจ๋‹ฌ์„ ๋„์šธ๋•Œ๋Š” ์˜คํžˆ๋ ค ์„ฑ๋Šฅ์ด ๋” ๋А๋ ค์ง„๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ preload๋กœ ์„ฑ๋Šฅ ๊ฐœ์„ ํ•˜๊ธฐ

๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ ๋ชจ๋‹ฌ์„ ์—ด๊ธฐ ์ „์— ๋ฏธ๋ฆฌ ๋ชจ๋‹ฌ๊ณผ ๊ด€๋ จ๋œ ์ฝ”๋“œ๋“ค์„ ๋กœ๋“œํ•ด ๋†“๋Š”๋‹ค. ๋ชจ๋‹ฌ์— ๊ด€๋ จ๋œ ์ฝ”๋“œ๋Š” ๋ฏธ๋ฆฌ ๋กœ๋“œ๊ฐ€ ๋˜์—ˆ์œผ๋ฏ€๋กœ ํด๋ฆญํ•œ ์ˆœ๊ฐ„์— ๋ฐ”๋กœ ๋ชจ๋‹ฌ์˜ ํ™”๋ฉด์„ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ“ ๋ฒ„ํŠผ์œ„์— ๋งˆ์šฐ์Šค๋ฅผ ์˜ฌ๋ ค ๋†จ์„๋•Œ ๋ชจ๋‹ฌ์„ ๋กœ๋”ฉ ํ•˜๋Š” ๋ฐฉ๋ฒ•

const handlerMouseEnter = () => {
  const lazyModalComponent = import('./components/ImageModal');
}

๐Ÿ“ ์ตœ์ดˆ ํŽ˜์ด์ง€ ๋กœ๋“œ์—์„œ ์ค‘์š” ํŒŒ์ผ๋“ค์˜ ๋กœ๋“œ๊ฐ€ ์™„๋ฃŒ ๋œํ›„ ๋ชจ๋‹ฌ ๋กœ๋”ฉ

์ค‘์š” ํŒŒ์ผ๋“ค์˜ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋ชจ๋‘ ๋งˆ์šดํŠธ ๋œ ํ›„์— ๋ชจ๋‹ฌ์„ import ํ•ด์ฃผ๋„๋ก ํ•œ๋‹ค.
useEffect(()=> {
  const lazyModalComponent = import('./components/ImageModal');
},[])

๐Ÿ“ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ”„๋ฆฌ๋กœ๋“œ ํ•ด์ค˜์•ผ ํ•  ๊ฒฝ์šฐ

๋งค๋ฒˆ import๋ฅผ ์จ์ฃผ๊ธฐ๋Š” ๋ฒˆ๊ฑฐ๋กœ์šธ๋•Œ ํŒฉํ† ๋ฆฌ ํŒจํ„ด์œผ๋กœ ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•˜๋„๋ก ํ•˜๋Š” ๋ฐฉ๋ฒ•.
function lazyWidthPreload(importFunction){
  const Component = React.lazy(importFunction);
  Component.preload = importFunction;
  return Component;
}

const lazyImageModal = lazyWidthPreload(() =>  import('./components/ImageModal'));

useEffect(()=> {
  lazyImageModal.preload(); 
},[])

๐Ÿ“ 1. lazyWidthPreload ํ•จ์ˆ˜

function lazyWidthPreload(importFunction) {
  const Component = React.lazy(importFunction);
  Component.preload = importFunction;
  return Component;
}
React์˜ React.lazy๋ฅผ ํ™•์žฅํ•˜์—ฌ, ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง€์—ฐ ๋กœ๋”ฉํ•˜๋ฉด์„œ๋„ ํ•„์š”ํ•  ๋•Œ ๋ฏธ๋ฆฌ ๋กœ๋“œ(preload)ํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  • importFunction: ๋™์  ์ž„ํฌํŠธ๋ฅผ ์œ„ํ•œ ํ•จ์ˆ˜ (์˜ˆ: () => import('./someComponent')).
  • React.lazy(importFunction): ์ฃผ์–ด์ง„ importFunction์„ ์‚ฌ์šฉํ•ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง€์—ฐ ๋กœ๋”ฉํ•˜๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์ด๋กœ ์ธํ•ด ์ปดํฌ๋„ŒํŠธ๋Š” ์ฒ˜์Œ ๋ Œ๋”๋ง ์‹œ ๋กœ๋“œ๋˜์ง€ ์•Š๊ณ , ํ•„์š”ํ•  ๋•Œ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋กœ๋“œ๋ฉ๋‹ˆ๋‹ค.
  • Component.preload = importFunction: Component์— preload ๋ฉ”์„œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ, ๊ฐœ๋ฐœ์ž๊ฐ€ ์›ํ•  ๋•Œ ํ•ด๋‹น ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค.
  • return Component: ์ง€์—ฐ ๋กœ๋”ฉ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋ฉฐ, preload ๋ฉ”์„œ๋“œ๊ฐ€ ์ถ”๊ฐ€๋œ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.

๐Ÿ“ 2. lazyImageModal ์ƒ์„ฑ

const lazyImageModal = lazyWidthPreload(() => import('./components/ImageModal'));
  • ์„ค๋ช…: lazyWidthPreload๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ./components/ImageModal ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง€์—ฐ ๋กœ๋”ฉํ•˜๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฒฐ๊ณผ: lazyImageModal์€ React.lazy๋กœ ์ƒ์„ฑ๋œ ์ง€์—ฐ ๋กœ๋”ฉ ์ปดํฌ๋„ŒํŠธ์ด๋ฉฐ, ์ถ”๊ฐ€๋กœ preload ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ImageModal์„ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์žฅ์ : ์ดˆ๊ธฐ ๋ฒˆ๋“ค ํฌ๊ธฐ๋ฅผ ์ค„์ด๊ณ , ImageModal์ด ํ•„์š”ํ•  ๋•Œ๋งŒ ๋กœ๋“œํ•˜์—ฌ ์„ฑ๋Šฅ์„ ์ตœ์ ํ™”ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ 3. useEffect๋กœ preload ํ˜ธ์ถœ

useEffect(() => {
  lazyImageModal.preload();
}, []);
์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ๋  ๋•Œ lazyImageModal์˜ preload ๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ImageModal ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ๊ณง ImageModal์„ ์—ด ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์€ ๊ฒฝ์šฐ, ๋ฏธ๋ฆฌ ๋กœ๋“œํ•˜์—ฌ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๊ฐœ์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • useEffect๋Š” ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋งˆ์šดํŠธ๋œ ํ›„ ์‹คํ–‰๋˜๋ฉฐ, ์˜์กด์„ฑ ๋ฐฐ์—ด []๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
  • lazyImageModal.preload(): ImageModal ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋กœ๋“œํ•˜์—ฌ, ์ดํ›„ ๋ Œ๋”๋ง ์‹œ ์ง€์—ฐ ์—†์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ค€๋น„ํ•ฉ๋‹ˆ๋‹ค.

์ •๋ฆฌ

  • ์ง€์—ฐ ๋กœ๋”ฉ: React.lazy๋ฅผ ํ†ตํ•ด ImageModal ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ดˆ๊ธฐ ๋กœ๋“œ์—์„œ ์ œ์™ธํ•˜์—ฌ ํŽ˜์ด์ง€ ๋กœ๋”ฉ ์†๋„๋ฅผ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ์›น ์•ฑ์ด ๋กœ๋“œ๋  ๋•Œ ImageModal์€ ๋กœ๋“œ๋˜์ง€ ์•Š์Œ (์ดˆ๊ธฐ ๋กœ๋”ฉ ์†๋„ ๊ฐœ์„ ).
  • ๋ฏธ๋ฆฌ ๋กœ๋“œ: preload ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ํ•„์š”ํ•œ ์‹œ์ ์— ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฏธ๋ฆฌ ๋กœ๋“œํ•˜์—ฌ, ์‚ฌ์šฉ์ž๊ฐ€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์š”์ฒญํ•  ๋•Œ ๋Œ€๊ธฐ ์‹œ๊ฐ„์„ ์ค„์ž…๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ ๋งˆ์šดํŠธ ์‹œ useEffect๊ฐ€ lazyImageModal.preload()๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ImageModal์„ ๋ฐฑ๊ทธ๋ผ์šด๋“œ์—์„œ ๋กœ๋“œ.
  • ์„ฑ๋Šฅ ์ตœ์ ํ™”: ์ดˆ๊ธฐ ๋ฒˆ๋“ค ํฌ๊ธฐ๋ฅผ ์ค„์ด๊ณ , ํ•„์š”ํ•œ ์ปดํฌ๋„ŒํŠธ๋งŒ ๋กœ๋“œํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž ์ธํ„ฐ๋ž™์…˜์— ๋”ฐ๋ผ ๋™์ ์œผ๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ImageModal์„ ์—ด ๋•Œ, ์ด๋ฏธ ๋กœ๋“œ๋œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ฆ‰์‹œ ๋ Œ๋”๋ง๋˜์–ด ๋ถ€๋“œ๋Ÿฌ์šด ๊ฒฝํ—˜ ์ œ๊ณต.

Suspense

React.lazy๋กœ ๋กœ๋“œ๋œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๋ ค๋ฉด ๋กœ ๊ฐ์‹ธ์•ผ ํ•˜๋ฉฐ, ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด fallback UI๋ฅผ ์ œ๊ณตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
<Suspense fallback={<div>Loading...</div>}>
  <lazyImageModal />
</Suspense>
  • ๋„คํŠธ์›Œํฌ ์ƒํƒœ ๊ณ ๋ ค: preload๋Š” ๋„คํŠธ์›Œํฌ ์š”์ฒญ์„ ๋ฐœ์ƒ์‹œํ‚ค๋ฏ€๋กœ, ๋„คํŠธ์›Œํฌ๊ฐ€ ๋А๋ฆฐ ํ™˜๊ฒฝ์—์„œ๋Š” ํƒ€์ด๋ฐ์„ ์กฐ์ •ํ•˜๊ฑฐ๋‚˜ ์กฐ๊ฑด๋ถ€๋กœ ํ˜ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
  • ์˜์กด์„ฑ ๋ฐฐ์—ด: useEffect์˜ []๋Š” ํ•œ ๋ฒˆ๋งŒ ์‹คํ–‰๋˜๋„๋ก ๋ณด์žฅํ•˜์ง€๋งŒ, ํŠน์ • ์กฐ๊ฑด์— ๋”ฐ๋ผ preload๋ฅผ ํ˜ธ์ถœํ•˜๋ ค๋ฉด ์˜์กด์„ฑ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.