본문으로 건너뛰기

빌드 최적화

Elftia의 메인 번들은 1,812 KB에서 759 KB로 최적화되었습니다(-58%). 이 문서는 회귀를 방지하기 위한 최적화 전략과 기준을 기록합니다.


번들 크기 제한

절대 제한 (반드시 준수)

지표제한현재확인 방법
단일 청크 최대 크기< 1 MB759 KBnpm run verify:build
메인 번들 (gzip 압축)< 300 KB221 KBnpm run verify:build
Vite 경고 수00빌드 출력

권장 목표

지표목표현재우선순위
메인 번들 (비압축)< 500 KB759 KBP1
전체 번들< 3 MB6.24 MBP2
첫 화면 로딩< 2s~2sP0

확인 명령어

# 빠른 검증 (4가지 핵심 지표)
npm run verify:build

# 상세 분석 (청크 분류 통계)
npm run analyze:build

# 시각적 분석 (stats.html 생성)
npm run build:renderer
# dist/stats.html 열기

코드 분할 전략

라우트 수준 코드 분할 (필수)

모든 페이지 컴포넌트는 지연 로딩을 위해 React.lazy를 사용해야 합니다. lazy/는 용도별로 구성된 디렉터리입니다(pages.tsx / workspaces.tsx / inline.tsx / shell.tsx / skeletons.tsx / with-suspense.tsx / index.ts 배럴). 새 페이지를 추가할 때는 lazy/pages.tsx를 수정하세요:

// packages/renderer/src/app/lazy/pages.tsx
export const LazySettingsPage = lazy(() => import('../Settings'));
export const SuspenseSettings = withSuspense(LazySettingsPage, PageSkeleton);

// packages/renderer/src/app/App.tsx — 기존 import 경로도 유효 (배럴 재내보내기)
import { SuspenseSettings as Settings } from './components/lazy';
<Route path="/settings" element={<Settings />} />
// 이렇게 하지 마세요: 페이지 컴포넌트를 직접 import
import Settings from './components/Settings';
<Route path="/settings" element={<Settings />} />

대형 컴포넌트 지연 로딩 (권장)

단일 컴포넌트가 100 KB를 초과하거나 대형 서드파티 라이브러리에 의존하는 경우 지연 로딩을 사용하세요.

이미 지연 로딩이 적용된 컴포넌트:

컴포넌트크기의존성
MermaidDiagram451 KBmermaid
HtmlPreviewPanel198 KBiframe sandbox
CodeEditor34 KBCodeMirror
Shell / StandaloneShell9 KBxterm

적용 기준:

조건지연 로딩 적용?
컴포넌트 번들 > 100 KB
대형 서드파티 라이브러리 의존
첫 화면에 불필요
사용 빈도가 낮음
소형 공통 컴포넌트 (< 10 KB)아니요
첫 화면에 필요한 핵심 컴포넌트아니요
자주 토글되는 UI 컴포넌트아니요

Context 최적화

전역적으로 필요하지 않은 Context는 페이지 수준 컴포넌트로 이동하세요:

// 좋은 예: 페이지 수준 Context
export function Settings() {
return (
<SettingsProvider>
<SettingsContent />
</SettingsProvider>
);
}

// 나쁜 예: 불필요한 Context를 전역으로 로드
<GlobalContext>
<Routes />
</GlobalContext>
경고

Context를 이동하기 전에 반드시 의존성을 분석하여 페이지 간 상태 공유가 깨지지 않는지 확인하세요.


Vendor 청크 구성

현재 전략은 업데이트 빈도와 사용 빈도를 기준으로 그룹화합니다:

// vite.config.js — manualChunks
{
'vendor-react': ['react', 'react-dom', 'react-router-dom'],
'vendor-ui': ['@radix-ui/react-context-menu', '@radix-ui/react-dialog', ...],
'vendor-icons': ['lucide-react'],
'vendor-utils': ['clsx', 'tailwind-merge', 'class-variance-authority', 'zustand'],
'vendor-markdown': ['react-markdown', 'remark-gfm', 'rehype-highlight'],
'vendor-codemirror': ['@codemirror/state', '@codemirror/view', ...],
'vendor-xterm': ['@xterm/xterm', '@xterm/addon-fit', '@xterm/addon-web-links'],
}

그룹화 원칙

유형업데이트 빈도캐시 우선순위예시
핵심 프레임워크낮음최고React, React DOM
대형 서드파티 라이브러리낮음높음CodeMirror, xterm
UI 컴포넌트 라이브러리중간중간Radix UI, lucide
유틸리티 라이브러리중간중간clsx, zustand

새 의존성 추가 시 확인

새 서드파티 의존성을 추가할 때:

# 1. 크기 확인
npm info <package> dist.unpackedSize

# 2. 100 KB 초과 시 vendor 청크에 추가
# 3. 업데이트 빈도가 높으면 별도 vendor 청크 생성
# 4. tree shaking 지원 여부 확인
# 5. npm run analyze:build로 영향도 확인

Tree Shaking

올바른 import 방법

// 좋은 예: named import (tree shaking 지원)
import { Button, Input, Select } from '@/components/ui';
import { Home, Settings, User } from 'lucide-react';

// 좋은 예: Radix UI 네임스페이스 import (공식 권장)
import * as Dialog from '@radix-ui/react-dialog';

// 나쁜 예: 라이브러리 전체 import
import * as UI from '@/components/ui';
import * as Icons from 'lucide-react';

미사용 import 확인

npm run typecheck # TypeScript로 미사용 import 감지
npm run lint:eslint # ESLint로 미사용 변수 경고

Vite 프로덕션 빌드 구성

// vite.config.js — 핵심 구성
build: {
minify: 'terser', // terser가 esbuild보다 압축률 우수
sourcemap: false, // 프로덕션에서 sourcemap 비활성화
chunkSizeWarningLimit: 500, // 청크 크기 경고 임계값 (KB)
terserOptions: {
compress: {
drop_console: true, // console.log 제거 (warn/error는 유지)
drop_debugger: true, // debugger 제거
},
},
}

일반적인 문제와 해결 방법

메인 번들이 너무 큼 (> 500 KB)

조사 절차:

  1. npm run build:renderer 실행 후 dist/stats.html 열기
  2. 메인 번들 구성 확인, 가장 큰 모듈 찾기
  3. 대형 컴포넌트에 지연 로딩이 빠져 있는지 확인
  4. 불필요한 전역 import 확인

해결 방법:

  • 대형 컴포넌트를 지연 로딩으로 전환
  • 미사용 import 제거
  • 페이지 컴포넌트를 라우트 수준 지연 로딩으로 전환

Vendor 청크가 너무 큼 (> 500 KB)

해결 방법:

  • 대형 vendor를 더 작은 청크로 분할
  • 업데이트 빈도에 따라 재그룹화
  • 중복 의존성 확인

전체 번들이 너무 큼 (> 5 MB)

해결 방법:

  • 차트 라이브러리 지연 로딩 (Mermaid, Cytoscape 등)
  • 사용 빈도가 낮은 기능 또는 의존성 제거
  • 더 가벼운 대체 라이브러리 고려

코드 분할 실패

조사 절차:

  1. lazy/ 디렉터리에서 관련 분할 파일의 지연 로딩 구성 확인 (페이지 수준은 lazy/pages.tsx, 워크스페이스 본문은 lazy/workspaces.tsx, 인라인 채팅 컴포넌트는 lazy/inline.tsx)
  2. 지연 로딩된 컴포넌트가 App.tsx에서 사용되고 있는지 확인
  3. Vite 구성의 manualChunks 확인

커밋 전 체크리스트

새 페이지 추가 시

  • 페이지 컴포넌트를 lazy/pages.tsx (또는 해당 분할 파일)에 추가
  • withSuspense로 래핑하고 fallback 제공
  • App.tsx에서 지연 로딩 버전 사용
  • npm run build:renderer 실행하여 별도 청크 생성 확인

대형 컴포넌트 추가 시

  • 컴포넌트 크기 > 100 KB → 지연 로딩 사용
  • 대형 서드파티 라이브러리 의존 → 지연 로딩 사용
  • 적절한 로딩 상태 제공

서드파티 의존성 추가 시

  • 의존성 크기 확인
  • 의존성 > 100 KB → vendor 청크에 추가
  • 업데이트 빈도가 높음 → 별도 vendor 청크
  • tree shaking 지원 → named import 사용
  • npm run analyze:build 실행하여 영향도 확인

지속적 최적화 제안

매 릴리스 전

npm run verify:build
npm run build:renderer | grep -i "warning"
# 메인 번들이 50 KB 이상 증가했다면 원인 조사

매월

npm run build:renderer
# dist/stats.html을 열어 최적화 가능한 모듈 확인
npm outdated
npm update

분기별

  • 모든 vendor 청크 구성 검토
  • 새로운 최적화 전략 평가
  • 사용 빈도가 낮은 기능 제거 여부 평가
  • 이 기준 문서 업데이트

CI/CD 연동

CI에 번들 크기 검사를 추가할 것을 권장합니다:

- name: Build and verify
run: |
npm run build:renderer
npm run verify:build || echo "Warning: Bundle size check failed"

성능 지표 기준선

지표기준선목표모니터링
메인 번들759 KB< 500 KBverify:build
첫 화면 로딩~2s< 2sLighthouse
전체 번들6.24 MB< 3 MBanalyze:build
청크 수76-analyze:build

참고 자료