트랜스파일러(Transpiler) : 바벨(Babel)과 폴리필(Polyfill) & 효율적인 Polyfill 사용 방법

 

01. 트랜스파일러(Transpiler)란?

트랜스파일러는 소스 코드를 다른 소스 코드로 변환하는 도구이다. 이는 컴파일러의 확장된 개념으로, 전통적인 컴파일러가 고급 언어를 기계어로 변환하는 것과 달리, 트랜스파일러는 같은수준의 언어에서 다른 형태의 언어로 변환한다.

예를 들어, 최신 자바스크립트 (ES6+) 코드를 구버전 자바스크립트(ES5)로 변환하는 것이 트랜스파일링이다.

 

프론트엔드 기술은 빠르게 발전하고 있으며, ECMAScript(ES)는 매년 새로운 자바스크립트 문법을 추가하고 있다. 하지만 모든 브라우저가 이 새로운 문법을 즉시 지원하지는 않기 때문에, 트랜스파일러를 사용해 코드를 변환하여 다양한 환경에서 문제없이 실행할 수 있도록 한다.

 

 

02. 바벨(Babel)

Babel은 최신 자바스크립트(ES6+) 코드를 구버전 자바스크립트(ES5)로 변환하는 자바스크립트 컴파일러이다.

위 사진처럼 공식 사이트에 따르면 바벨은 자바스크립트 컴파일러라고 한다. 왜 컴파일러라 할까?

 

현대에 컴파일이라는 용어는 넓은 의미로 사용된다. 전통적으로 컴파일은 고급 언어를 기계어로 변환하는 것을 의미했지만, 지금은 소스 코드를 다른 형태로 변환하는 거의 모든 작업을 포함하게 되었다. 이 확장된 의미에서 트랜스파일링도 컴파일링의 한 형태로 간주되는 것이다. 따라서 바벨은 트랜스파일러이지만, 위와 같은 이유로 자바스크립트 컴파일러라고도 한다.

 

 

💡 바벨(Babel)이 필요한 이유

ECMAScript(ES)는 매년 새로운 기능을 도입하고 있지만, 모든 브라우저가 이를 즉시 지원하지는 않는다.

Babel은 이를 해결하기 위해 최신 문법을 변환하여 다양한 환경에서도 코드를 실행할 수 있게 도와준다.

// ES6 문법
class Person {
  constructor(name) {
    this.name = name;
  }

  sayHello() {
    console.log(`Hello, ${this.name}!`);
  }
}

const person = new Person('guswjd');
person.sayHello();

 

위의 예시 코드처럼 ES6에서 도입된 화살표 함수나 class 와 같은 문법을 Bable은 일반 함수나 프로토 타입을 이용한 함수로 변환해준다.

// Babel 변환 후
function Person(name) {
  this.name = name;
}

Person.prototype.sayHello = function () {
  console.log('Hello, ' + this.name + '!');
};

var person = new Person('guswjd');
person.sayHello();

 

 

 

🔥 바벨(Babel)의 한계

Babel은 문법적 변환만 담당하며, 최신 자바스크립트 기능(예: Promise, Set, Map) 자체는 변환하지 않는다.

Babel은 기존에 존재하는 구문을 변환할 수 있지만, 새로운 전역 객체나 메서드는 변환할 수 없다.

// 최신 자바스크립트 코드
const arrowFunc = () => {};

const aPromise = new Promise((resolve) => resolve("done"));

const includesMethod = [1, 2, 3].includes(2);

const aSet = new Set([1, 2, 3]);

 

이 코드가 트랜스파일링 되면 아래와 같다.

// Babel 컴파일 결과
var arrowFunc = function arrowFunc() {}; // 화살표 함수는 변환됨

var aPromise = new Promise();            // Promise는 변환되지 않음

var includesMethod = [1, 2, 3].includes(2); // includes 메서드는 변환되지 않음

var aSet = new Set([1, 2, 3]);           // Set 객체는 변환되지 않음

 

즉, 어떤 ES6+ 문법은 정상적으로 바벨에 의해 트랜스파일링 되었지만, 어떤 문법은 트랜스파일링 되지 못했다.

이를 해결하기 위해 Polyfill이 필요하다.

 

 

 

 

03. 폴리필 (Polyfill)

Polyfill은 최신 기능을 지원하지 않는 브라우저에서 해당 기능을 사용할 수 있도록 하는 코드 조각이다.

간단히 말해, 최신 자바스크립트 기능이 오래된 브라우저에서도 동작하도록 만들어주는 역할을 한다.

MDN에서는 Polyfill을 다음과 같이 정의하고 있다.

"Polyfill은 이전 브라우저에서 기본적으로 지원하지 않는 최신 기능을 제공하는 데 필요한 코드입니다."

 

 

#1. Polyfill이 필요한 이유

JavaScript의 기능은 ECMAScript 표준을 따라 계속 발전하고 있으며, 새로운 메서드와 객체가 추가된다.

하지만 오래된 브라우저들은 이러한 최신 기능을 지원하지 않기 때문에, 코드가 정상적으로 동작하지 않을 수 있다.

예를 들어, 다음과 같은 코드들은 최신 브라우저에서는 문제없이 실행되지만, 오래된 브라우저에서는 오류를 발생시킬 수 있다.

[1, 2, 3].at(-1); // 최신 브라우저에서만 지원

Promise.resolve(1); // 오래된 브라우저에서는 Promise 객체가 없음

new Set([1, 2, 3]); // Set 객체 역시 오래된 브라우저에서 지원하지 않음

이러한 문제를 해결하기 위해 Polyfill을 사용하여 해당 기능이 없는 브라우저에서도 정상적으로 동작하도록 기능을 추가할 수 있다.

 

 

 

#2. Polyfill 적용 방식

◼︎ 개별 폴리필 적용

특정 기능이 필요한 경우, 해당 기능에 대한 폴리필을 직접 추가할 수 있다.

예를 들어, Array.prototype.includes의 폴리필 코드를 MDN에서 찾아 적용할 수 있다.

// Array.prototype.includes 폴리필
if (!Array.prototype.includes) {
  Array.prototype.includes = function (element) {
    return this.indexOf(element) !== -1;
  };
}

 

◼︎ 폴리필 라이브러리 사용

core-js 라이브러리를 사용하면 여러 기능의 폴리필을 한꺼번에 추가할 수 있다.

core-js는 다양한 최신 기능의 폴리필을 제공하며, 필요에 따라 자동으로 필요한 폴리필만 적용할 수도 있다.

npm install core-js
import 'core-js/stable';
import 'regenerator-runtime/runtime';

 

 

 

🔥 Polyfill의 문제점(위의 방식처럼 사용하였을 경우)

◼︎ 파일 크기 증가

core-js나 개별 폴리필을 적용하는 방식으로 코드를 작성하면 폭넓은 브라우저를 지원할 수 있다.

하지만 JavaScript 파일의 크기가 커지는 문제가 발생할 수 있다.

특히, core-js처럼 전체 Polyfill을 추가하는 경우 최신 브라우저에서도 불필요한 코드가 포함될 수 있으며 이는 초기 로딩 시간이 늘어나고 사용자 경험은 저하될 것이다. 실행해야 하는 polyfill 스크립트가 많아질수록 사용자가 경험하는 웹 서비스의 성능은 나빠질 것이다.

 

◼︎ 최신 브라우저에서의 비효율성

최신 브라우저에서는 대부분의 최신 기능이 이미 구현되어 있다.

그러나 전체 polyfill을 추가할 경우, 이미 지원되는 기능에 대한 코드까지 내려받아야 하므로 불필요하게 리소스를 낭비하게 된다.

 

 

 

 

04. 효율적인 Polyfill 사용 방법

1️⃣ @babel/preset-env 사용하기

@babel/preset-env는 브라우저 호환성 목록을 기반으로 필요한 Polyfill만 추가해주는 Smart Preset이다.

예를 들어, Internet Explorer 11을 지원하도록 Babel 설정하도록 하자.

// babel.config.js
module.exports = {
  presets: [
    ['@babel/preset-env', { targets: { ie: 11 } }],
  ],
};

 

이 설정 후, core-js/actual을 import하면 IE 11에 필요한 Polyfill만 포함되게 된다.

import 'core-js/actual';

 

만약 IE 11을 지원 브라우저에서 제외하면 더 적은 polyfill이 포함되게 될 것이다.

위와 같이 @babel/preset-env를 통해 불필요한 스크립트 크기를 줄일 수 있다.

 

 

 

2️⃣ user-agent에 따라 동적으로 Polyfill 생성하기

앞서 Babel을 올바르게 설정함으로써 포함되는 Polyfill 스크립트의 크기를 줄일 수 있다. 하지만 최신 버전의 브라우저에서 불필요한 스크립트를 내려받게 되는 문제는 동일하다. 최신 브라우저에서 불필요한 Polyfill이 다운로드되는 문제를 해결하기 위해 브라우저의 User-agent에 따라 필요한 Polyfill만 동적으로 제공하는 방법이 있다. polyfill.io 서비스는 이 방식을 구현한 대표적인 예시이다.

 

polyfill.io는 사용자의 브라우저에 맞춰 어떤 Polyfill이 필요한지 판단하고, 그에 맞는 스크립트를 동적으로 생성하여 제공한다. 최신 브라우저에서는 Polyfill이 필요 없으므로 빈 스크립트가 반환되며, 구형 브라우저에서는 필요한 Polyfill만 제공하여 불필요한 코드나 크기를 줄일 수 있다.

  1. 최신 Chrome 브라우저에서는 빈 스크립트를 반환하고, (최신 브라우저에서는 Polyfill을 내려받지 않으며, 브라우저가 해당 기능을 네이티브하게 지원하기 때문에 추가적인 코드가 불필요)
  2. Internet Explorer 11에서는 필요한 Polyfill 스크립트만 제공한다. (구형 브라우저에서는 필요한 polyfill만 선택적으로 내려받아, 불필요한 코드나 크기 감소)

 

최신 버전의 브라우저에서 polyfill.io를 호출하면 빈 스크립트가 반환된다.

예를 들어, 아래와 같이 최신 Chrome에서 polyfill.io를 호출하면 빈 스크립트가 반환된다.

$ curl -XGET "https://polyfill.io/v3/polyfill.min.js" \
   -H "User-Agent: Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) Chrome/109.0.0.0"
/* 빈 스크립트 */

 

IE 11에서 호출하면 필요한 Polyfill 스크팁트만 반환된다. 

IE11은 최신 기능을 네이티브로 지원하지 않으므로, 필요한 기능에 맞는 Polyfill이 제공된다.

아래와 같이 polyfill.io를 호출하면 해당 브라우저에 필요한 Polyfill 스크립트가 반환된다.

$ curl -XGET "https://polyfill.io/v3/polyfill.min.js" \
   -H "User-Agent: Mozilla/5.0 (Windows NT 10.0; Trident/7.0; rv:11.0) like Gecko"

 

 

 

polyfill.io는 요청할 때 features 파라미터를 통해 명시적으로 필요한 기능을 지정할 수 있다.

예를 들어, Promise와 Array.prototype.includes 기능에 대한 Polyfill을 요청하려면 아래와 같이 할 수 있다.

<script src="https://polyfill.io/v3/polyfill.min.js?features=Promise%2CArray.prototype.includes"></script>

 

이렇게 설정하면 Promise와 Array.prototype.includes에 대한 Polyfill만 로드된다.

최신 브라우저에서는 필요 없지만, 구형 브라우저에서는 필요한 Polyfill을 내려받을 수 있다.

 

 

 


References

https://toss.tech/article/smart-polyfills

 

똑똑하게 브라우저 Polyfill 관리하기

현대적인 JavaScript를 쓰면서도 넓은 범위의 기기를 지원하기 위한 Polyfill을 어떻게 똑똑하게 설정할 수 있는지 소개합니다.

toss.tech

 

https://happysisyphe.tistory.com/49

 

컴파일과 폴리필의 차이점 분석 (babel, polyfill)

서언 웹 생태계에서 JavaScript는 브라우저와 뗄 수 없는 관계입니다. JavaScript는 매번 새로운 버전을 출시합니다. 그러면 브라우저는 최신 문법을 이해할 수 없게 됩니다. 만일 브라우저가 빠르게

happysisyphe.tistory.com

 

반응형