React 빌드 속도 개선: 캐시와 병렬 전략
React 개발 환경에서 webpack과 바벨의 캐시 설정 및 병렬 빌드를 통해 빌드 시간을 효율적으로 줄이는 구현 전략
목차
개요
React 프로젝트가 커지면 빌드 시간이 개발 속도를 직접적으로 저해한다. 이 글은 캐시와 병렬 빌드를 중심으로 빌드 시간을 줄이는 실무적 접근을 정리한다. 처음 접하는 사람도 이해할 수 있도록 원리와 설정 예제를 함께 제공한다.
왜 빌드가 느려지는가
빌드 지연은 주로 세 가지 요인에서 발생한다.
- 소스 파일과 의존성의 증가로 인한 트랜스파일 비용
- 반복 작업에서 결과물을 재사용하지 못하는 비효율적인 설정
- 단일 스레드 처리로 병렬화를 활용하지 못함
이 세 가지에 대해 캐싱과 병렬화를 적용하면 유의미한 개선을 얻을 수 있다.
캐시 전략
webpack 파일시스템 캐시
webpack 5부터 제공하는 파일시스템 캐시는 전체 빌드의 대부분을 빠르게 만든다. 변경된 파일만 재컴파일하도록 캐시를 저장하고 재사용한다. 기본 설정과 함께 캐시 위치와 핸들링을 조정하면 CI 환경에서도 효과적이다.
module.exports = {
// ...기타 설정
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename]
},
cacheDirectory: path.resolve(__dirname, '.webpack_cache')
}
};
위 설정은 빌드 결과를 .webpack_cache에 저장한다. CI에서 캐시를 보존하면 풀 빌드 시간을 크게 줄일 수 있다.
바벨 캐싱
바벨 트랜스파일은 비용이 크다. babel-loader에서 cacheDirectory를 활성화하면 이전 결과를 재사용한다. 개발 서버와 로컬에서 특히 유효하다.
module.exports = {
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
cacheCompression: false
}
}
}
]
}
};
cacheCompression을 false로 두면 압축/해제 비용을 줄여 속도를 더 끌어올릴 수 있다.
의존성 및 어셋 캐시
의존성 자체는 변경이 적으므로 패키지 매니저 레벨에서 캐시를 활용하면 네트워크 비용을 줄인다. CI에서는 node_modules 캐시, pnpm의 store 캐시 등 저장소를 재활용한다. 또한 이미지나 폰트 같은 정적 자산은 빌드 파이프라인에서 해시 기반 캐싱을 적용한다.
병렬 빌드 전략
thread-loader와 병렬 트랜스파일
webpack에서는 thread-loader를 통해 로더 수준에서 병렬 처리를 할 수 있다. CPU 코어를 활용해 바벨 작업을 병렬로 실행하면 트랜스파일 시간이 크게 줄어든다.
module.exports = {
module: {
rules: [
{
test: /\.m?js$/,
use: [
'thread-loader',
{
loader: 'babel-loader',
options: { cacheDirectory: true }
}
],
exclude: /node_modules/
}
]
}
};
thread-loader는 초기 워커 생성 비용이 있으므로 매우 작은 프로젝트에서는 오히려 느려질 수 있다. 프로젝트 규모와 빌드 프로파일을 측정한 뒤 적용 여부를 결정한다.
멀티 컴파일과 파티셔닝
멀티 페이즈 빌드(예: 여러 엔트리나 마이크로 프론트엔드)는 빌드 단위를 분할해 병렬로 실행하면 유리하다. npm 스크립트에서 병렬 실행 도구를 사용하거나 CI의 matrix/parallel 기능을 활용한다.
// package.json 예시
{
"scripts": {
"build:app": "webpack --config webpack.app.js",
"build:admin": "webpack --config webpack.admin.js",
"build:all": "concurrently \"npm:build:app\" \"npm:build:admin\""
}
}
concurrently나 npm-run-all을 사용해 로컬에서 병렬 빌드를 실행하면 멀티 엔트리 환경에서 시간 단축을 얻을 수 있다.
CI에서의 병렬화
CI는 워커를 여러 개 할당할 수 있으므로 빌드를 분할해 병렬화하면 속도 향상이 크다. 예를 들어 테스트, lint, 앱 빌드를 병렬로 실행하거나 엔트리별로 나눠 실행한다. 단, 캐시 공유와 아티팩트 관리가 필요하다.
측정과 안전한 적용
변경 전후의 빌드 시간을 측정해야 실질적 개선을 확인할 수 있다. 대표적인 방법은 다음과 같다.
- 로컬에서 clean 후 시간 측정
- CI에서 cold cache와 warm cache 결과 비교
- 프로파일링 도구(webpack --profile, --json) 사용
캐시를 도입할 때는 캐시 무효화 전략을 명확히 한다. 예를 들어 환경별 설정 파일이 변경되면 캐시가 무효화되도록 buildDependencies를 설정한다.
권장 체크리스트
- webpack 캐시 타입을 filesystem으로 설정
- babel-loader에 cacheDirectory 활성화
- thread-loader로 CPU 병렬화 검토
- 엔트리 분할 후 병렬 빌드 적용
- CI에서 캐시 보존과 병렬 작업 구성
- 빌드 프로파일 측정으로 변경 효과 확인
결론
캐시와 병렬화는 서로 보완적이다. webpack 빌드 캐시 설정과 바벨 캐싱을 먼저 적용해 반복 빌드 비용을 낮추고, 이후 thread-loader나 빌드 분할로 병렬화하면 더 큰 효과를 얻는다. 단계별로 측정하면서 적용하면 안정적으로 빌드 속도를 개선할 수 있다.