V8 Explicit Compile Hints — 주석 한 줄로 JavaScript 시작 속도를 630ms 줄이는 법
Chrome 136에 도입된 V8의 Explicit Compile Hints 기능으로 JavaScript 초기 로딩 성능을 개선하는 원리와 사용법을 분석한다.
브라우저가 JavaScript 파일을 받으면 즉시 모든 코드를 컴파일하지 않는다. "이 함수는 나중에 호출될 수도 있고, 안 될 수도 있으니까 일단 넘어가자"는 전략을 쓴다. 이를 **지연 컴파일(Lazy Compilation)**이라고 한다. 대부분의 경우 합리적인 전략이지만, 페이지 로드 직후 반드시 실행되는 함수까지 뒤로 미루면 오히려 병목이 된다. V8 13.5(Chrome 136)에 도입된 Explicit Compile Hints는 개발자가 "이 파일의 함수들은 전부 바로 실행된다"고 V8에 알려주는 기능이다. 주석 한 줄이면 된다.
지연 컴파일이 문제가 되는 순간
V8의 기본 전략은 이렇다.
| 단계 | 동작 | 시점 |
|---|---|---|
| 1. 파싱 | 함수 경계만 파악 (가벼운 파싱) | 스크립트 로드 시 |
| 2. 대기 | 함수 본문 컴파일 보류 | — |
| 3. 호출 | 함수가 실제 호출될 때 컴파일 | 메인 스레드 블로킹 |
비유하면 식당에서 주문을 받은 뒤 "손님이 젓가락을 들면 그때 요리를 시작"하는 것과 같다. 주문이 들어왔으면 미리 조리를 시작하는 게 당연히 빠르다.
문제는 3단계다. 함수가 호출되는 시점에 메인 스레드에서 컴파일이 일어나면, 그 시간 동안 UI가 멈춘다. 페이지 로드 직후 실행되는 초기화 코드, 라우팅 로직, 이벤트 핸들러 등이 전부 이 패턴에 해당한다.
[💡 잠깐! 이 용어는?] 지연 컴파일(Lazy Compilation): JavaScript 엔진이 함수 정의를 만나도 즉시 컴파일하지 않고, 함수가 처음 호출될 때 컴파일하는 전략. 메모리를 절약하지만, 호출 시점에 지연이 발생할 수 있다.
Explicit Compile Hints의 동작 원리
사용법은 놀라울 정도로 단순하다. JavaScript 파일 최상단에 매직 코멘트를 추가하면 된다.
//# allFunctionsCalledOnLoad
function initializeApp() {
const root = document.getElementById('root')
const config = loadConfig()
renderMainView(root, config)
}
function loadConfig() {
return JSON.parse(localStorage.getItem('app-config') || '{}')
}
function renderMainView(root, config) {
root.innerHTML = buildTemplate(config)
attachEventListeners(root)
}
function attachEventListeners(root) {
root.addEventListener('click', handleClick)
root.addEventListener('scroll', handleScroll)
}
initializeApp()//# allFunctionsCalledOnLoad 한 줄이면 V8은 이 파일의 모든 함수를 즉시 컴파일한다. 지연 없이 백그라운드 스레드에서 미리 컴파일을 끝내기 때문에, 함수가 호출되는 시점에는 이미 실행 준비가 완료되어 있다.
즉시 컴파일이 빠른 두 가지 이유
| 이유 | 설명 |
|---|---|
| 중복 작업 제거 | 지연 컴파일에서는 가벼운 파싱(함수 경계 파악) + 본격 파싱(컴파일)을 두 번 한다. 즉시 컴파일은 한 번에 끝낸다 |
| 백그라운드 병렬화 | 스크립트가 네트워크에서 로드되는 동안 백그라운드 스레드에서 컴파일을 진행한다. 메인 스레드가 블로킹되지 않는다 |
비유하면 택배가 오는 동안 포장을 뜯을 가위를 미리 준비해놓는 것과 같다. 택배가 도착하면 바로 개봉할 수 있다.
성능 벤치마크
V8 팀이 상위 20개 인기 웹사이트를 대상으로 테스트한 결과:
| 측정 항목 | 결과 |
|---|---|
| 개선된 사이트 | 20개 중 17개 |
| 평균 파싱+컴파일 시간 감소 | 630ms |
| 적용 방식 | 코드 변경 없이 주석 한 줄 추가 |
630ms는 사용자가 체감할 수 있는 수준의 차이다. Core Web Vitals의 FCP(First Contentful Paint)가 1.8초 이내여야 "Good" 등급인 점을 감안하면, 파싱+컴파일에서만 630ms를 절약하는 건 상당한 개선이다.
[💡 잠깐! 이 용어는?] FCP(First Contentful Paint): 브라우저가 페이지의 첫 번째 콘텐츠(텍스트, 이미지 등)를 화면에 렌더링하는 시점. LCP(Largest Contentful Paint)와 함께 Core Web Vitals의 핵심 지표다.
언제 써야 하고, 언제 피해야 하나
모든 파일에 //# allFunctionsCalledOnLoad를 붙이는 건 좋은 전략이 아니다. 즉시 컴파일은 메모리와 CPU를 더 사용하기 때문이다.
| 시나리오 | Explicit Compile Hint | 이유 |
|---|---|---|
| 앱 진입점 (entry.js) | O | 페이지 로드 직후 모든 함수가 실행됨 |
| 라우터 초기화 코드 | O | 첫 렌더링에 필수적인 코드 |
| Critical Path의 유틸리티 | O | 초기 렌더링에 사용되는 헬퍼 함수들 |
| 서드파티 라이브러리 | X | 라이브러리 전체를 즉시 컴파일하면 메모리 낭비 |
| 코드 스플리팅된 청크 | X | 지연 로드 목적으로 분리한 코드를 즉시 컴파일하면 취지에 반함 |
| 관리자 페이지 전용 코드 | X | 대부분의 사용자가 접근하지 않는 코드 |
비유하면 레스토랑 오픈 전에 모든 메뉴를 미리 조리해두는 건 비효율적이다. 오늘의 추천 메뉴만 미리 준비하고, 나머지는 주문이 들어오면 조리하는 게 맞다.
적용 가이드
1단계: 크리티컬 패스 파일 식별
Chrome DevTools의 Performance 탭에서 "Compile Script" 항목을 확인한다. 파싱+컴파일에 시간이 많이 소요되면서 페이지 로드 직후 실행되는 파일이 후보다.
2단계: 매직 코멘트 추가
const webpack = require('webpack')
module.exports = {
plugins: [
new webpack.BannerPlugin({
banner: '//# allFunctionsCalledOnLoad',
raw: true,
entryOnly: true
})
]
}Webpack의 BannerPlugin을 사용하면 엔트리 파일에만 자동으로 매직 코멘트를 삽입할 수 있다. 수동으로 파일마다 추가할 필요가 없다.
3단계: 효과 측정
# Chrome을 --enable-benchmarking 플래그로 실행
# Performance 탭 → Record → 페이지 로드
# "Parse Script" + "Compile Script" 항목의 시간 변화를 비교향후 발전 방향
현재는 파일 단위(allFunctionsCalledOnLoad)로만 힌트를 줄 수 있다. V8 팀은 향후 함수 단위의 세분화된 컴파일 힌트를 계획하고 있다. 특정 함수만 골라서 "이건 바로 실행된다"고 지정할 수 있게 되면, 파일 전체를 즉시 컴파일하는 것보다 더 정밀한 최적화가 가능해진다.
정리
- V8 13.5(Chrome 136)에 Explicit Compile Hints 기능이 도입됐다
//# allFunctionsCalledOnLoad매직 코멘트 한 줄로 파일 내 모든 함수를 즉시 컴파일한다- 상위 20개 웹사이트 중 17개에서 평균 630ms 파싱+컴파일 시간이 감소했다
- 앱 진입점, 라우터, Critical Path 코드에 적용하면 효과적이다
- 서드파티 라이브러리나 코드 스플리팅된 청크에는 적용하지 않는 것이 좋다
- 향후 함수 단위 힌트로 확장될 예정이다
코드 한 줄 바꾸지 않고 주석 한 줄 추가만으로 수백 밀리초를 절약할 수 있다. 비용 대비 효과가 이렇게 높은 최적화는 드물다. 페이지 로드 성능이 중요한 프로젝트라면 엔트리 파일에 먼저 적용해보는 것을 권한다.
참고:
- V8 Blog — Explicit Compile Hints: https://v8.dev/blog/explicit-compile-hints
- Chrome 136 Release Notes: https://developer.chrome.com/blog/chrome-136-beta
같은 카테고리 · JavaScript
비슷한 주제의 최신 글
태그가 겹치는 글
공통 태그가 많을수록 위에 보인다