본문으로 건너뛰기
기술스택 · stack/javascript/폴리필과 트랜스파일러: 오래된 브라우저 대응

JavaScript · 3장 코드 품질과 도구

폴리필과 트랜스파일러: 오래된 브라우저 대응

최신 문법과 기능으로 코드를 써도, 사용자의 브라우저가 그걸 모르면 페이지가 깨져요. 새 코드를 옛 브라우저에서도 돌게 해 주는 두 가지 도구와, 어디까지 지원할지 정하는 법을 정리했어요.

#3.6 · Vite · Browserslist 기준

01. 새 코드와 옛 브라우저 사이의 두 가지 빈틈

오래된 브라우저가 최신 코드를 못 돌리는 이유는 두 가지예요. 대응 방법도 각각 달라요.

빈틈예옛 브라우저에서해결
문법을 몰라요a ?? b, obj?.name, #private 필드코드를 읽는 단계에서 SyntaxError — 파일 전체가 실행되지 않아요트랜스파일러
기능이 없어요array.at(), structuredClone, Object.groupBy그 줄에 닿을 때 TypeError (…is not a function)폴리필
①새 문법(??)은 트랜스파일러가 옛 문법으로 다시 쓰고, 없는 기능(at)은 폴리필이 빈자리를 채워요. 두 가지를 거친 코드는 옛 브라우저에서도 돌아가요.

02. 문법은 트랜스파일러가 바꿔요

트랜스파일러는 코드를 읽어서 같은 뜻의 옛 문법으로 다시 써 주는 도구예요. Babel이 대표적이고, TypeScript 컴파일러나 Vite가 쓰는 esbuild 같은 빌드 도구도 이 일을 해요. 빌드할 때 한 번 바뀌므로 사용자 브라우저에서는 추가로 할 일이 없어요.

예를 들어 ??는 "null이나 undefined면 오른쪽"이라는 뜻이니, 옛 문법으로는 조건 비교로 풀어 쓸 수 있어요. 도구가 실제로 만드는 코드는 조금 더 복잡하지만 뜻은 같아요.

const input = 0;

const modern = input ?? 10;                                        // 새 문법
const old = (input !== null && input !== undefined) ? input : 10; // 옛 문법으로 풀어 쓴 모양

console.log(modern, old); // 0 0

문법은 이렇게 미리 바꿔 둘 수밖에 없어요. 브라우저가 파일을 읽다가 모르는 문법을 만나면 파일 전체가 실행되지 않기 때문이에요(SyntaxError).

03. 없는 기능은 폴리필이 채워요

폴리필(polyfill)은 브라우저에 없는 내장 기능을 자바스크립트로 직접 만들어 끼워 넣는 코드예요. 먼저 그 기능이 있는지 확인하고(기능 감지), 없을 때만 채워요. 아래에서는 오래된 브라우저인 척 at을 일부러 지운 뒤, 간단한 폴리필로 다시 채워 볼게요.

// 오래된 브라우저인 척: at을 지워요
delete Array.prototype.at;
console.log(typeof [].at);           // undefined

// 폴리필: 없을 때만 채워요
if (typeof Array.prototype.at !== 'function') {
  Array.prototype.at = function (index) {
    const i = Math.trunc(index) || 0;
    return this[i < 0 ? this.length + i : i];
  };
  console.log('폴리필을 넣었어요');
}

console.log([10, 20, 30].at(-1));    // 30

원리는 이렇게 단순하지만, 실제 폴리필은 명세의 세세한 동작까지 똑같이 맞춰야 해서 직접 만들지 않아요. 검증된 라이브러리인 core-js를 쓰고, Babel 같은 도구가 지원 대상 브라우저에 필요한 것만 골라 넣게 해요.

04. 어디까지 지원할지 정하기

"모든 브라우저"를 지원하면 코드가 커지고 느려져요. 그래서 지원할 브라우저 목록을 먼저 정하고, 도구가 그 목록에 맞춰 바꾸고 채우게 해요. 이 목록을 적는 표준 같은 방법이 Browserslist예요. Babel · Autoprefixer 같은 여러 도구가 같은 목록을 읽어요.

package.json에 이렇게 적어요.

{
  "browserslist": ["baseline widely available"]
}

Browserslist는 Baseline을 그대로 목록으로 쓸 수 있어요(baseline widely available, baseline newly available, baseline 2024 같은 연도). 빌드 도구 Vite도 기본 대상이 'baseline-widely-available'이에요. 지금 버전 기준으로 Chrome · Edge 111, Firefox 114, Safari 16.4 이상이에요. 이 범위 밖의 옛 브라우저까지 지원해야 하면 그때 대상을 넓히고 폴리필을 더해요.

예전에는 페이지에 <script src="https://…/polyfill.js">처럼 다른 회사의 서버에서 폴리필을 받아 오는 방식도 많이 썼어요. 2024년에 널리 쓰이던 polyfill.io 도메인이 다른 손에 넘어가 악성 코드를 내보낸 사건 이후로는, 필요한 폴리필을 내 빌드 결과물에 직접 포함하는 게 원칙이에요.

아주 오래된 브라우저를 지원해야 해요. 아래 각각에 트랜스파일러와 폴리필 중 무엇이 필요할지 골라 보세요.

  • (가) user?.address
  • (나) Object.groupBy(items, fn)
  • (다) const add = (a, b) => a + b;
  • (라) [3, 1, 2].toSorted()
  • (마) count ??= 0;
해답 보기

문법인 (가) 옵셔널 체이닝, (다) 화살표 함수, (마) 논리 대입은 트랜스파일러가 옛 문법으로 바꿔요. 내장 기능인 (나) Object.groupBy, (라) toSorted는 폴리필이 채워요. 구분법: 새로운 기호 · 키워드면 문법, 무엇.이름()으로 부르는 함수면 기능이에요.

05. 실전 포인트

  • 언제 쓰나요? 대부분은 빌드 도구(Vite 등)의 기본 설정이 문법 변환을 알아서 해요. 사용자 통계를 보고 지원 범위를 Browserslist로 정한 뒤, 그 범위에 없는 기능을 쓸 때만 core-js 폴리필을 더해요.
  • 대신 쓰는 것: 막연히 "옛 브라우저도 되게" 모든 폴리필을 넣지 않아요. 지금 많이 쓰는 기능 대부분은 이미 Widely available이라 폴리필이 대부분의 사용자에게 무게만 더해요. 다른 서버에서 폴리필을 받아 오는 <script>는 쓰지 않아요.
  • 흔한 실수: 트랜스파일러만 설정하고 "옛 브라우저도 된다"고 믿는 것(기능은 폴리필이 따로 필요해요), 반대로 폴리필로 문법까지 해결하려는 것이에요. 지원 범위를 바꿨다면 실제 그 브라우저에서 한 번은 열어 봐요.

정리

  • 모르는 문법은 트랜스파일러(Babel · esbuild 등)가 빌드할 때 옛 문법으로 바꿔요.
  • 없는 기능은 폴리필(core-js)이 기능 감지 뒤 채워요. 직접 만들지 말고 검증된 라이브러리를 써요.
  • 지원 범위는 Browserslist로 정해요. baseline widely available처럼 Baseline을 쓸 수 있고, Vite의 기본 대상도 Baseline Widely available이에요.
  • 폴리필은 다른 서버에서 받아 오지 않고 내 빌드에 넣어요.
SIMPLE · 기술스택 / JavaScript — 3장 코드 품질과 도구