λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°

FrontEnd/Optimization

μ½”λ“œ μŠ€ν”Œλ¦¬νŒ…

πŸ’‘ Ref:  https://velog.io/@velopert/react-code-splitting#1-μ§„μ§œ-기본적인-μ½”λ“œ-μŠ€ν”Œλ¦¬νŒ…

 

μ½”λ“œ μŠ€ν”Œλ¦¬νŒ… ?

λ¦¬μ•‘νŠΈ μ—μ„œμ˜ μ½”λ“œ μŠ€ν”Œλ¦¬νŒ…? From gpt

λ¦¬μ•‘νŠΈ μ½”λ“œ μŠ€ν”Œλ¦¬νŒ…μ€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ JavaScript μ½”λ“œλ₯Ό 더 μž‘μ€ 청크둜 λΆ„ν• ν•˜μ—¬ ν•„μš”ν•  λ•Œ λ™μ μœΌλ‘œ λ‘œλ“œν•˜λŠ” κΈ°μˆ μž…λ‹ˆλ‹€. 이λ₯Ό 톡해 초기 λ²ˆλ“€ 크기λ₯Ό 쀄이고 νŽ˜μ΄μ§€ λ‘œλ”© 속도λ₯Ό ν–₯μƒμ‹œν‚¬ 수 μžˆμŠ΅λ‹ˆλ‹€.

일반적으둜 λ¦¬μ•‘νŠΈ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ ν•˜λ‚˜μ˜ λ²ˆλ“€ νŒŒμΌμ— λͺ¨λ“  JavaScript μ½”λ“œκ°€ ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 큰 규λͺ¨μ˜ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ 경우 이 λ²ˆλ“€ 파일의 크기가 컀져 초기 λ‘œλ”© μ‹œκ°„μ΄ μ¦κ°€ν•˜κ²Œ λ©λ‹ˆλ‹€. μ½”λ“œ μŠ€ν”Œλ¦¬νŒ…μ„ μ‚¬μš©ν•˜λ©΄ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ„ μ—¬λŸ¬ 개의 μž‘μ€ 청크둜 λΆ„ν• ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

λΆ„ν• λœ μ²­ν¬λŠ” 각각의 κΈ°λŠ₯ λ˜λŠ” λΌμš°νŠΈμ™€ μ—°κ΄€λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, μ‚¬μš©μžκ°€ νŠΉμ • νŽ˜μ΄μ§€λ‘œ 이동할 λ•Œ ν•΄λ‹Ή νŽ˜μ΄μ§€μ— ν•„μš”ν•œ μ½”λ“œλ§Œ λ™μ μœΌλ‘œ λ‘œλ“œλ©λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•¨μœΌλ‘œμ¨ μ‚¬μš©μžκ°€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ— 접속할 λ•Œ ν•„μš”ν•˜μ§€ μ•Šμ€ μ½”λ“œλ₯Ό λΆˆλŸ¬μ˜€μ§€ μ•Šμ•„λ„ λ˜λ―€λ‘œ 초기 λ‘œλ”© 속도가 ν–₯μƒλ©λ‹ˆλ‹€.

λ¦¬μ•‘νŠΈ μ½”λ“œ μŠ€ν”Œλ¦¬νŒ…μ€ **React.lazy()**와 **Suspense**λ₯Ό μ‚¬μš©ν•˜μ—¬ κ΅¬ν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€. React.lazy() ν•¨μˆ˜λŠ” λ™μ μœΌλ‘œ 뢈러올 μ»΄ν¬λ„ŒνŠΈλ₯Ό μ •μ˜ν•˜λŠ” 데 μ‚¬μš©λ˜λ©°, Suspense μ»΄ν¬λ„ŒνŠΈλŠ” λ™μ μœΌλ‘œ λ‘œλ“œλ˜λŠ” μ»΄ν¬λ„ŒνŠΈλ₯Ό λŒ€κΈ°ν•˜κ³  λ‘œλ”© μƒνƒœλ₯Ό μ²˜λ¦¬ν•˜λŠ” 데 μ‚¬μš©λ©λ‹ˆλ‹€.
κ°„λ‹¨ν•œ μ˜ˆμ‹œλ₯Ό 톡해 μ½”λ“œ μŠ€ν”Œλ¦¬νŒ…μ„ 이해해 λ³΄κ² μŠ΅λ‹ˆλ‹€:
import React, { lazy, Suspense } from 'react';

const LazyComponent = lazy(() => import('./LazyComponent'));

const App = () => {
  return (
    <div>
      <h1>My React App</h1>
      <Suspense fallback={<div>Loading...</div>}>
        <LazyComponent />
      </Suspense>
    </div>
  );
};

export default App;

 

μ°Έκ³ ) lazy, suspenseλ₯Ό μ‚¬μš©ν•˜λŠ”κ²Œ μ•„λ‹Œ 일반 μ½”λ“œ μŠ€ν”Œλ¦¬νŒ…

import React, { Component } from 'react';

class App extends Component {
  state = {
    SplitMe: null
  };
  handleClick = () => {
    import('./SplitMe').then(({ default: SplitMe }) => {
      this.setState({
        SplitMe
      });
    });
  };
  render() {
    const { SplitMe } = this.state;
    return (
      <div>
        <button onClick={this.handleClick}>Click Me</button>
        {SplitMe && <SplitMe />}
      </div>
    );
  }
}

export default App;
μœ„μ˜ μ˜ˆμ‹œμ—μ„œ **LazyComponent**λŠ” μ½”λ“œ μŠ€ν”Œλ¦¬νŒ…μ„ μ μš©ν•˜κ³ μž ν•˜λŠ” μ»΄ν¬λ„ŒνŠΈμž…λ‹ˆλ‹€. React.lazy() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ ν•΄λ‹Ή μ»΄ν¬λ„ŒνŠΈλ₯Ό λ™μ μœΌλ‘œ λ‘œλ“œν•©λ‹ˆλ‹€. Suspense μ»΄ν¬λ„ŒνŠΈλŠ” **LazyComponent**κ°€ λ‘œλ”©λ˜λŠ” λ™μ•ˆ λ‘œλ”© μƒνƒœλ₯Ό μ²˜λ¦¬ν•©λ‹ˆλ‹€.
μ΄λ ‡κ²Œ μ½”λ“œλ₯Ό μž‘μ„±ν•˜λ©΄ **LazyComponent**λŠ” νŽ˜μ΄μ§€μ— μ‹€μ œλ‘œ ν•„μš”ν•œ μ‹œμ μ—μ„œλ§Œ λ‘œλ“œλ˜λ―€λ‘œ 초기 λ‘œλ”© μ‹œκ°„μ΄ μ€„μ–΄λ“€κ²Œ λ©λ‹ˆλ‹€.
λ¦¬μ•‘νŠΈ μ½”λ“œ μŠ€ν”Œλ¦¬νŒ…μ€ 주둜 동적 λ‘œλ”©, λΌμš°νŒ… λ˜λŠ” μ‚¬μš©μž μ•‘μ…˜μ— λ”°λ₯Έ ν•„μš”ν•œ μ»΄ν¬λ„ŒνŠΈμ˜ λ‘œλ“œ μ‹œμ μ„ μ‘°μ ˆν•˜λŠ” 데 μ‚¬μš©λ©λ‹ˆλ‹€. 이λ₯Ό 톡해 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ μ„±λŠ₯을 μ΅œμ ν™”ν•˜κ³  μ‚¬μš©μž κ²½ν—˜μ„ κ°œμ„ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

 

μ½”λ“œ μŠ€ν”Œλ¦¬νŒ…μ˜ 문제점

SSR

μ»΄ν¬λ„ŒνŠΈκ°€ SSRμ—μ„œ λžœλ”λ§ 될 λ•Œ, λ¬Έμžμ—΄ ν˜•μ‹μœΌλ‘œ λžœλ”λ§μ΄ λœλ‹€.

λ¬Έμžμ—΄ ν˜•μ‹μ΄λΌ 함은 μ•„λž˜ μ½”λ“œλ₯Ό μ°Έκ³ ν•˜λ©΄ 쒋을 λ“― ν•˜λ‹€.

import React from 'react';
import ReactDOMServer from 'react-dom/server';

const App = () => {
  return <h1>Hello, World!</h1>;
};

const html = ReactDOMServer.renderToString(<App />); <-- μš”λΆ€λΆ„

console.log(html); // Output: <h1>Hello, World!</h1>

즉, λ¬Έμžμ—΄ ν˜•μ‹μ€ HTML markup λ‚΄μš©λ§Œ μžˆμ„ 뿐이닀. λ”°λΌμ„œ λ¬Έμžμ—΄ ν˜•μ‹μœΌλ‘œ λžœλ”λ§ λœλ‹€λŠ” 것은 HTML markup λ‚΄μš©λ§Œ λžœλ”κ°€ λœλ‹€λŠ” 것과 λ™μΌν•˜λ‹€.

κ·Έλ ‡κΈ° λ•Œλ¬Έμ—, μ½”λ“œ μŠ€ν”Œλ¦¬νŒ…μ„ μœ„ν•œ dynamic imports을 μ‹€ν–‰ ν•  μˆ˜κ°€ μ—†λ‹€.

ν•΄κ²°λ°©μ•ˆ

  • react-loadable을 μ‚¬μš©ν•¨μœΌλ‘œμ¨, νŽ˜μ΄μ§€ λ‘œλ”©μ„ ν•  λ•Œ λΆ€ν„° μ²­ν¬νŒŒμΌλ“€μ„ λ‹€λ₯Έ μžλ°”μŠ€ν¬λ¦½νŠΈνŒŒμΌλ“€κ³Ό λ™μΌν•œ μ‹œμ μ—μ„œ λ‘œλ”©μ„ μ‹œμž‘ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.