Electron 앱 용량 줄이기 — 100MB에서 30MB로
사용자가 100MB 앱을 안 깔고 싶어한다
초기 Electron 앱의 크기가 100MB였다. 설치 시간도 오래 걸리고, 특히 느린 인터넷 환경의 사용자들이 "좀 더 작을 수 없나요?"라고 물어봤다.
의존성을 정리하고, 불필요한 부분을 제거했다. 이제 30MB다. 설치도 빠르고, 사용자 만족도도 올라갔다.
분석: 뭐가 용량을 먹나
<?xml version="1.0"?>
npm ls --depth=0
dependencies:
electron 180MB (Electron 자체)
node_modules/ 90MB (의존성)
- lodash 4MB
- moment 8MB
- uuid 2MB
- 기타 76MB
build artifacts 20MB
native modules 10MB
최적화 1: 불필요한 의존성 제거**
<?xml version="1.0"?>
// lodash 제거 → 네이티브 함수로 변경
import _ from 'lodash'
// Bad
_.pick(obj, ['a', 'b'])
_.omit(obj, ['c', 'd'])
// Good (최신 JavaScript)
const { a, b } = obj
const { c, d, ...rest } = obj
// moment 제거 → date-fns로 변경 (더 가벼움)
import { format, parse } from 'date-fns'
// uuid는 유지 (자체 구현은 위험)
// 결과: 12MB → 2MB
최적화 2: 언어 파일 제거**
<?xml version="1.0"?>
// electron-builder 설정에서 불필요한 로케일 제거
{
"build": {
"asarUnpack": [
"node_modules/electron/dist/resources/locales/en*",
"node_modules/electron/dist/resources/locales/ja*"
],
"files": [
"!**/locales/**/*",
"!**/resources/**/*.lproj"
]
}
}
// 또는 프로세싱으로 제거
import * as fs from 'fs'
import * as path from 'path'
function removeUnusedLocales() {
const keep = ['en', 'ja', 'ko'] // 필요한 언어만
const localesPath = path.join(
__dirname,
'node_modules/electron/dist/resources/locales'
)
fs.readdirSync(localesPath).forEach(file => {
const lang = file.split('.')[0]
if (!keep.includes(lang)) {
fs.unlinkSync(path.join(localesPath, file))
}
})
}
// 효과: Electron 번들에서 30MB 절감
최적화 3: 폰트 서브셋팅**
<?xml version="1.0"?>
// 전체 폰트 파일은 거대함
// 필요한 글자만 추출
npm install -D fonttools
// subsetting script
#!/bin/bash
pyftsubset JetBrainsMono-Regular.ttf --unicodes="U+0020-U+007E,U+00C0-U+00FF" --output-file="JetBrainsMono-Regular-subset.ttf"
// CSS에서 사용
@font-face {
font-family: 'JetBrains Mono';
src: url('./fonts/JetBrainsMono-Regular-subset.ttf') format('truetype');
font-display: swap;
}
// 효과: 폰트 파일 6MB → 1.5MB
최적화 4: Native 모듈 최소화**
<?xml version="1.0"?>
// 불필요한 옵션 의존성 제거
npm list --all | grep optional
// 선택적 의존성 건너뛰기
npm ci --no-optional
// 또는 package.json에서
{
"optionalDependencies": {
"sharp": "^0.32.0" // 이미지 처리
}
}
// electron-builder에서
{
"build": {
"nodeGypRebuild": false,
"buildDependenciesFromSource": false
}
}
// 효과: 불필요한 네이티브 바인딩 10MB 제거
최적화 5: 빌드 아티팩트 최소화**
<?xml version="1.0"?>
// .gitignore와 비슷하게
// electron-builder의 files 설정으로 제외
{
"build": {
"files": [
"dist/**/*",
"node_modules/**/*",
"package.json"
],
"extraMetadata": {
"name": "my-app"
}
},
"files": [
"!**/*.map", // Source maps 제거
"!**/test/**/*", // 테스트 파일
"!**/node_modules/@types/**/*",
"!**/*.ts", // TypeScript 원본
"!**/.gitignore",
"!**/README.md",
"!**/LICENSE"
]
}
// 효과: 5MB 절감
최적화 6: 코드 분할 및 동적 로드**
<?xml version="1.0"?>
// 큰 라이브러리는 필요할 때만 로드
async function loadPDFLibrary() {
// 처음엔 로드 안 함
const { PDFDocument } = await import('pdf-lib')
return PDFDocument
}
// 또는 webpack/vite 설정
{
build: {
rollupOptions: {
output: {
manualChunks: {
'pdf': ['pdf-lib'],
'chart': ['chart.js']
}
}
}
}
}
체크리스트**
<?xml version="1.0"?>
// 체크리스트 (scripts/optimize.sh)
#!/bin/bash
echo "🔍 Analyzing app size..."
du -sh . | sort -hr
echo "📦 Checking dependencies..."
npm ls --all | head -20
echo "🗑️ Cleaning up..."
# 불필요한 파일 제거
rm -rf **/*.map
rm -rf **/.test.*
find node_modules -name "*.d.ts" -type f -delete
echo "✅ Done!"
npm run build:app
최종 결과**
- 초기: 100MB
- 의존성 정리: 100MB → 85MB
- 로케일 제거: 85MB → 65MB
- 폰트 최적화: 65MB → 60MB
- native 모듈: 60MB → 50MB
- 코드 분할: 50MB → 30MB
마무리**
Electron 앱의 크기는 의존성 관리로 대부분 절감할 수 있다. 큰 라이브러리가 정말 필요한지, 더 작은 대안이 있는지 항상 질문해야 한다.
100MB에서 30MB로 줄이는 것만으로도 사용자 경험이 크게 개선된다. 다운로드도 빠르고, 설치도 빠르고, 앱 자체도 빠르다.