๐Ÿ’ก 2019๋…„ React ์ฝ”๋“œ ๋ถ„ํ• 

47457 ๋‹จ์–ด ssrreactcodesplittingjavascript
์ง€๊ธˆ 2019๋…„!๋ชจ๋“  ์‚ฌ๋žŒ๋“ค์€ ๊ทธ๋“ค์ด ์ฝ”๋“œ ๋ถ„ํ• ์„ ์•Œ๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•œ๋‹ค.๊ทธ๋ž˜์„œโ€Š-โ€Š๋‹ค์‹œ ํ•œ ๋ฒˆ ๊ฒ€์‚ฌํ•ฉ์‹œ๋‹ค!

์ฝ”๋“œ ๋ถ„ํ• ์€ ๋ฌด์—‡์„ ๋Œ€ํ‘œํ•ฉ๋‹ˆ๊นŒ?


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

๋ˆ„๊ฐ€ ์ฝ”๋“œ ๋ถ„ํ• ์„ ์ง„ํ–‰ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

React.lazy ? ์•„๋‹ˆ์š” - ๊ทธ๊ฒƒ๋งŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.์ฝ”๋“œ ๋ถ„ํ• ์€ ๋ฒˆ๋“ค ํ”„๋กœ๊ทธ๋žจ ๋‹จ๊ณ„์—์„œ ์ง„ํ–‰๋˜๋ฉฐ, ์ฆ‰ ์›น ํŒจํ‚ค์ง€, ํŒจํ‚ค์ง€, ๋˜๋Š” "๋ณธ ์ปดํ“จํ„ฐ"esm modules์˜ ๊ฒฝ์šฐ ํŒŒ์ผ ์‹œ์Šคํ…œ์—๋งŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.์ฝ”๋“œ ๋ฒ„์ŠคํŠธ๋Š” ํŒŒ์ผ์ผ ๋ฟ, ํŒŒ์ผ์€ ์ž ์‹œ ํ›„ ์–ด๋”˜๊ฐ€๋กœ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ˆ„๊ฐ€ ์ฝ”๋“œ ๋ถ„ํ• ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๊นŒ?

React.lazy์ด ์‚ฌ์šฉ ์ค‘์ž…๋‹ˆ๋‹ค.๋ฒˆ๋“ค ํ”„๋กœ๊ทธ๋žจ์˜ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ถ„ํ• ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.๋ Œ๋”๋งํ•  ๋•Œ import๋งŒ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.๊ทธ๋ฟ์ด์•ผ.

React loadable์€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

React.lazy์ด ๊ทธ๊ฒƒ์„ ๋Œ€์ฒดํ–ˆ๋‹ค.Suspense๊ณผ ๊ฐ™์€ ๋” ๋งŽ์€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜์—ฌ ๋กœ๋“œ ์ƒํƒœ๋ฅผ ์ œ์–ดํ•ฉ๋‹ˆ๋‹ค.๊ทธ๋ž˜์„œโ€Š-โ€Š๊ฐœ์šฉ React.Lazy.

Yep, that's all. Thank you for reading and have a nice day.


์™œ ์ด ๋ฌธ์žฅ์€ ์™„์„ฑ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๊นŒ?


์ข‹์•„์š”.React.lazy๊ณผ ์ฝ”๋“œ ๋ถ„ํ• ์— ๊ด€ํ•ด์„œ ๋‚˜๋Š” ํšŒ์ƒ‰ ๊ตฌ์—ญ์„ ์–ธ๊ธ‰ํ•˜๋Š” ๊ฒƒ์„ ์žŠ์–ด๋ฒ„๋ ธ๋‹ค.

ํšŒ์ƒ‰ ์˜์—ญ 1 โ€“ ํ…Œ์ŠคํŠธ


๋น„๋™๊ธฐ์„ฑ ๋•Œ๋ฌธ์— React.lazy์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์€ ์‰ฝ์ง€ ์•Š๋‹ค.์•„์ง ๋ถˆ๋Ÿฌ์˜ค์ง€ ์•Š์•˜๋‹ค๋ฉด (๋ถˆ๋Ÿฌ์˜ค๋”๋ผ๋„) ๋น„์–ด ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. Promises๊ณผ import์ด ๋˜๋Œ์•„์˜ค๊ณ  ๋ ˆ์ด์ง€๋Š” ์•ฝ์†์„ ๋ฐ›์•„๋“ค์ž…๋‹ˆ๋‹ค. ์ด ์•ฝ์†๋“ค์€ ํ•ญ์ƒ ๋‹ค์Œ ๋˜‘๋”ฑ๊ฑฐ๋ฆฌ๋Š” ์†Œ๋ฆฌ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.
๋น„๋™๊ธฐ์ ์ธ ํŠน์„ฑ ๋•Œ๋ฌธ์— React.lazy์„ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์€ ์‰ฝ์ง€ ์•Š๋‹ค.mount(MyLazyComponent) ๋’ค์— ์žˆ๋Š” "์ง„์‹ค"Component์ด ๋ถˆ๋Ÿฌ์˜ค์ง€ ์•Š์œผ๋ฉด MyLazy์˜ ๊ฒฐ๊ณผ๋Š”'๋น„์–ด ์žˆ์„ ๋ฟ์ž…๋‹ˆ๋‹ค.-import์ด ๋Œ์•„์˜ค๋”๋ผ๋„ lazy์€ ์Šน๋‚™ํ•˜๊ณ  ์Šน๋‚™์€ ํ•ญ์ƒ ๋‹ค์Œ ๋˜‘๋”ฑ๊ฑฐ๋ฆฌ๋Š” ์†Œ๋ฆฌ์—์„œ ์ง‘ํ–‰๋œ๋‹ค.๊ทธ๋ž˜์„œโ€Šโ€”โ€Šํ˜„์žฌ ๋ˆˆ๊ธˆ์—์„œ ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ์˜์›ํžˆ ์–ป์„ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.์ด๊ฒƒ์€ ๋ฒ•๋ฅ ์ด๋‹ค!
const LazyComponent = lazy(() => import('/path/to/dynamic/component'));
const Fallback = () => <div />;
const SuspenseComponent = () => (
    <Suspense fallback={<Fallback />}>
      <LazyComponent />
    </Suspense>
);
const wrapper = mount(<SuspenseComponent />)
expect(wrapper.find('Fallback')).to.have.lengthOf(1)
expect(wrapper.find('DynamicComponent')).to.have.lengthOf(0)
// ^ not loaded

await wrapper.waitUntilLazyLoaded()
// ^ Oh god, why!?

expect(wrapper.find('Fallback')).to.have.lengthOf(0)
expect(wrapper.find('DynamicComponent')).to.have.lengthOf(1)
// ^ loaded!
์ œ์•ˆ๋œ ์†”๋ฃจ์…˜?๋ฏฟ์ง€ ๋ชปํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์ œ์•ˆ๋œ ํ•ด๊ฒฐ ๋ฐฉ์•ˆ์€ ๋™๊ธฐํ™” ํ…Œ์ด๋ธ”์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

lazy () ๋ฅผ ์ง€์›ํ•˜๋Š”sync thenables #14626



gaearon
๋Œ“๊ธ€ Jan 18, 2019
์šฐ๋ฆฌ ์™œ ์•ˆ ํ•˜์ง€?ํ˜„์žฌ ๊ฒฝ์Ÿ ์กฐ๊ฑด ๋•Œ๋ฌธ์— ์‹คํŒจํ–ˆ๊ณ  ๊ณคํ˜น์Šค๋Ÿฌ์šด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. (์ƒํƒœ๋Š” ํ•ด๊ฒฐ๋˜์—ˆ์ง€๋งŒ ๊ฒฐ๊ณผ๋Š” ๋‹ค์Œ ์ค„๋กœ ๋ฎ์–ด์”๋‹ˆ๋‹ค.)์ด๊ฒƒ์€ ๊ทธ๊ฒƒ์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.
๋‚˜๋Š” ์ด๊ฒƒ์ด ํ…Œ์ŠคํŠธ์— ์œ ์šฉํ•  ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค.https://github.com/airbnb/enzyme/issues/1917#issuecomment-454208642 ์ฐธ์กฐ.์‚ฌ๋žŒ๋“ค์ด ๋™๊ธฐํ™” ํ™˜๊ฒฝ์—์„œ waitForLazyLoaded๊ณผ ๊ฐ™์€ ๋ณ€ํ†ต ๋ฐฉ๋ฒ•์„ ์ฐพ๋Š” ๊ฒƒ์€ ๋งค์šฐ ๋‚œ์ฒ˜ํ•˜๋‹ค.sync-thenables๋ฅผ ์ง€์›ํ•˜๋Š” ๊ฒƒ์€ ์ข‹์€ ํ•ด๊ฒฐ ๋ฐฉ์•ˆ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
View on GitHub
๊ทธ๋Ÿผ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ๋™๊ธฐํ™”ํ•˜์ž!!
const LazyText = lazy(() => ({
   then(cb) {   
      cb({default: Text});
      // this is "sync" thenable
   },
}));     
const root = ReactTestRenderer.create(
  <Suspense fallback={<Text text="Loading..." />}>          
     <LazyText text="Hi" /> // this lazy is not very lazy
  </Suspense>,
);
๊ฐ€์ ธ์˜ค๊ธฐ ํ•จ์ˆ˜๋ฅผ ๋ฉ”๋ชจ๋ฆฌ ๋™๊ธฐํ™”๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ์€ ์–ด๋ ต์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
const syncImport = (importFn) => {
   let preloaded = undefined;
   const promise = importFn().then(module => preloaded = module);
   // ^ "auto" import and "cache" promise   
   return () => preloaded ? { then: () => preloaded } : promise;
   // ^ return sync thenable then possible
}
const lazyImport = isNode ? syncImport : a => a; 
// ^ sync for node, async for browser
const LazyComponent = React.lazy(lazyImport(() => import('./file'));

ํšŒ์ƒ‰ ์˜์—ญ 2 โ€“ SSR


If you DON'T need SSR โ€“ please continue reading the article!

React.lazy์€ SSR ์นœํ™”์ ์ž…๋‹ˆ๋‹ค.๊ทธ๋Ÿฌ๋‚˜ ์„œ๋ฒ„์ธก์— ๋Œ€ํ•œ ๊ถ๊ธˆ์ฆ์€ Suspense์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.
๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋‘ ๊ฐ€์ง€ ์†”๋ฃจ์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์€ ์‹œ๋ฎฌ๋ ˆ์ด์…˜์„ ํ†ตํ•ด ์„œ์ŠคํŽœ์Šค๋ฅผ ๋ถ€๋ถ„์ ์œผ๋กœ ๋Œ€์ฒดํ•ฉ๋‹ˆ๋‹ค.๊ทธ๋ฆฌ๊ณ  import์˜ ์ˆ˜์ • ๋ฒ„์ „์„ ๋™๊ธฐํ™” then๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ lazy๋„ ๋™๊ธฐํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • import React from 'react';
    const realLazy = React.lazy;
    React.lazy = importer => realLazy(syncImport(importer));
    React.Suspense = React.Fragment; // :P
    // ^ React SSR just got fixed :D
    
    ์ด๊ฒƒ์€ ์ข‹์€ ์„ ํƒ์ด์ง€๋งŒ, ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๊ทธ๋‹ค์ง€ ์šฐํ˜ธ์ ์ด์ง€ ์•Š๋‹ค.์™œ?๋‘ ๋ฒˆ์งธ ๊ฐ€๋Šฅํ•œ ์†”๋ฃจ์…˜์„ ์ •์˜ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.
  • ์€ ์‚ฌ์šฉํ•œ ์Šคํฌ๋ฆฝํŠธ, ๋ธ”๋ก, ์Šคํƒ€์ผ์„ ์ถ”์ ํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ์— ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค. (ํŠนํžˆ ์Šคํƒ€์ผ!)์ˆ˜ํ•ฉ ๋ฐ˜์‘ํ•˜๊ธฐ ์ „์—๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ฝ”๋“œ ๋ถ„ํ•  ์–ด์…ˆ๋ธ”๋ฆฌ๊ฐ€ ์•„๋‹Œ ๋นˆ ๊ตฌ๋ฉ์ด ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.๋‹ค์‹œ ํ•œ ๋ฒˆ ๋งํ•˜์ง€๋งŒ, ๋ฐฉ๊ธˆ ๋ถ„ํ• ๋œ ์ฝ”๋“œ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ Œ๋”๋งํ•  ๋‚ด์šฉ์„ ๋ Œ๋”๋งํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ์ฝ”๋“œ ๋ถ„ํ•  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ


  • Universal-component - ๊ฐ€์žฅ ์˜ค๋ž˜๋˜๊ณ  ์œ ์ง€ ๋ณด์ˆ˜๊ฐ€ ๊ฐ€๋Šฅํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.๊ทธ๊ฒƒ์€ ์ฝ”๋“œ ๋ถ„ํ• ์„ ๋ฐœ๋ช…ํ–ˆ๋‹ค. ์›น ํŽ˜์ด์ง€์— ์ฝ”๋“œ ๋ถ„ํ• ์„ ๊ฐ€๋ฅด์ณค๋‹ค.

  • React-loadable โ€“ ๋งค์šฐ ์œ ํ–‰ํ•˜์ง€๋งŒ ์œ ์ง€๋˜์ง€ ์•Š๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.์ฝ”๋“œ๋กœ ๊ฐ€๋ž˜๋ฅผ ๋ฑ‰๋Š” ๊ฒƒ์ด ์œ ํ–‰ํ•˜๋Š” ์ผ์ด ๋˜์—ˆ๋‹ค.๋ฌธ์ œ๋Š” ํ์‡„์ ์ด์–ด์„œ ์ฃผ๋ณ€์— ์ง€์—ญ์‚ฌํšŒ๊ฐ€ ์—†๋‹ค.

  • Loadable-components โ€“ ๊ธฐ๋Šฅ์ด ์™„์ „ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์‚ฌ์šฉ์ด ์ฆ๊ฒ๊ณ  ์ฃผ์œ„์— ๊ฐ€์žฅ ํ™œ๋ฐœํ•œ ์ง€์—ญ์‚ฌํšŒ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  • Imported-component - ๋‹จ์ผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ ์›น ํŒจํ‚ค์ง€์— ๊ท€์†๋˜์ง€ ์•Š๊ณ  ํŒจํ‚ค์ง€๋‚˜ esm๋ฅผ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • React-async-component โ€“ ์ด๋ฏธ ์ฃฝ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ (๊ทธ๋Ÿฌ๋‚˜ ์œ ํ–‰) ๋Š” ์ฝ”๋“œ ๋ถ„ํ• , ์‚ฌ์šฉ์ž ์ •์˜ ๋ฐ˜์‘ ํŠธ๋ฆฌ๋ฅผ ๋‘˜๋Ÿฌ์‹ผ ๋ชจ๋“  ๊ฒƒ์— ํฐ ์˜ํ–ฅ์„ ๋ฏธ์ณค๋‹ค.
  • ์˜ ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ - ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์ค‘ ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์›น ํŽ˜์ด์ง€์˜ ์ง„ํ™”๋‚˜ React 16์—์„œ ์‚ด์•„๋‚จ์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. - ์ €๋Š” ์—ฌ๊ธฐ์— ๊ทธ๊ฒƒ๋“ค์„ ์—ด๊ฑฐํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ข‹์€ ํ›„๋ณด์ž๋ฅผ ์•Œ๊ณ  ์žˆ๋‹ค๋ฉด - DM๋งŒ ์žˆ์œผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
  • ์–ด๋Š ๋„์„œ๊ด€์„ ์„ ํƒํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?


    ๊ทธ๊ฒƒ์€ ๋งค์šฐ ์‰ฝ๋‹ค. - ๋ฐ˜์‘ํ•  ์ˆ˜ ์—†๋‹ค. - ๊ทธ๊ฒƒ์€ ๋ฌด๊ฒ๊ณ , ์œ ์ง€ ๋ณด์ˆ˜๊ฐ€ ์—†๊ณ , ์œ ํ–‰์ด ์ง€๋‚ฌ์ง€๋งŒ, ์„ค๋ น ๊ทธ๊ฒƒ์ด ์—ฌ์ „ํžˆ ๋งค์šฐ ์œ ํ–‰ํ•˜๋”๋ผ๋„.(์ฝ”๋“œ ๋ถ„ํ• ์„ ํ™๋ณดํ•ด ์ฃผ์…”์„œ ๋‹ค์‹œ ํ•œ ๋ฒˆ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค)
    ๊ตฌ์„ฑ ์š”์†Œ๋ฅผ ๋กœ๋“œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ข‹์€ ์„ ํƒ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.๊ทธ๊ฒƒ์€ ๋งค์šฐ ์ž˜ ์จ์„œ ๋ชจ๋“  ์ƒ์ž๋ฅผ ์—ด๋ฉด ๋ฐ”๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ ๊ทน์ ์œผ๋กœ ๋ณดํ˜ธํ•˜๊ณ  ์ง€์ง€ํ•œ๋‹ค.[์™„์ „ ๋™์  ๊ฐ€์ ธ์˜ค๊ธฐ]๋ฅผ ์ง€์›ํ•˜์—ฌ ์ฃผ์–ด์ง„ ๋„๊ตฌ์— ๋”ฐ๋ผ ํŒŒ์ผ์„ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์ง€๋งŒ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.์„œ์ŠคํŽœ์Šค๊ฐ€ ์ง€์›๋˜๋ฏ€๋กœ React ๋Œ€์‹  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.๊ฒŒ์œผ๋ฅด๋‹ค
    ์ผ๋ฐ˜ ๊ตฌ์„ฑ ์š”์†Œ๋Š” ์‹ค์ œ๋กœ ์™„์ „ํžˆ ๋™์ ์œผ๋กœ ๊ฐ€์ ธ์˜จ ๋ฐœ๋ช…์ž์ด๋‹ค. ๊ทธ๋“ค์€ ์›น ํŒจํ‚ค์ง€์—์„œ ๊ทธ๊ฒƒ์„ ์‹คํ˜„ํ–ˆ๋‹ค.๊ทธ๋ฆฌ๊ณ  ๋‹ค๋ฅธ ๋งŽ์€ ๋‚ฎ์€ ์ˆ˜์ค€์˜ ์ผ๋“ค์„ ๊ทธ๋“ค์€ ํ•ด๋ƒˆ๋‹ค.๋‚ด๊ฐ€ ๋งํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฒƒ์€ ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์•ฝ๊ฐ„ ํ•˜๋“œ์ฝ”์–ด๊ฐ€ ์žˆ์–ด์„œ ์‚ฌ์šฉ์ž์˜ ์šฐํ˜ธ์„ฑ์ด ์•ฝ๊ฐ„ ๋–จ์–ด์ง„๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.๊ตฌ์„ฑ ์š”์†Œ ๋ฌธ์„œ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ๋น„๊ธธ ๋ฐ๊ฐ€ ์—†๋‹ค.์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฌธ์„œ๋ฅผ ์ฝ์œผ์‹ญ์‹œ์˜คโ€Š-โ€Š๋””ํ…Œ์ผ์ด ๋งŽ์œผ์‹  ๊ฑฐ ์•„์‹œ๊ฒ ์ง€๋งŒ...
    React ๊ฐ€์ ธ์˜ค๊ธฐ ๊ตฌ์„ฑ ์š”์†Œ - ์ข€ ์ด์ƒํ•ฉ๋‹ˆ๋‹ค.์ด๊ฒƒ์€ ๋ฌถ์Œ ํ”„๋กœ๊ทธ๋žจ์— ๋…๋ฆฝ์ ์ด๊ธฐ ๋•Œ๋ฌธ์— ์˜์›ํžˆ ๋‚˜์˜์ง€ ์•Š์œผ๋ฉฐ ์›น ํŒฉ 5์™€ 55์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์ด๊ฒƒ์€ ์›๊ฐ€๊ฐ€ ์žˆ๋‹ค.SSR ๊ธฐ๊ฐ„ ์ด์ „์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ์‚ฌ์šฉํ•œ ๋ชจ๋“  ์Šคํฌ๋ฆฝํŠธ๋ฅผ ํŽ˜์ด์ง€ ๋ณธ๋ฌธ์— ์ถ”๊ฐ€ํ•˜์ง€๋งŒ, ๋ชจ๋“  ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋™์‹œ์— ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. - ๊ฐ€์ ธ์˜จ ์•Œ ์ˆ˜ ์—†๋Š” ํŒŒ์ผ ์ด๋ฆ„๊ณผ ์›๋ณธ'๋„์ž…'(์ด๊ฒƒ์ด ๋ฐ”๋กœ ํŒจํ‚ค์ง€์™€ ๋…๋ฆฝ์ ) ์„ ํ˜ธ์ถœํ•ด์„œ ์‚ฌ์šฉํ•œ ๋ธ”๋ก์„ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.๊ทธ๋Ÿฌ๋‚˜ ์ฃผ ๋ฒˆ๋“ค ๋‚ด๋ถ€์—์„œ๋งŒ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ ๋ฒˆ๋“ค์„ ๋‹ค์šด๋กœ๋“œํ•˜๊ณ  ์‹คํ–‰ํ•œ ํ›„์—๋งŒ ๋ชจ๋“  ๋‹ค๋ฅธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.React์™€ ๊ฐ™์€ ์ „์ฒด ๋™์  ๊ฐ€์ ธ์˜ค๊ธฐ๋Š” ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.๊ฒŒ์œผ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ํƒ€์ž๋ฅผ ์น  ์ˆ˜ ์žˆ๋‹ค.๊ถ๊ธˆ์ฆ๋„ ์ง€์ง€ํ•ฉ๋‹ˆ๋‹ค.SSR์— ๋™๊ธฐํ™” ๋ ˆ์ด๋ธ”์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.๋˜ํ•œ ์™„์ „ํžˆ ๋‹ค๋ฅธ CSS ๋ฐฉ๋ฒ•๊ณผ ์™„๋ฒฝํ•œ ๋ Œ๋”๋ง ์ง€์›์ด ์žˆ์Šต๋‹ˆ๋‹ค.
    ์—ด๊ฑฐํ•œ ๋„์„œ๊ด€์€ ์งˆ๊ณผ ์ธ๊ธฐ์˜ ์ •๋„์— ์ฐจ์ด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋ชจ๋‘ ์ข‹์€ ์นœ๊ตฌ์ด๊ธฐ ๋•Œ๋ฌธ์— ์—ด์‹ฌํžˆ ์„ ํƒํ•˜์‹ญ์‹œ์˜ค.

    ๋งค๋„๋Ÿฌ์šด ์ฝ”๋“œ / ์–ด์…ˆ๋ธ”๋ฆฌ ๋กœ๋“œ ๊ฐ€๋Šฅ


    React ์ฝ”๋“œ ๋ฒ„์ŠคํŠธ ๋‹จ์ˆœํ™”โœ‚๏ธโœจ



    React ์ฝ”๋“œ ๋ถ„ํ• ์ด ๊ฐ„๋‹จํ•ด์ง‘๋‹ˆ๋‹ค.์†Œํฌ์˜ ํฌ๊ธฐ๋ฅผ ์ค„์ด๊ณ  ์••๋ ฅ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋„๋ก ํ•˜๋‹คโœ‚๏ธโœจ.








    npm install @loadable/component

    ๋ฌธ์„œ

    See the documentation at smooth-code.com/open-source/loadable-components for more information about using Loadable Components!

    Quicklinks to some of the most-visited pages:

    ์ธ์Šคํ„ด์Šค

    import loadable from '@loadable/component'
    const OtherComponent = loadable(() => import('./OtherComponent'))
    function MyComponent() {
      return (
        <div>
          <OtherComponent />
        </div>
      )
    }

    ๋กœ๋“œ ๊ฐ€๋Šฅ ๊ตฌ์„ฑ ์š”์†Œ ์ง€์›

    Loadable Components is an MIT-licensed open source project. It's an independent project with ongoing development made possible thanks to the support of these awesome backers. If you'd like to join them, please consider:

    ๊ธˆ๋ฉ”๋‹ฌ ์Šคํฐ์„œ

    Gold Sponsors are those who have pledged $100/month and more to loadable.

    ๋ผ์ด์„ผ์Šค

    Licensed under the MIT License, Copyright ยฉโ€ฆ

    ํ‹ฐ์นด์‹œ / react ๊ฐ€์ ธ์˜จ ๊ตฌ์„ฑ ์š”์†Œ

    โœ‚๏ธ๐Ÿ“ฆ๋ฒˆ๋“ค ํ”„๋กœ๊ทธ๋žจ๊ณผ ๋ฌด๊ด€ํ•œ SSR ์นœ์„  ์ฝ”๋“œ ๋ถ„ํ•  ์†”๋ฃจ์…˜

    ๊ฐ€์ ธ์˜จ ๊ตฌ์„ฑ ์š”์†Œโœ‚

    ์ฝ”๋“œ ๋ฒ„์ŠคํŠธ๋Š” ํ•ญ์ƒ ์œ ํšจํ•ฉ๋‹ˆ๋‹ค*




    SSR-friendly code splitting compatible with any platform
    Deliver a better experience within a single import


    * It's really will never let you down. All credits to your bundler.

    ๐Ÿ‘‰ Usage | API | Setup | SSR | CCS Concurrent loading | Webpack/Parcel

    Library Suspense SSR Hooks Library Non-modules import(./${value}) babel-macro webpack only
    React.lazy โœ… โŒ โŒ โŒ โŒ โŒ ๐Ÿ˜น
    react-loadable โœ… โœ… โŒ โŒ โœ… โŒ โŒ ๐Ÿ˜ฟ
    @loadable/component โœ… โœ… โŒ โœ… โŒ โœ… โŒ ๐Ÿ˜ฟ
    imported-component โœ… โœ… โœ… โœ… โœ… โŒ โœ… ๐Ÿ˜ธ

    Read more about what this table displays

    Key features:

    • 1๏ธโƒฃ Single source of truth - your bundler drives everything
    • ๐Ÿ“– library level code splitting
    • ๐Ÿง™๏ธ Hybrid and Prerendering compatible
    • ๐Ÿ’ก TypeScript bindings
    • โš›๏ธ React.Lazy underneath (if hot module updates are disabled)
    • ๐ŸŒŸ Async on client, sync on server. Supports Suspense (even onโ€ฆ

    ์–ผ๊ตด ๊ณต๊ฐ„ / react ๊ณตํ†ต ๊ตฌ์„ฑ ์š”์†Œ

    ๐Ÿš€ React ๊ณตํ†ต ๊ตฌ์„ฑ ์š”์†Œ์˜ ์ตœ์ข… ๋‹ต์•ˆ: SSR+ ์ฝ”๋“œ ๋ถ„ํ•  ๋™๊ธฐํ™”

    React ๊ณตํ†ต ๊ตฌ์„ฑ ์š”์†Œ

    ๐Ÿพ๐Ÿพ๐Ÿพ GIT CLONE 3.0 LOCAL DEMO ๐Ÿš€๐Ÿš€๐Ÿš€

    ์†Œ๊ฐœ

    For "power users" the traditional SPA is dead. If you're not universally rendering on the server, you're at risk of choking search engine visibility. As it stands, SEO and client-side rendering are not a match for SSR. Even though many search engines claim better SPA indexing, there are many caveats. Server-side rendering matters: JavaScript & SEO Backfire โ€“ A Hulu.com Case Study

    The real problem has been simultaneous SSR + Splitting. If you've ever attempted such, you know. Here is a one-of-a-kind solution that brings it allโ€ฆ

    ํšŒ์ƒ‰ ์˜์—ญ 3 โ€“ ํ˜ผํ•ฉ ๋ Œ๋”

    SSR is a good thing, but, you know, hard. Small projects might want to have a SSR โ€“ there are a lot of reasons to have it โ€“but they might not want to setup and maintain it.

    SSR could be really, REALLY hard. Try razzle or go with Next.js if you want a quick win.

    So the easiest my solution for SSR, especially for simple SPA would be prerendering. Like opening your SPA in a browser and hitting "Save" button. Like:

    • React-snapโ€Š-โ€Šuses puppeteer(aka headless Chrome) to render your page in a "browser" and saves a result as a static HTML page.
    • Rendertronโ€Š-โ€Šwhich does the same, but in a different (cloud) way.

    Prerendering is "SSR" without "Server". It's SSR using a Client. Magic! And working out of the boxโ€ฆ โ€ฆ โ€ฆ but not for code-spitting.
    Soโ€Š-โ€Šyou just rendered your page in a browser, saved HTML, and asked to load the same stuff. But Server Side Specific Code (to collect all used chunks) was not used, cos THERE IS NO SERVER!

    In the previous part, I've pointed to libraries which are bound to webpack in terms of collecting information about used chunksโ€Š-โ€Šthey could not handle hybrid render at all.

    Loadable-components version 2(incompatible with current version 5), was partially supported by react-snap. Support has gone.

    React-imported-component could handle this case, as long as it is not bound to the bundler/side, so there is no difference for SSR or Hybrid, but only for react-snap, as long as it supports "state hydration", while rendertron does not.

    This ability of react-imported-component was found while writing this article, it was not known beforeโ€Š-โ€Šsee example. It's quite easy.

    And here you have to use another solution, which is just perpendicular to all other libraries.

    ๋ฏธ๋ฆฌ ๋ Œ๋”๋ง ์–ด์…ˆ๋ธ”๋ฆฌ ๋ฐ˜์‘

    This library was created for partial hydration, and could partially rehydrate your app, keeping the rest still de-hydrated. And it works for SSR and Hybrid renderers without any difference.
    The idea is simple:

    • during SSRโ€Š-โ€Šrender the component, wrapped with a
    • on the clientโ€Š-โ€Šfind that div, and use innerHTML until Component is ready to replace dead HTML.
    • you don't have to load, and wait for a chunk with split component to NOT render a white hole instead of itโ€Š-โ€Šjust use pre-rendered HTML, which is absolutely equal to the one a real component would render, and which already exists - it comes with a server(or hybrid) response .

    That's why we have to wait for all the chunks to load before hydrateโ€Š-โ€Što match server-rendered HTML. That's why we could use pieces of server-rendered HTML until the โ€‹client is not ready - it is equal to the one we are only going to produce.

    import {PrerenderedComponent} from 'react-prerendered-component';
    const importer = memoizeOne(() => import('./Component'));
    // ^ it's very important to keep the "one" promise
    const Component = React.lazy(importer); 
    // or use any other library with ".prefetch" support
    // all libraries has it (more or less)
    const App = () => (
      <PrerenderedComponent live={importer()}> 
       {/* ^ shall return the same promise */ }
          <Component /> 
       {/* ^ would be rendered when component goes "live" */ }
      </PrerenderedComponent>
    );
    

    ํ‹ฐ์นด์‹œ / ๋ฏธ๋ฆฌ ๋ Œ๋”๋ง ์–ด์…ˆ๋ธ”๋ฆฌ ๋ฐ˜์‘


    ๐Ÿค”์ „ ์‹œ๋Œ€์˜ ์ผ๋ถ€ ์ˆ˜ํ•ฉ ์ž‘์šฉ๊ณผ ์บ์‹œ๋ฅผ ์—ผ๋ คํ•˜๋‹ค


    ๋ฏธ๋ฆฌ ๋ Œ๋”๋ง ์–ด์…ˆ๋ธ”๋ฆฌ ๋ฐ˜์‘


    ๋ถ€๋ถ„ ์ˆ˜ํ™” ๋ฐ ์–ด์…ˆ๋ธ”๋ฆฌ ๋ ˆ๋ฒจ ์บ์‹œ

    ์ƒ๊ฐ


    ๊ฐ„๋‹จํžˆ ๋งํ•˜๋ฉด: js ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ ค๊ณ  ํ•˜์ง€ ๋ง๊ณ  ๋ฏธ๋ฆฌ ๋ Œ๋”๋ง ํŠธ๋ฆฌ์™€ ์ผ์น˜ํ•˜๋Š”react ํŠธ๋ฆฌ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค
    ๊ทธ๋Ÿฌ๋‚˜ js ์ฝ”๋“œ๊ฐ€ ๊ต์ฒด๋  ์ค€๋น„๊ฐ€ ๋˜๊ธฐ ์ „์— ๋ฏธ๋ฆฌ ๋ณด์—ฌ์ค€ html๋ฅผ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค.์‚ด๋ ค์ค˜.
    HTML ๋ ˆ๋ฒจ์—์„œ๋Š” ๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๊นŒ?์บ์‹œ, ํ…œํ”Œ๋ฆฟํ™” ๋ฐ ๊ธฐํƒ€ ์ข‹์€ ๊ฒƒ๐Ÿš€, 3kb*๋งŒ ์ง€์›๋ฉ๋‹ˆ๋‹ค.

    ๋ฏธ๋ฆฌ ๋ Œ๋”๋ง ์–ด์…ˆ๋ธ”๋ฆฌ


    Render something on server, and use it as HTML on the client

  • ์„œ๋ฒ„ ์ธก ๋ Œ๋”๋ง ๋ฐ์ดํ„ฐ
  • ์–ด๋”˜๊ฐ€์— thisIsServer์œผ๋กœ ์ „ํ™”๋ฅผ ๊ฑธ์–ด ํ™˜๊ฒฝ์„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ฐ˜์‘ ๋ฏธ๋ฆฌ ๋ Œ๋”๋ง ๊ตฌ์„ฑ ์š”์†Œ will leave trails, ์ด๋ฏธ ์•Œ๊ณ  ์žˆ๋Š” id๋ฅผ ๊ฐ€์ง„div๋กœ ๋ชจ๋“  ๋ธ”๋ก์„ ๊ฐ์‹ธ์ค๋‹ˆ๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ
  • React ํ”„๋ฆฌ์  ํ…Œ์ด์…˜ ๊ตฌ์„ฑ ์š”์†Œ๋Š” ์•Œ๋ ค์ง„ ID๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ณ  read rendered HTML์€ ํŽ˜์ด์ง€์—์„œ ๋Œ์•„์˜ต๋‹ˆ๋‹ค.
  • ์‚ฌ์ดํŠธ ์ค€๋น„ ์™„๋ฃŒ
  • React ์‚ฌ์ „ ๋ Œ๋”๋ง ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ์ค€๋น„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.์„œ๋ฒ„์—์„œ ๋ณด๋‚ธ ๋ฏธ๋ฆฌ ์กด์žฌํ•˜๋Š” HTML์„ ๋ณด์—ฌ์ฃผ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
  • ๋ชจ๋“  ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๊ต์ฒด๋  ์ค€๋น„๊ฐ€ ๋˜๋ฉด - ์ˆ˜ํ™”๋ฌผ
  • , ํ•˜์ง€๋งŒ ๊ทธ ์ด์ „์€ ์•„๋‹™๋‹ˆ๋‹ค.์ด๊ฒŒ...
  • ์ž…๋‹ˆ๋‹ค.
    View on GitHub

    ๋„ˆ๋ฌด ๊ธธ์–ด์„œ ์ฝ์„ ์ˆ˜๊ฐ€ ์—†์–ด์š”.

  • reactloadable๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค. ๊ฐ€์น˜ ์žˆ๋Š” ๊ฐ’์„ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๋ฐ˜์‘.๊ฒŒ์œผ๋ฆ„๋„ ์ข‹์ง€๋งŒ ๋„ˆ๋ฌด ๊ฐ„๋‹จํ•˜๋‹ค.
  • SSR์€ ์–ด๋ ค์šด ์ผ์ž…๋‹ˆ๋‹ค.
  • ์ด๋ผ๋Š” ๊ฒƒ์„ ์•„์…”์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ํ˜ผํ•ฉ ์ธํ˜• ๊ตฌ๋™ ๋ Œ๋”๋ง์€ ์ผ์ž…๋‹ˆ๋‹ค.๋•Œ๋กœ๋Š” ๋” ์–ด๋ ค์šธ ๋•Œ๋„ ์žˆ๋‹ค.
  • ์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ