방춘덕(고양이 키우면 지을 이름)의 개발 블로그입니다.
polyfill과 transpiler 본문
목차
- polyfill
- transpiler
- polyfill과 transpiler의 차이
1. polyfill
JS는 각 버전별로 문법과 동작이 매우 급변하는데, 브라우저 개발사가 항상 이에 맞게 최신 버전으로 업데이트를 하지만 소수의 사용자만이 제때 업데이트를 한다. 또한 각 브라우저들 마다 약간씩 API의 지원 범위가 차이가 나는데 이 모든 걸 개발자들이 신경 쓰기 어려운 것이 현실이다.
이를 위해 polyfill이 생겼는데, polyfill은 모던 브라우저에서만 지원하던 API들을 이전 버전의 브라우저에서도 동작하게끔 도와준다.
아래의 예를 보고 이해해보자.
'use strict';
/* http://www.ecma-international.org/ecma-262/6.0/#sec-number.isnan */
module.exports = function isNaN(value) {
return value !== value;
};
is-nan es-shim에서 가져온 코드이다. polyfill을 사용하면 isNaN을 지원하지 않더라도, 미리 구현된 코드를 통해 모던 브라우저와 같은 결과를 낼 수 있게 도와준다.
여기서 의문이 하나 들었다. 이렇게 하위 호환성을 위한 코드가 늘어나면 코드의 전체 크기가 커져 로딩이 오래 걸리지 않을까? 정답은 맞다. 실제로 로딩 시간은 길어진다. 하지만 속도를 제외하고 생산성과 유지보수의 측면에서 바라본다면 손해보단 이득이 크다.
그렇다면 polyfill코드의 크기를 줄여보는 것은 어떨까? 이 글의 마지막 부분을 봐보면, 작성자는 코드를 빌드하는 시점에서 코드를 분석해서 사용할 코드에 대해서만 polyfill을 추가했다고 한다. 하지만 이러한 노력에도 불구하고 그저 11kb만 감소하였고, 이미 이러한 최적화 방법들이 훌륭하다고 말해주고 있다.
마지막으로 모든 코드가 polyfill이 가능하거나 동일한 결과를 보장할 수 없을 수도 있다고한다. 따라서 개발자들은 사용하려는 함수가 어떻게 구현됐는지 가능하면 알아야 한다. 아래 관련된 shim들에 대한 링크를 걸어두도록 하겠다.
2. transpiler
class, const, let등 API와 관련 없이 아예 새로운 문법을 사용하고 싶을 때는 어떻게 해야 할까? 이러한 상황에서 사용해야 하는 것이 바로 transpiler다. transform + compiler를 합친 단어로 새로운 문법이 사용된 코드를 이전 문법으로 변환해주는 작업을 담당한다.
class Person {
constructor(name) {
this.name = name
}
showName() {
console.log(name)
}
}
const mrWang = new Person('Chunsik Wang')
mrWang.showName()
위 class 키워드는 es6에서 지원하는 문법이다. 이를 대표적인 transpiler인 babel로 가장 흔하게 변환하는 es6 -> es5로 변환해본다면 아래와 같이 변경된다. (이 사이트에서 직접 해볼 수 있다.)
"use strict";
function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } }
function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
var Person =
/*#__PURE__*/
function () {
function Person(name) {
_classCallCheck(this, Person);
this.name = name;
}
_createClass(Person, [{
key: "showName",
value: function showName() {
console.log(name);
}
}]);
return Person;
}();
var mrWang = new Person('Chunsik Wang');
mrWang.showName();
3. polyfill과 transpiler의 차이
polyfill과 transpiler는 비슷하면서 다르다. 둘 다 최신 기능을 구 버전의 실행환경에서 동작 가능하게 바꿔준다는 점이다. 하지만 polyfill은 오롯이 API에서만 구 버전 지원을 도와주고, transpiler는 신규 문법을 구 버전으로 바꿔주는 역할을 한다.
이해하기 쉽게 표로 알아보자.
polyfill | transpiler | |
Map | O | |
Promise | O | |
Array.prototype.includes | O | |
class | O | |
let, const | O | |
() => {} (Arrow Function) | O |
이 글을 작성할 때 읽은 감사한 자료들.
https://www.geeksforgeeks.org/javascript-polyfilling-transpiling/
https://remysharp.com/2010/10/08/what-is-a-polyfill/
http://www.logeshpaul.com/blog/polyfilling-and-transpiling/
https://en.wikipedia.org/wiki/Polyfill_(programming)
'JS' 카테고리의 다른 글
Virtual DOM (0) | 2020.01.18 |
---|---|
ECMAScript와 그 역사 (0) | 2020.01.10 |
event bubbling, capturing, delegation (0) | 2019.12.27 |
closure (0) | 2019.12.20 |
prototype과 prototype chain (0) | 2019.12.16 |