Vite 초기 번들에서 선택 기능 의존성을 분리한 방법
lodash 사용 범위를 줄이고 xlsx·Firebase 등 선택 기능을 지연 로딩과 manualChunks로 분리한 번들 최적화 과정을 정리합니다.
관리자 웹의 초기 번들에는 엑셀, PDF, 차트, 푸시, 소켓처럼 첫 화면에 항상 필요하지 않은 기능이 함께 포함돼 있었다. 번들 크기 문제를 해결할 때 모든 외부 라이브러리를 하나의 vendor로 묶으면 파일 수는 줄지만 초기 로드와 캐시 무효화 범위는 여전히 크다.
먼저 의존성의 가져오기 단위를 줄였다
초기 정리에서는 전체 lodash 패키지 대신 실제 사용하는 함수 패키지로 바꾸고, 더 이상 쓰지 않는 Sentry와 xlsx 직접 의존성을 제거했다. 이 단계는 기능 청크를 나누기 전 불필요한 코드가 번들 그래프에 들어오는 입구를 줄인 작업이었다.
하지만 의존성을 정리하는 것만으로는 선택 기능이 정적 import를 통해 초기 그래프에 포함되는 문제를 해결할 수 없었다. 후속 개선에서 엑셀 다운로드 시점에 xlsx를 동적으로 불러오고, FCM과 알림창 초기화도 브라우저 로드 이후로 미뤘다.
아래 코드 예시는 설명을 위해 식별자와 운영 설정값을 일반화했습니다.
const loadOptionalNotifications = async () => {
const notificationModule = await import("./notifications");
await notificationModule.initialize();
};
SweetAlert 기본 설정도 requestIdleCallback에서 준비하고, 유휴 시간 전에 오류가 발생한 경우에만 즉시 동적 import하도록 구성했다.
manualChunks는 선택 기능의 경계만 명시했다
Vite 설정에서는 앱 내부 도메인 코드를 강제로 묶지 않고 대형 외부 의존성만 분리했다.
manualChunks(id) {
const modulePath = id.replaceAll(/\\/g, "/");
if (!modulePath.includes("/node_modules/")) return;
if (modulePath.includes("/node_modules/xlsx/")) return "optional-spreadsheet";
if (modulePath.includes("/node_modules/jspdf/")) return "optional-document";
if (modulePath.includes("/node_modules/chart.js/")) return "optional-charts";
}
onlyExplicitManualChunks: true도 함께 사용했다. 지정한 패키지의 공용 helper까지 무조건 같은 청크로 끌어들여 entry와 vendor 사이에 역참조가 생기는 일을 피하기 위해서다. 앱 내부 모듈은 Vite의 자동 분할에 맡겨 과거 수동 분할에서 발생할 수 있는 순환 참조 범위를 줄였다.
다운로드 최적화는 import 시점과 캐시 경계를 함께 바꾸는 일이다
이 구조에서 엑셀 기능을 사용하지 않는 사용자는 초기 화면에서 vendor-xlsx를 받을 필요가 없다. 비즈니스 코드가 바뀌어도 해시가 다른 기능 청크만 갱신되므로 변경이 적은 외부 라이브러리 캐시도 유지하기 쉬워진다.
flowchart LR A[초기 화면] --> B[필수 앱 코드] A -. 기능 사용 시 .-> C[엑셀 청크] A -. 기능 사용 시 .-> D[PDF 청크] A -. 로그인 후 유휴 시간 .-> E[푸시 청크]
당시 네트워크 기록에는 콘텐츠 다운로드가 약 1,000ms에서 100ms 수준으로 줄어든 비교가 있다. 이 수치는 캐시와 네트워크 조건에 영향을 받는 관측값이다. 선택 기능은 동적 import로 늦추고, 대형 외부 의존성은 명시적인 캐시 단위로 분리했다.
번들 최적화에서 manualChunks만 추가하면 끝나는 것은 아니다. 정적 import가 남아 있으면 분리된 청크도 초기 로드에 포함된다. 언제 불러올지와 어떤 파일로 캐시할지를 함께 설계해야 한다.