정의
폴리필(옛 브라우저에 없는 함수를 채우는 코드)을 모든 방문자에게 무조건 주지 않고, "이 기능이 없나?"를 브라우저에서 실제로 한 줄 검사한 뒤 부족한 브라우저에만 로드하는 방식이다. 최신 브라우저는 감지만 하고 폴리필을 받지 않으므로 비용이 거의 0이 된다.
여기서 feature detection(기능 감지) 은 'at' in Array.prototype처럼 기능 유무를 직접 테스트하는 것으로, User-Agent 문자열을 파싱해 브라우저를 추측하는 방식보다 견고하다(UA는 위조·누락된다).
왜 필요한가
폴리필 번들은 쉽게 수십 KB가 된다. 이걸 전원에게 내려주면, 폴리필이 전혀 필요 없는 최신 브라우저 사용자(대개 다수)까지 매번 그만큼을 더 받고 파싱한다. 지원해야 할 옛 브라우저가 소수일수록 이 낭비가 커진다.
차등 로딩은 옛 브라우저에는 정확성을, 최신 브라우저에는 성능을 동시에 준다. 감지 비용은 인라인 스크립트 수십 바이트로 매우 싸고, 실제 폴리필 다운로드는 옛 브라우저만 지불한다.
동작 원리
- 지원 타깃에서 결손 API를 계산해 self-host 폴리필 번들을 빌드타임에 만든다.
<head>에 작은 동기 감지 스크립트를 둔다. 대표 API 몇 개를 검사한다.- 하나라도 없으면 그때만 폴리필 번들을 동기적으로 로드한다. 전부 있으면 아무것도 받지 않는다.
- 감지 스크립트는 앱 번들보다 먼저 실행돼야 한다 — 그래야 앱이 시작될 때 폴리필이 준비돼 있다.
<head>
<script>
// 대표 API 몇 개만 검사 — 하나라도 없으면 옛 브라우저로 판단
if (
!("at" in Array.prototype) ||
!("replaceAll" in String.prototype) ||
typeof structuredClone !== "function" ||
!("hasOwn" in Object)
) {
// 동기 로드: 앱 번들 실행 전에 폴리필이 준비되게
document.write('<script src="/polyfills-legacy.js"><\/script>');
}
</script>
</head>
실무 적용
- 최신 브라우저에서 네트워크 탭을 열어 "폴리필 미수신"을 확인한다.
- 옛 브라우저(또는 감지 강제)로 "수신·동작"을 확인한다.
- 폴리필은 외부 CDN이 아니라 같은 오리진에서 제공한다(공급망 공격 이력·가용성 위험 회피).
트레이드오프
| 옵션 | 최신 브라우저 비용 | 운영 부담 | 적합 상황 |
|---|---|---|---|
| 엔트리에 정적 포함 | +수십 KB 상시 | 없음 | 옛 브라우저가 다수거나 단순함이 우선 |
| 빌드타임 번들 + feature-detect 조건 로드 | ≈ 0 (감지 수십 B) | 없음 | 타깃이 "옛 vs 최신" 이분법일 때 최적 |
| UA 기반 서버 동적 생성 | ≈ 0 | 서버 운영 필요 | 브라우저 스펙트럼이 매우 넓을 때 |
사용하면 안 되는 경우
- 지원 타깃이 사실상 최신뿐이라 폴리필이 필요 없는 경우 — 감지 스크립트조차 군더더기.
- 감지 스크립트를 앱 번들 뒤에 두어, 앱이 폴리필 없이 먼저 시작해 초기에 터지는 배치.
흔한 실수
- 감지를 UA 문자열로 하다가 위조·신규 브라우저에 오판.
- 폴리필을 외부 CDN에서 받아 공급망·가용성 위험을 떠안기.
- 감지 스크립트를 async/defer로 두어 실행 순서가 밀리는 것.
관련 개념
- syntax-transpilation-vs-runtime-polyfill — 무엇을 폴리필해야 하는지(문법이 아니라 런타임 API)
- readonly-viewer-bundle-splitting — 필요할 때만 코드를 로드하는 청크 분리 사고