코드 스플리팅(code splitting)
자바스크립트로 개발을 하고 배포하ㅁ는 과정에서 빌드(build) 과정을 거치게 되는데, 이 과정에서 모든 파일들이 하나로 합쳐지게 된다.
→ 즉, 우리가 index.js, components들로 나눴던 소스 코드들이 하나의 거대한 소스 코드로 합쳐진다는 말임
간단한 프로젝트라면 영향이 적겠지만, 거대한 프로젝트라면(특히 SPA 페이지에서) 길고 많은 자바스크립트 코드(.css, .html도 마찬가지)가 탄생합니다. 이 경우 인터넷 환경이 좋지 못한 곳에서는 거대한 소스 코드들을 불러오는데 상당한 로딩시간을 갖게 됩니다.
이를 개선하고자 코드에서 당장 사용하는 부분만을 로딩하고, 현재 필요하지 않은 코드 부분은 따로 분리시켜 나중에 로드함으로써 로딩시간을 개선하는 것이 코드 스플리팅입니다.
웹팩(webpack)
어플리케이션의 모든 파일들을 묶고 압축하여 하나의 결과물을 만들어주는 웹 개발 도구
1. 가장 기본적인 코드 스플리팅
리액트에만 해당되는것이 아니라, 웹 팩으로 구성된 다른프로젝트에서도 적용 가능
1. 코드 스플리팅 할 함수 준비
src/notify.js
export default function notify() {
alert('안녕하세요!');
}
SplitMain.js
import React from 'react';
export default function SplitMain() {
const onClick = () => {
import('../notify').then(result => result.default());
};
return (
<div className = "SplitMain">
<button onClick={onClick}>Click Me</button>
</div>
);
}
import 를 함수로 사용하면, Promise 를 반환한다. import() 함수는 아직 표준은 아니지만 stage-3 단계에 있는 dynamic import 라는 문법이다. 이 함수는 모듈을 비동기적으로 CommonJS 형태로 불러오니, 따로 default 를 명시해주어야 한다. 위에서 사용한 코드에서는 "default 를 notify로 부르겠다" 라고 설정을 해준다.
2. yarn build로 빌드
notify 코드 스플리팅 후의 빌드 결과
2. 유틸 함수인 React.lazy 와 Suspense 사용하기
React.lazy 사용 방법
const SplitMe = React.lazy(() => import('./SplitMe'));
Suspense는 리액트 내장 컴포넌트로서 코드 스플리팅된 컴포넌트를 로딩하도록 발동시킬 수 있고, 로딩이 끝나지 않았을 때 보여 줄 UI를 설정할 수 있음
Suspense 사용방법
import { Suspense } from 'react';
(...)
<Suspense fallback = {<div>loading...</div>}>
<SplitMe />
</Suspense>
Suspense에서 fallback props를 통해 로딩 중에 보여줄 JSX를 지정할 수 있음
3. Loadable Components를 통한 코드 스플리팅
Loadable Components
- 코드 스플리팅을 편하게 하도록 도와주는 서드파티 라이브러리이다.
- 이 라이브러리의 이점은 서버 사이드 렌더링을 지원한다는 것이다
- React.lazy와 Suspense는 아직 서버 사이드 렌더링을 지원하지 않음
- 서버 사이드 렌더링 : 웹 서비스의 초기 로딩 속도 개선, 캐싱 및 검색 엔진 최적화를 가능하게 해주는 기술
- 서버 사이드 렌더링을 사용하면 웹 서비스의 초기 렌더링을 사용자의 브라우저가 아닌 서버 쪽에서 처리한다
- 사용자는 서버에서 렌더링한 html 결과물을 받아 와서 그대로 사용하기 때문에 초기 로딩 속도도 개선되고
- 검색 엔진에서 크롤링할 때도 문제 없음
- 렌더링하기 전에 필요할 때 스플리팅된 파일을 미리 불러올 수 있는 기능이 있음
사용 방법
import logo from './logo.svg';
import './App.css';
import React, {useState, Suspense} from 'react';
import loadable from '@loadable/component';
const SplitMe = loadable(() => import('./SplitMe'));
const App = () => {
const [visible, setVisible] = useState(false);
const onClick = () => {
setVisible(true);
};
return (
<div className={"App"}>
<header className={"App-header"}>
<img src={logo} className={"App-logo"} alt={"logo"}/>
<p onClick={onClick}>code splitting</p>
{visible && <SplitMe/>}
</header>
</div>
);
}
export default App;
Suspense 컴포넌트의 fallback 처럼 로딩중에 보여주고 싶은 UI가 있다면 loadable을 다음과 같이 사용해준다
//변경 전
const SplitMe = loadable(() => import('./SplitMe'));
//변경 후
const SplitMe = loadable(() => import('./SplitMe'), {
fallback: <div>로딩중...</div>
});
더 좋은 UX를 제공하는 미리 불러오는(preload)방식
여태까진 클릭을 하면 로딩이 시작되었는데, 이 방식은 클릭 하기 전에 컴포넌트에 마우스 커서가 올라가는 순간부터 로딩이 시작된다. 말로만 하면 복잡해보이지만, 마우스 오버 이벤트를 등록해주면 됨
import logo from './logo.svg';
import './App.css';
import React, {useState, Suspense} from 'react';
import loadable from '@loadable/component';
const SplitMe = loadable(() => import('./SplitMe'));
const App = () => {
const [visible, setVisible] = useState(false);
const onClick = () => {
setVisible(true);
};
const onMouseOver = () => {
SplitMe.preload();
};
return (
<div className={"App"}>
<header className={"App-header"}>
<img src={logo} className={"App-logo"} alt={"logo"}/>
<p onClick={onClick} onMouseOver={onMouseOver}>code splitting</p>
{visible && <SplitMe/>}
</header>
</div>
);
}
export default App;
[정리]
서버 사이드 렌더링을 할 계획이 없다면 → React.lazy 와 Suspense로 구현
서버 사이드 렌더링을 할 계획이 있다면 → Loadable Components를 사용
'React' 카테고리의 다른 글
[React] 백엔드 프로그래밍 : Node.js의 Koa 프레임워크 (0) | 2023.05.03 |
---|---|
[React] 서버 사이드 렌더링 (0) | 2023.05.02 |
[React] 리덕스 미들웨어를 통한 비동기 작업 관리 (0) | 2023.04.14 |
[React] 리덕스를 사용해 상태 관리 (0) | 2023.04.06 |
[React] 리덕스 라이브러리 (0) | 2023.04.05 |