Polyfill 은 최신 웹 기능을 지원하지 않는 구형 브라우저에서도 그 기능을 사용할 수 있게 해주는 JavaScript 코드 또는 플러그인을 의미합니다. 즉, Polyfill 은 최신 기능을 구형 브라우저 환경에 맞춰주는 보완 코드입니다.

Polyfill 이 필요한 이유
웹 표준과 JavaScript 는 꾸준히 발전하면서 새로운 기능과 API가 추가되고 있습니다. 예를 들어, 2015년에 JS의 메이저 업데이트로 추가된 ES6 등이 있습니다. 이 중 Promise, fetch, Array.prototype.includes 등은 오래된 브라우저에서는 지원되지 않습니다. 더 정확히 말하면 구형 브라우저의 엔진이 해당 기능을 지원하지 않기 때문에 위와 같은 코드를 만나면 코드가 제대로 실행되지 않거나, 오류가 발생하게 됩니다. 그리고 이런 구형 브라우저에서는 이러한 최신 기능을 아직 지원하지 않거나 부분적으로만 지원하는 경우가 많습니다. 이런 상황에서, 개발자는 새로운 기능을 사용하고 싶어도 구형 브라우저 사용자를 고려해야 하는 문제가 발생합니다.
Polyfill은 이러한 문제를 해결해 줍니다. 구형 브라우저가 최신 문법의 기능을 지원하지 않을 때, Polyfill은 그 기능을 흉내내어 동일한 결과를 제공하여, 모든 사용자에게 일관된 경험을 제공합니다.
Polyfill 의 동작
Polyfill은 기본적으로 기능 감지(Feature Detection)를 통해 필요한 경우에만 동작하도록 설계됩니다. 예를 들어, 아래의 코드처럼 fetch API 가 지원되지 않는 브라우저에서는 Polyfill을 추가로 로드하고, 최신 브라우저에서는 기본 기능을 사용하도록 할 수 있습니다.
if (!'fetch' in window)) {
const script = document.createElement('script');
script.src = 'path/to/fetch-polyfill.js';
document.head.appendChild(script);
}
Polyfill 의 장점
- 호환성 유지: Polyfill을 통해 구형 브라우저 사용자들도 최신 웹 애플리케이션의 기능을 문제없이 사용할 수 있습니다.
- 개발 편의성: 개발자는 최신 기능을 걱정없이 사용할 수 있으며, Polyfill이 구형 브라우저에서 필요한 기능을 추가해줍니다.
- 일관된 사용자 경험: 모든 사용자에게 동일한 기능과 사용자 경험을 제공할 수 있습니다.
Polyfill 의 한계
- Polyfill 은 최신 기능을 구형의 브라우저 환경에서 에뮬레이션하는 방식이기 때문에 기능과 성능에 영향을 줄 수 있습니다. 무거운 기능을 Polyfill로 구현할 경우 실행 속도가 느려질 수 있습니다.
- 최신 기능을 완전히 동일하게 구현하는 데에는 한계가 있을 수 있으며, 특정 부분에는 부분적인 기능만 지원될 수 있습니다.
Polyfill 사용
실제 Polyfill을 프로젝트에 추가하는 방법은 여러가지가 있습니다. 가장 많이 사용되는 방법은 core-js 와 같은 라이브러리를 사용하는 것입니다. 바벨(Babel)을 함께 사용하면 소스 코드에 필요한 Polyfill을 자동으로 삽입하여 빌드 할 수 있습니다. 또한 Polyfill.io 와 같은 서비스는 특정 브라우저가 지원하지 않는 기능에 대해서 필요한 Polyfill을 제공하므로 효율적입니다.
// babel.config.js 또는 .babelrc
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage" // Babel 이 소스 코드를 분석하고 코드에서 필요한 폴리필만 추가
"corejs": 3 // core-js의 특정 버전 지정
}
]
]
}
또는, 직접 가져올 수도 있습니다.
import 'core-js/stable'; // Promise 등의 ES6
import 'regenerator-runtime/runtime'; // async/await
Polyfill 사용하지 않기
최신 브라우저만을 타겟으로 한다면 Polyfill이 필요하지 않을 수 있습니다. 타입스크립트를 사용한다면 tsconfig 에서는 target을 ES6 또는 ESNext로 설정할 필요가 있습니다. 그리고 아래와 같이 babel을 설정합니다.
{
presets: [
[
"@babel/preset-env",
{
targets: {
esmodules: true, // 최신 브라우저만 타겟으로 설정 (자동 폴리필 포함 X)
},
useBuiltIns: false // Polyfill 비활성화
}
]
]
}
Polyfill 만들어보기
fetch API는 XMLHttpRequest(XHR) 보다 현대적인 방식으로 HTTP 요청을 처리할 수 있게 해주는 새로운 API로, xhr의 댠순한 문법적인 개선 이상의 효과를 보여줍니다. Promise 기반이기에 비동기 요청의 처리가 더 간결하고 에러 핸들링도 쉽습니다. 또한 스트림을 사용하여 대용량 데이터를 더 효율적으로 처리할 수 있는 기능을 제공하며, 응답이 완료되기 전이라도 데이터를 점진적으로 처리할 수 있는 기능을 제공합니다. 이는 특히 대용량 파일이나 미디어 데이터를 다룰 때 유용하며, 성능 향상에 기여할 수 있습니다.
다음은 fetch 가 출시하기 이전에 사용되었던 xhr을 이용하여 fetch api 를 모방하도록 만든 Polyfill 입니다.
(function () {
if (!("fetchh" in window)) {
console.log("Fetch API is not supported..!");
window.fetchh = function (url, options) {
return new Promise2(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(options && options.method ? options.method : "GET", url);
if (options && options.headers) {
Object.keys(options.headers).forEach(function (header) {
xhr.setRequestHeader(header, options.headers[header]);
});
}
xhr.onload = function () {
var response = {
ok: xhr.status >= 200 && xhr.status < 300,
status: xhr.status,
statusText: xhr.statusText,
url: xhr.responseURL,
text: function () {
return Promise2.resolve(xhr.responseText);
},
json: function () {
return Promise2.resolve(JSON.parse(xhr.responseText));
},
blob: function () {
return Promise2.resolve(new Blob([xhr.response]));
},
};
resolve(response);
};
// Handle network errors
xhr.onerror = function () {
reject(new TypeError("Network request failed"));
};
// Handle request timeout
xhr.ontimeout = function () {
reject(new TypeError("Network request time out"));
};
// Send request
xhr.send(options && options.body ? options.body : null);
});
};
}
})();
fetch API 자체가 ES6의 Promise를 기반으로 하기에 코드 안에 Promise가 들어있습니다. 그러나 fetch API, Promise 이 둘은 거의 같은 시기에 표준화 되었기에, fetch를 지원하지 않는다면 Promise 또한 지원하지 않을 확률이 있을 것 같습니다. 여기서 Promise 까지 Polyfill로 만들어보았습니다.
비동기 처리를 보장하도록 setTimeout을 사용했습니다.
(function () {
if (!("Promise2" in window)) {
window.Promise2 = function (executor) {
var resolveCallbacks = [];
var rejectCallbacks = [];
var isFulfilled = false;
var isRejected = false;
var value;
function resolve(val) {
if (isFulfilled || isRejected) return;
isFulfilled = true;
value = val;
setTimeout(function () {
resolveCallbacks.forEach(function (callback) {
callback(value);
});
}, 0);
}
function reject(reason) {
if (isFulfilled || isRejected) return;
isRejected = true;
value = reason;
setTimeout(function () {
rejectCallbacks.forEach(function (callback) {
callback(value);
});
}, 0);
}
this.then = function (onFulfilled) {
return new Promise2(function (resolve, reject) {
function handleFulfilled() {
try {
var result = onFulfilled(value);
resolve(result);
} catch (error) {
reject(error);
}
}
if (isFulfilled) {
setTimeout(handleFulfilled(), 0);
} else if (!isRejected) {
resolveCallbacks.push(handleFulfilled);
}
});
};
this.catch = function (onRejected) {
return new Promise2(function (resolve, reject) {
function handleRejected() {
try {
var result = onRejected(value);
resolve(result);
} catch (error) {
reject(error);
}
}
if (isRejected) {
setTimeout(handleRejected(), 0);
} else if (!isFulfilled) {
rejectCallbacks.push(handleRejected);
}
});
};
executor(resolve, reject);
};
// 캡슐화. Promise 내부에서만 사용하도록 하기 위함.
Promise2.resolve = function (value) {
return new Promise2(function (resolve) {
resolve(value);
});
};
Promise2.reject = function (reason) {
return new Promise2(function (resolve, reject) {
reject(reason);
});
};
}
})();
코드: https://codesandbox.io/p/sandbox/gs6svd
Reference
fetch - https://github.com/JakeChampion/fetch
GitHub - JakeChampion/fetch: A window.fetch JavaScript polyfill.
A window.fetch JavaScript polyfill. Contribute to JakeChampion/fetch development by creating an account on GitHub.
github.com
Polyfill, MDN - https://developer.mozilla.org/en-US/docs/Glossary/Polyfill
Polyfill - MDN Web Docs Glossary: Definitions of Web-related terms | MDN
A polyfill is a piece of code (usually JavaScript on the Web) used to provide modern functionality on older browsers that do not natively support it.
developer.mozilla.org
https://create-react-app.dev/docs/supported-browsers-features
Supported Browsers and Features | Create React App
Supported Browsers
create-react-app.dev
폴리필 - https://ko.javascript.info/polyfills#ref-404
폴리필
ko.javascript.info
'웹 개발' 카테고리의 다른 글
| pnpm 1편 - (부제: "왜 npm ci --legacy-peer-deps를 쓰나요?") (5) | 2025.06.07 |
|---|---|
| Playwright 를 이용한 E2E 테스트 (0) | 2025.05.05 |
| 번들러와 기능 (0) | 2024.09.20 |
| 로컬 스토리지 (Local Storage) | Web Storage API (0) | 2024.07.06 |
| 캐싱 전략 - Cache-Control (0) | 2024.05.29 |