1. Polyfill?
자바스크립트의 최신 기능을 모두 사용하면서 오래된 브라우저를 지원하려면 Babel로 코드 문법을 변환함과 동시에
Polyfill도 사용해야 한다.
Polyfill은 런타임에 기능을 주입하는 것을 말한다. 런타임에 기능이 존재하는지 검사해서 기능이 없는 경우 주입한다.
Babel을 사용하면 최신 자바스크립트 표준에 추가된 모든 기능을 사용할 수 있다고 생각하겠지만 Polyfill에 대한
설정은 별도로 해야 한다.
예를 들어 ES8에 추가된 String.padStart 메서드는 폴리필을 통해서 추가할 수 있다.
if (!String.prototype.padStart) {
String.prototype.padStart = func;
}
func는 padStart 폴리필 함수이다.
2. core-js 모듈의 모든 폴리필 사용하기
core-js는 Babel에서 Polyfill을 공식적으로 지원하는 패키지이다. 가장 간단한 사용 방법은 core-js 모듈을
자바스크립트 코드로 불러오는 것이다.
import 'core-js';
const p = Promise.resolve(10);
const obj = {
a : 10,
b : 20,
c : 30,
}
const arr = Object.valuses(obj);
const exist = arr.includes(20);
core-js 모듈을 가져오면 해당 모듈의 모든 Polyfill이 포함된다.
즉, 낮은 버전의 브라우저에서도 프로미스, Object.values, 배열의 includes 메서드를 사용할 수 있다.
웹팩을 사용하는 경우에는 entry 속성에 core-js 모듈을 넣는다.
module.exports = {
entry: ['core-js', './src/index.js'],
...
}
core-js 모듈은 사용방법이 간단하지만, 필요하지 않은 Polyfill까지 포함되므로 번들 파일의 크기가 커진다.
그래서 번들 파일의 크기에 민감하지 않은 프로젝트에서 보통 사용한다.
3. core-js 모듈에서 필요한 Polyfill만 가져오기
core-js로부터 필요한 Polyfill만 가져오면 번들 파일의 크기를 줄일 수 있다.
import 'core-js/features/promise';
import 'core-js/features/object/values';
import 'core-js/features/array/includes';
const p = Promise.resolve(10);
const obj = {
a : 10,
b : 20,
c : 30,
}
const arr = Object.valuses(obj);
const exist = arr.includes(20);
필요한 Polyfill을 가져오는 방법은 번들 파일의 크기를 최소화할 수 있는 방법이므로 크기에 민감한 프로젝트에
적합하지만, Polyfill을 추가하는 과정이 번거롭고, 필요한 Polyfill을 포함시키지 않는 실수를 할 수 있다.
4. @babel/preset-env 프리셋 이용하기
@babel/preset-env 프리셋은 실행 환경에 대한 정보를 설정해 주면 자동으로 필요한 기능을 주입해준다.
예를 들어, babel.config.js 파일에 특정 버전의 브라우저를 위한 플러그인만 포함한다.
const presets = [
[
'@babel/preset-env',
{
targets: '> 0.25%, not dead',
}
],
]
module.exports = { presets };
targets 속성으로 지원하는 브라우저 정보를 입력한다. 시장 점유율이 0.25% 이상이고 업데이트가 종료되지 않은
브라우저를 입력했다.
브라우저 정보는 browserslist라는 패키지 문법을 사용한다.
실습
npm i @babel/core @babel/cli @babel/preset-env core-js
필요한 패키지를 설치하고 babel.config.js 파일을 만든다.
const presets = [
[
"@babel/preset-env",
{
targets: {
chrome: "40",
},
useBuiltIns: "entry",
corejs: { version: 3, preposals: true },
},
],
];
module.exports = { presets };
1 : @babel/preset-env 프리셋을 사용한다.
2 : 크롬 버전을 최소 40으로 설정한다.
3 : useBuiltIns 속성은 Polyfill과 관련된 설정으로 entry를 입력하면 지원하는 브라우저에서 필요한
폴리필만 포함시킨다.
4 : babel에게 core-js 버전을 알려준다.
npx babel src/code.js
바벨을 실행해보자.
"use strict";
require("core-js/modules/es.symbol.js");
require("core-js/modules/es.symbol.description.js");
require("core-js/modules/es.symbol.async-iterator.js");
...
require("core-js/modules/web.url-search-params.js");
var p = Promise.resolve(10);
var obj = {
a: 10,
b: 20,
c: 30
};
var arr = Object.valuses(obj);
var exist = arr.includes(20);
모듈을 가져오는 코드가 수십 줄에 걸쳐서 출력된다. 여기서 출력되는 Polyfill은 크롬 버전 40에 없는 기능을 위한 것
실제로 사용한 기능은 프로미스, Object.values, 배열의 includes 메서드밖에 없는데 불필요한 많은코드가 추가된다.
useBuiltIns 속성에 usage를 입력하면 코드에 사용된 기능의 Polyfill만 추가한다.
usage 옵션을 사용할 경우 code.js의 core-js 모듈을 가져오는 코드가 필요하지 않다.
// import "core-js";
const p = Promise.resolve(10);
const obj = {
a: 10,
b: 20,
c: 30,
};
const arr = Object.valuses(obj);
const exist = arr.includes(20);
const presets = [
[
"@babel/preset-env",
{
targets: {
chrome: "40",
},
useBuiltIns: "usage",
corejs: { version: 3, preposals: true },
},
],
];
module.exports = { presets };
결과를 살펴보면 코드와 관련된 세 개의 Polyfill이 추가되었다.
"use strict";
require("core-js/modules/es.object.to-string.js");
require("core-js/modules/es.promise.js");
require("core-js/modules/es.array.includes.js");
require("core-js/modules/es.string.includes.js");
// import "core-js";
var p = Promise.resolve(10);
var obj = {
a: 10,
b: 20,
c: 30
};
var arr = Object.valuses(obj);
var exist = arr.includes(20);
require("core-js/modules/es.string.includes.js");
그런데 문자열의 includes가 불필요하게 추가되었다.
이는 Babel이 코드에서 사용된 변수의 타입을 추론하지 못하기 때문이다. Babel의 입장에서는 보수적으로 Polyfill을
추가할 수밖에 없다.
자바스크립트는 동적 타입 언어이기 때문에 Babel 입장에서 타입 추론은 까다로운 문제이다.
타입 스크립트와 같은 정적 타입 언어를 사용한다면 비교적 쉽게 해결할 수 있다.
번들 크기를 최적화할 목적이라면 필요한 Polyfill을 직접 추가하는 방법이 가장 좋다.
하지만 번들 파일 크기를 유지하면서 Polyfill 추가를 깜빡하는 실수를 막고 싶다면 @babel/preset-env도 좋다.
깃허브
https://github.com/SeoJaeWan/test-babel-env
'React > 실험실' 카테고리의 다른 글
[React] Webpack - Plugin 사용 (0) | 2022.04.18 |
---|---|
[React] Webpack (1) | 2022.04.12 |
[React] Babel - 깊은 설정 (0) | 2022.04.05 |
[React] Babel (2) | 2022.04.04 |
[React] Webpack 환경에서 환경변수 사용 (1) | 2022.03.29 |