Code Spliting

hyena_lee·2023년 3월 23일
0

React

목록 보기
8/10
post-thumbnail

React의 주목해야 할 기능

  • React는 현재도 계속해서 업데이트가 되고 있는 오픈소스 라이브러리입니다. 이번에 React가 버전 18로 업데이트가 되면서 많은 부분이 바뀌었는데, 가장 빠르게 알아볼 수 있는 변화는 콘솔 창에 이전에 보이지 않던 경고문이 보인다는 점입니다.

    [그림] React 18로 업데이트 된 뒤 보이게 된 경고문

  • 해당 경고문은 이제 React 18 버전은 더이상 ReactDOM.render를 지원하지 않는다는 내용입니다.

  • 물론 버전이 18보다 낮은 앱에서는 해당 경고문은 보이지 않습니다.

  • 그러나 계속해서 업데이트가 되고 있는 라이브러리이니만큼 해당 이슈는 알아둬야 할 것입니다.

  • 언제까지 18 버전 이하만 사용할 일은 없을 것이고, 18버전을 쓰는데도 지원하지 않는 이전의 문법을 사용해서는 안 되기 때문입니다.

const rootElement = document.getElementById("root");
ReactDOM.render(<AppTest />, rootElement);

[코드] React 18이전의 index.js

  • 저런 경고문이 보이는 이유는 React 18에서는 이제 createRoot API를 사용하기 때문이기 때문입니다.
  • React 18에서 생긴 자동 배칭 또한 이 createRoot API를 사용해야 합니다.
import { createRoot } from "react-dom/client";

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
    <App />
);

[그림] 바뀐 index.js

  • 그 중 주목할 부분은 Concurrent Feature입니다.
  • 지금까지는 Concurrent Mode라고 명명되었지만 이번에 Concurrent Feature로 바뀌면서 하나의 기능으로 들어오게 되었습니다.
  • 그 중에는 Suspense 기능이 있는데, React 18 버전부터는 이 Suspense 기능을 이용해 독립적으로 렌더링을 할 수 있도록 했습니다.

코드 분할(Code Spliting)

  • 대부분 React 앱들은 Webpack, Rollup과 같은 툴을 사용해 번들링(Bundling)합니다.
  • 이렇게 하면 HTML 웹 페이지에 JavaScript를 쉽게 추가할 수 있기 때문입니다.
  • 번들된 앱은 모든 JavaScript가 한 곳에 있기 때문에 페이지를 설정하는 데 필요한 호출 수가 적은 링크 태그 하나만 필요하게 됩니다.
  • 과거에는 이렇게 해도 무리가 없었습니다. 모던 웹 이전의 웹 JavaScript 코드는 최소한의 수준으로 작성되었기 때문입니다.

[그림] 이제 브라우저 JavaScript 엔진이 해석해야 하는 JavaScript 코드 양이 많아지게 되었습니다.

  • 그러나 이제는 번들링하게 되면 특정 지점에서 코드를 해석하고 실행하는 정도가 느려지게 되었습니다.
  • 모던 웹으로 발전하면서 점점 DOM을 다루는 정도가 정교해지며 JavaScript 코드 자체가 방대해지고 무거워졌기 때문입니다.

  • “그렇다면 어느 페이지에서 코드를 해석하고 실행하는 정도가 느려졌는지 파악해서 번들을 나눈 뒤에 지금 필요한 코드만 불러오고 나중에 필요한 코드는 나중에 불러올 수 있지 않을까??”

  • 이것이 코드 분할의 핵심 아이디어입니다. 번들이 거대해지는 것을 방지하기 위한 좋은 해결 방법은 번들을 물리적으로 나누는 것입니다. 코드 분할은 런타임 시 여러 번들을 동적으로 만들고 불러오는 것으로, Webpack, Rollup과 같은 번들러가 지원하는 기능입니다.

  • 따라서 코드 분할을 하게 되면 지금 당장 필요한 코드가 아니라면 따로 분리를 시키고, 나중에 필요할 때 불러와서 사용할 수 있습니다.

  • 이를 통하여 대규모 프로젝트의 앱인 경우에도 페이지의 로딩 속도를 개선할 수 있게 됩니다.

번들 분할 혹은 줄이는 법

  • 번들링 되는 파일에는 여러분들이 앱을 만들면서 npm을 통해 다운받는 서드파티(Third Party) 라이브러리도 포함이 됩니다.

  • 서드파티 라이브러리는 개인 개발자나 프로젝트 팀, 혹은 업체등에서 개발하는 라이브러리로, 즉 제 3자 라이브러리 입니다. - 서드파티 라이브러리는 플러그인이나 라이브러리 또는 프레임워크 등이 존재하며, 이 라이브러리를 잘 사용하면 편하고 효율적인 개발을 할 수 있습니다.

  • 그러나 서드파티 라이브러리는 사용자에게 다양한 메소드를 제공하기 때문에 코드의 양이 많고, 번들링 시 많은 공간을 차지합니다.

  • 따라서 사용 중인 라이브러리의 전부를 불러와서 사용하는 것보다 따로 따로 불러와서 사용할 수 있다면 많은 공간을 차지하지 않을 수 있게 됩니다.

/* 이렇게 lodash 라이브러리를 전체를 불러와서 그 안에 들은 메소드를 꺼내 쓰는 것은 비효율적입니다.*/
import _ from 'lodash';

...

_.find([]);

/* 이렇게 lodash의 메소드 중 하나를 불러와 쓰는 것이 앱의 성능에 더 좋습니다.*/
import find from 'lodash/find';

find([]);
  • 해당 코드는 lodash라는 라이브러리를 예시로 하고 있습니다.

  • lodash는 배열, 숫자, 객체, 문자열을 사용할 때 반복적인 작업 같은 것을 할 시 사용하기에 좋은 라이브러리입니다.

  • lodash라는 라이브러리는 하나의 폴더와 같고, 그 폴더 안에는 개발 시 다양한 상황에 쓰기 좋은 메소드들, 즉 함수 코드들이 들어 있습니다.

  • 이 함수 코드들의 양이 상당하기 때문에 전부 가져올 시, 정말로 필요한 것 한두 개만 쓰인다면 나머지는 그냥 쓰이지 않는 코드 뭉치로 앱 내부에 남게 됩니다.

  • 이는 앱의 성능을 저하시킬 요지가 있기 때문에, 필요한 것 한두 개만 가져다 쓰는 식으로 개발하는 것이 훨씬 좋습니다.

React에서의 코드 분할

  • React는 SPA(Single-Page-Application)인데, 사용하지 않는 모든 컴포넌트까지 한 번에 불러오기 때문에 첫 화면이 렌더링 될때까지의 시간이 오래걸립니다.

  • 그래서 사용하지 않는 컴포넌트는 나중에 불러오기 위해 코드 분할 개념을 도입했습니다.

  • React에서 코드 분할하는 방법은 dynamic import(동적 불러오기)를 사용하는 것입니다.

  • 그 전까지는 코드 파일의 가장 최상위에서 import 지시자를 사용해 사용하고자 하는 라이브러리 및 파일을 불러오는 방법을 사용했었습니다.

  • 이를 static import(정적 불러오기)라고 합니다.

Static Import

/* 기존에는 파일의 최상위에서 import 지시자를 이용해 라이브러리 및 파일을 불러왔습니다. */
import moduleA from "library";

form.addEventListener("submit", e => {
  e.preventDefault();
  someFunction();
});

const someFunction = () => {
  /* 그리고 코드 중간에서 불러온 파일을 사용했습니다. */
}
  • 기존에는 항상 import 구문은 문서의 상위에 위치해야 했고, 블록문 안에서는 위치할 수 없는 제약 사항이 있었습니다.

  • 왜냐하면 번들링 시 코드 구조를 분석해 모듈을 한 데 모으고 사용하지 않는 모듈은 제거하는 등의 작업을 하는데, 코드 구조가 간단하고 고정이 되어 있을 때에야만 이 작업이 가능해지기 때문이었습니다.

  • 그러나 이제는 구문 분석 및 컴파일해야 하는 스크립트의 양을 최소화 시키기 위해 dynamic import 구문을 지원합니다.

Dynamic Import

form.addEventListener("submit", e => {
  e.preventDefault();
	/* 동적 불러오기는 이런 식으로 코드의 중간에 불러올 수 있게 됩니다. */
  import('library.moduleA')
    .then(module => module.default)
    .then(someFunction())
    .catch(handleError());
});

const someFunction = () => {
    /* moduleA를 여기서 사용합니다. */
}
  • 이런 식으로 dynamic import를 사용하게 되면 불러온 moduleA 가 다른 곳에서 사용되지 않는 경우, 사용자가 form을 통해 양식을 제출한 경우에만 가져오도록 할 수 있습니다.

  • dynamic import는 then 함수를 사용해 필요한 코드만 가져옵니다. 가져온 코드에 대한 모든 호출은 해당 함수 내부에 있어야 합니다

  • 이 방식을 사용하면 번들링 시 분할된 코드(청크)를 지연 로딩시키거나 요청 시에 로딩할 수 있습니다.

  • 이 dynamic import는 React.lazy 와 함께 사용할 수 있습니다.

profile
실수를 두려워 말고 계속 도전 하는 개발자의 여정!

0개의 댓글