벤치마크 및 성능
본 벤치마크는 paraglide-js benchmark의 테스트 아키텍처를 참고하여, **모던 다국어 웹 애플리케이션이 초기 사전 렌더링 후 클라이언트 측 하이드레이션(Hydration)를 완료하기까지 클라이언트가 실제로 전송받아야 하는 전체 국제화 리소스(HTML + 런타임 JS + 로케일 청크)의 실제 네트워크 전송 크기(Transfer Size)**를 정밀 측정합니다.
시나리오 설명: 순수 정적 페이지(Zero-JS MPA)에서는 서버가 이미 번역된 HTML을 직접 전달하므로 클라이언트 측 i18n 오버헤드가 없습니다. 본 테스트는 클라이언트 측 하이드레이션(Hydration), 동적 인터랙션(폼 검증, 즉각적인 문구 팝업 등), 클라이언트 라우팅 기능을 갖춘 모던 풀스택 애플리케이션을 대상으로 하며, 첫 화면이 상호작용 가능한 상태에 도달할 때까지 다운로드되는 정적 자산의 총비용을 측정합니다.
비교 대상 라이브러리 및 설정 모드:
ts-intl(경량 런타임):default(전체 언어 일괄 번들링) 및locale-splitting(언어별 동적 청크 분할) 모드 평가.paraglide(컴파일러 기반):default(컴파일된 전체 함수 번들링) 및experimental-middleware-locale-splitting(라우트 미들웨어 분할) 모드 평가.i18next(전통적 런타임):default(전체 언어 JSON 번들링) 및http-backend(클라이언트 비동기 fetch) 모드 평가.
전송 크기 비교 차트
Playwright 헤드리스 Chromium을 통해 페이지에 접근하여, 네트워크 유휴(networkidle) 상태에 도달할 때까지 발생한 모든 성공적인 HTTP 2xx/3xx 정적 응답 전송 크기의 총합을 측정했습니다:
Playwright Headless Chromium · Real HTTP Transfer Size
벤치마크 데이터 매트릭스
테스트 기준 워크로드: 첫 화면에 100개의 번역 메시지 렌더링 (이 중 20%는 동적 변수 보간 포함).
시나리오 1: 확장된 대규모 앱 (10개 언어 · 네임스페이스 내 총 500개 메시지)
이 시나리오에서는 네임스페이스에 총 500개의 메시지가 존재하며, 페이지에서 실제로 100개를 참조하여 렌더링합니다:
| 라이브러리 및 빌드 모드 | 첫 화면 전송 크기 | i18next 기본 대비 | 메커니즘 특성 |
|---|---|---|---|
| paraglide (미들웨어 분할) | 36.3 KB | -91.4% | 독립 JS 함수로 컴파일, 미사용 키 트리쉐이킹, 활성 언어만 분할 전달 |
| ts-intl (로케일 분할) | 57.8 KB | -86.2% | 코어 런타임 약 2 KB, 활성 언어의 500개 메시지 JSON만 전송 |
| paraglide (기본 일괄) | 76.6 KB | -81.8% | 미사용 키 트리쉐이킹 적용, 단 10개 언어의 컴파일 함수 일괄 번들링 |
| i18next (HTTP 동적 로드) | 188.7 KB | -55.1% | 클라이언트가 활성 언어 JSON 비동기 요청, 베이스 런타임 포함 |
| ts-intl (기본 일괄) | 360.0 KB | -14.4% | 10개 언어 전체 500개 메시지 JSON 일괄 번들링 |
| i18next (기본 일괄) | 420.4 KB | 기준선 (Baseline) | 10개 언어 전체 500개 메시지 JSON 및 전체 런타임 라이브러리 번들링 |
시나리오 2: 경량 시작 앱 (5개 언어 · 네임스페이스 내 총 100개 메시지)
이 시나리오에서는 네임스페이스에 총 100개의 메시지가 존재하며, 페이지에서 100개 전체를 참조하여 렌더링합니다:
| 라이브러리 및 빌드 모드 | 첫 화면 전송 크기 | i18next 기본 대비 | 메커니즘 특성 |
|---|---|---|---|
| ts-intl (로케일 분할) | 29.7 KB | -83.8% | 코어 런타임 약 2 KB, 활성 언어의 100개 메시지 JSON만 전송 |
| paraglide (미들웨어 분할) | 36.1 KB | -80.3% | 활성 언어의 100개 컴파일된 메시지 함수만 전달 |
| paraglide (기본 일괄) | 47.1 KB | -74.3% | 5개 언어 100개 메시지 컴파일 함수 일괄 번들링 |
| ts-intl (기본 일괄) | 56.9 KB | -69.0% | 5개 언어 100개 메시지 JSON 일괄 번들링 |
| i18next (HTTP 동적 로드) | 167.5 KB | -8.6% | 클라이언트가 활성 언어 JSON 비동기 요청, 베이스 런타임 포함 |
| i18next (기본 일괄) | 183.3 KB | 기준선 (Baseline) | 5개 언어 100개 메시지 JSON 및 전체 런타임 라이브러리 일괄 번들링 |
기술 아키텍처 및 번들 크기 구성 분석
1. 컴파일러 기반 솔루션의 트리쉐이킹(Tree-shaking) 이점과 트레이드오프
- 장점:
paraglide는 각 번역 메시지를 개별적으로 내보내지는 JavaScript 함수로 컴파일합니다. 번들러(Rollup / esbuild)는 AST 분석을 통해 코드에서 참조되지 않는 함수를 빌드 타임에 감지하여 제거(트리쉐이킹)할 수 있습니다. 시나리오 1에서 사용되지 않은 400개 메시지가 번들에서 완전히 제외되므로 전송 크기가 가장 작습니다(36.3 KB). - 트레이드오프: 전용 코드 생성 빌드 단계가 반드시 필요하며, 런타임에 동적으로 원격 딕셔너리를 교체하거나 핫 리로드하기 어렵습니다.
2. 경량 런타임 솔루션의 온디맨드 로케일 분할 이점
- 코드 생성 불필요:
ts-intl은 순수 TypeScript 런타임 라이브러리입니다. 코드 생성 단계 없이 표준 TypeScript 객체나 JSON 파일을 직접 소비합니다. - 언어 수 증가에 대한 독립성:
locale-splitting모드에서는 번들러의 동적 임포트(Dynamicimport())를 활용하여 언어별 딕셔너리가 별도 청크로 분할됩니다. 클라이언트는 현재 활성화된 언어 청크만 다운로드하므로, 지원 언어가 5개에서 10개 이상으로 늘어나더라도 단일 페이지 초기 네트워크 전송량은 거의 일정하게 유지됩니다(~30 KB ~ 57 KB). - 외부 런타임 의존성 제로:
ts-intl코어 런타임은 압축 시 약 2 KB에 불과하며, 브라우저 표준 WebIntlAPI를 직접 활용하여 복수형 및 숫자/날짜 포맷을 처리하므로 거대한 외부 파서나 엔진을 포함하지 않습니다.
3. 전통적 런타임 라이브러리의 용량 증가 원인
i18next는 방대한 설정 관리 시스템, 이벤트 이미터, AST 파서, 커스텀 포매터를 자체 내장하고 있어 기본 런타임 번들 크기가 상대적으로 큽니다.- 일반적인 설정에서는 정적
import를 통해 모든 언어 리소스를 단일 진입점에 가져오므로, 실제로 사용되지 않는 언어 딕셔너리까지 클라이언트 초기 청크에 모두 번들링됩니다.
로컬에서 벤치마크 재현하기
벤치마크 테스트 스위트 소스 코드는 apps/benchmark에 위치해 있습니다. 로컬 환경에서 직접 다음 명령을 실행하여 결과를 재현할 수 있습니다:
# 1. 테스트용 Chromium 설치 (최초 1회만 필요)
pnpm --filter @aaakul/ts-intl-benchmark prebench
# 2. 전체 벤치마크 매트릭스 실행 (SSG 빌드 및 Playwright 샘플링 자동 수행)
pnpm --filter @aaakul/ts-intl-benchmark bench
# 3. 로컬 프리뷰 서버 실행 (http://localhost:3005 에서 시각화 결과 확인)
pnpm --filter @aaakul/ts-intl-benchmark preview