파일 크기 최소화
js 파일 내부의 불필요한 주석, 경고 메세지, 공백 등 → 제거
코드 트랜스파일 작업
브라우저에서 JSX 문법 or 다른 최신 js 문법 → 원활한 실행 되도록
정적 파일(img 등) → 경로 설정
프로젝트에서 사용 중인
모든 js/css 파일 → 각각 하나의 파일로 합쳐짐 (총 2개)
최소 2개 이상의 JS 파일 생성
CRA의 기본 웹팩 설정
→ SplitChunks 기능 적용
캐싱 효과
→ 자동으로 따로 분리
$ yarn build
해당 파일 내용에 따라 생성
알 수 있는 것
브라우저 → 새 파일 받아야 할지 여부
ex. 7b7f7f25
2
node_modules에서 불러온 라이브러리 관련 코드
main
직접 프로젝트에 작성하는 (App 같은) 컴포넌트 코드
파일 분리하는 작업
필요한 시점에 사용 가능 (js 함수, 객체, 컴포넌트 등)
SplitChunks
→ 단순히 효율적인 캐싱 효과만 有
모든 코드(모든 페이지) → 한 파일(main)에 저장
→ 악순환
효과
함수가 필요한 지점에 파일 불러와서 사용 가능
예시 코드
export default function notify() {
alert("안녕하세요!");
}
src/App.js
▶ 기존
import logo from "./logo.svg";
import "./App.css";
import notify from "./notify";
function App() {
const onClick = () => {
notify();
};
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p onClick={onClick}>Hello React!</p>
</header>
</div>
);
▶ 적용 후
import logo from "./logo.svg";
import "./App.css";
function App() {
const onClick = () => {
import("./notify").then((res) => res.default());
};
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p onClick={onClick}>Hello React!</p>
</header>
</div>
);
}
export default App;
원리
import를 함수로 사용 시
→ Promise 반환
default
로 내보낸 모듈 불러올 때
result.default
를 참조해야 사용 가능
const onClick = () => {
import("./notify").then((res) => res.default());
};
빌드 후
build/static/js
→ 3으로 시작하는 파일 생성 (notify 관련 코드 들어감)
[ 확인 ] Network 탭
Hello React를 클릭하는 시점에 새로운 js 파일 불러옴
파일 내용 확인 시
notify(필요해서 불러온 코드)관련 코드만 有
구현 : import 함수로 부르고 컴포넌트 자체를 state에 넣는 방식
SplitMe.js
) import React from "react";
const SplitMe = () => {
return <div>SplitMe</div>;
};
export default SplitMe;
App.js
클래스형 컴포넌트
스플리팅할 컴포넌트 부를 메소드 내부에서 호출 후, state 넣기 (setState)
render함수
→ 해당 컴포넌트의 유효성 검사 후, 렌더링
import React, { Component } from "react";
import logo from "./logo.svg";
import "./App.css";
class App extends Component {
state = {
SplitMe: null,
};
handleClick = async () => {
const loadedModule = await import("./SplitMe");
this.setState({
SplitMe: loadedModule.default,
});
};
render() {
const { SplitMe } = this.state;
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p onClick={this.handleClick}>Hello React!</p>
{SplitMe && <SplitMe />}
</header>
</div>
);
}
}
export default App;
매번 state 선언 → 불편
유틸 함수 : 컴포넌트 렌더링 시점에서 비동기적으로 로딩 가능하게 함
const SplitMe = React.lazy(() => import('./SplitMe'));
- 코드 스플리팅된 컴포넌트 → 로딩하도록 발동 가능
- 로딩 끝나지 x 때 → 보여줄 UI 설정 가능
import React, { Suspense } from 'react';
(...)
<Suspense fallback = {<div>loading...</div>}>
<SplitMe/>
</ Suspense>
fallback props
로딩 중 보여줄 JSX 지정 가능
useState 생성 (의미: 단순히 코드 스플리팅된 컴포넌트의 가시성)
setState → 업데이트
→ 보여짐
import React, { useState, Suspense } from "react";
import logo from "./logo.svg";
import "./App.css";
const SplitMe = React.lazy(() => import("./SplitMe"));
function App() {
const [visible, setVisible] = useState(false);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p onClick={() => setVisible(true)}>Hello React!</p>
<Suspense fallback={<div>loading...</div>}>
{visible && <SplitMe />}
</Suspense>
</header>
</div>
);
}
export default App;
서드파티 라이브러리 (코드 스플리팅 더 편하게 도와주는)
$ yarn add @loadable/component
import React, { useState, Suspense } from "react";
import logo from "./logo.svg";
import "./App.css";
import loadable from "@loadable/component";
const SplitMe = loadable(() => import("./SplitMe"), {
fallback: <div>loading...</div>,
});
function App() {
const [visible, setVisible] = useState(false);
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p onClick={() => setVisible(true)}>Hello React!</p>
{visible && <SplitMe />}
</header>
</div>
);
}
export default App;
(렌더링하기 전에 필요할 때) 스플리팅된 파일 미리 부를 수 있는 기능
방법
onMouseOver
에 스플리팅된 컴포넌트.preload()
⇒ 마우스 커서를 해당 위치 (Hello React!)에 올린 즉시 → 로딩 시작
→ 클릭 시, 렌더링
코드 예시
const onMouseOver = () => {
SplitMe.preload();
};
(...)
<p onMouseOver={onMouseOver}>
Hello React!
</p>
import React, { useState, Suspense } from "react";
import logo from "./logo.svg";
import "./App.css";
import loadable from "@loadable/component";
const SplitMe = loadable(() => import("./SplitMe"), {
fallback: <div>loading...</div>,
});
function App() {
const [visible, setVisible] = useState(false);
const onMouseOver = () => {
SplitMe.preload();
};
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p onClick={() => setVisible(true)} onMouseOver={onMouseOver}>
Hello React!
</p>
{visible && <SplitMe />}
</header>
</div>
);
}
export default App;
타임아웃, 로딩 UI 딜레이, SSR 렌더링 호환 등