단의 개발 블로그
코드 스플리팅 본문
실제 서비스 되는 애플리케이션은 빌드 작업을 거쳐 배포된다. 불필요한 주석, 경고메세지, 주석을 제거해서 파일 크기를 최소화 하고, jsx문법이나 다른 최신 자바스크립트 문법이 원활하게 실행되도록 코드 트랜스 파일 작업도 가능하다. 이런 작업은 웹팩이라는 도구가 담당하는데, 별도의 설정을 하지 않을 경우 프로젝트에서 사용 중인 모든 자바스크립트 파일과 css 파일이 합쳐진다. CRA로 빌드할 경우 최소 두 개 이상의 자바스크립트 파일이 생성되는데, CRA의 기본 웹팩 설정에는 splitChunks라는 기능이 적용되어 modules에서 불러온 파일, 일정크기 이상의 파일, 여러 파일 간 공유된 파일을 자동으로 분리시켜 캐싱 효과를 누릴 수 있게 해준다.
빌드하기
yarn build 명령어를 실행하면 다음과 같이 build 폴더 안에 파일이 만들어진다.

해시로 된 파일이 생성되며, 브라우저가 새로 받아야 할지 말지를 결정한다. 코드를 변경하고 다시 빌드하면, main으로 시작하는 파일의 이름만 바뀐다. 이렇게 파일이 분리하는 작업을 코드 스플리팅이라고 한다. 기본 탑재된 SplitChunks 기능을 통한 코드 스플리팅은 단순히 효율적인 캐싱 효과만 있다. 페이지 A, B, C로 구성된 싱글 페이지 애플리케이션이 존재할 때 A 페이지에 방문 했다면 B, C 페이지의 컴포넌트는 필요하지 않다. 하지만 A, B, C의 빌드는 같이 되어 있기 때문에 파일의 크기가 커져버린다. 로딩도 좋지 않고 트래픽도 많이 나온다.
이를 해결하려면 비동기 로딩을 사용해서 필요한 시점에 불러와 사용하면 된다.
함수 비동기 로딩
경고창을 띄우는 단순한 컴포넌트를 만들어주고, 클릭 시 해당 컴포넌트가 실행되도록 한다.
export default function notify() {
alert('Hello')
}
function App() {
const onClick = () => {
import ('./notify').then(result => result.default());
}
return (
<div className="App">
<p onClick={onClick}>Hello!</p>
</div>
);
}
export default App;
import() 함수 형태로 메소드 안에서 사용하면, 파일을 따로 분리시켜 저장한다. 그래서 실제 함수가 필요한 지점에서 파일을 불러와 함수를 사용한다. Promise를 반환한다. 이 함수를 통해 모듈을 불러올 때 모듈에서 default 로 내보낸 것은 result.default로 참조해야 사용할 수 있다. 프로젝트를 실행해서 확인한다.


React.lazy와 Suspese
리액트에 내장된 기능인 React.lazy와 컴포넌트인 Suspense로도 가능하다.
const SplitMe = ()=> {
return <>SplitMe</>
}
export default SplitMe;
function App() {
const [visible, setVisible] = useState(false);
const onClick = () => {
setVisible(true)
}
return (
<div className="App">
<p onClick={onClick}>Hello!</p>
<Suspense fallback={<>loading....</>}>
{visible && <SplitMe/>}
</Suspense>
</div>
);
}
Loadable Components
코드 스플리팅을 편하게 하도록 도와주는 서드파티 라이브러리다. 서버 사이드 렌더링을 지원하기 때문에 렌더링 하기 전에 필요할 때 스플리팅된 파일을 미리 불러올 수 있다.
서버 사이드 렌더링의 이점은 다음과 같다.
- 초기 로딩 속도 개선
- 캐싱 및 검색 엔진 최적화
라이브러리를 추가한다.
yarn add @loadable/component
코드를 수정한다.
import loadable from '@loadable/component';
const SplitMe = loadable(() => import('./SplitMe'));
만약 로딩 중 다른 ui가 존재하면 아래와 같이 구현하면 된다.
const SplitMe = loadable(() => import('./SplitMe'), {
fallback: <div>loading....</div>
})
다음은 컴포넌트를 미리 불러오는 방법이다.
function App() {
const [visible, setVisible] = useState(false);
const onClick = () => {
setVisible(true)
}
const onMouseOver = () => {
SplitMe.preload();
}
return (
<div className="App">
<p onClick={onClick} onMouseOver={onMouseOver}>Hello!</p>
{visible && <SplitMe/>}
</div>
);
}