-
바벨 사용법과 웹팩 통합 - 바벨(Babel) | 김정환Front-end/개발환경 2020. 6. 10. 20:38반응형
4-2. 프리셋 사용하기
이처럼 바벨은 목적에 따라 몇 가지 프리셋을 제공한다.
· preset-env
· preset-flow
· preset-react
· preset-typescript
preset-env는 ECMAScript2015+를 변환할 때 사용한다. 바벨 7 이전 버전에는 연도별로 각 프리셋을 제공했지만(babel-reset-es2015, babel-reset-es2016, babel-reset-es2017, babel-reset-latest) 지금은 env 하나로 합쳐졌다. 무척 맘에 드는 부분이다.
preset-flow, preset-react, preset-typescript는 flow, 리액트, 타입스크립트를 변환하기 위한 프리셋이다.
인터넷 익스플로러 지원을 위해 env 프리셋을 사용해 보자.
먼저 패키지를 다운로드한다.
> npm install -D @babel/preset-env
설치한 바벨 설정을 조금만 더 바꿔본다.
babel.config.js :
module.exports = { presets: [ '@babel/preset-env' ] }
그리고 빌드하면,
> npx babel app.js
"use strict";
var alert = function alert(msg) {
return window.alert(msg);
};우리가 만든 mypreset.js와 같은 결과를 출력한다.
5. env 프리셋 설정과 폴리필
과거에 제공했던 연도별 프리셋을 사용해 본 경험이 있다면 까다롭고 헷갈리는 설정 때문에 애를 먹었을지도 모르겠다. 그에 비해 env 프리셋은 무척 단순하고 직관적인 사용법을 제공한다.
5-1. 타겟 브라우저
우리 코드가 크롬 최신 버전(2019년 12월 기준)만 지원하다고 하자. 그렇다면 인터넷 익스플로러를 위한 코드 변환은 불필요하다. target 옵션에 브라우저 버전명만 지정하면 env 프리셋은 이에 맞는 플러그인들을 찾아 최적의 코드를 출력해 낸다.
babel.config.js :
module.exports = { presets: [ [ '@babel/preset-env', { targets: { chrome: '79', // 크롬 79까지 지원하는 코드를 만든다 } } ] ] }
> npx babel app.js
"use strict";
const alert = msg => window.alert(msg);크롬은 블록 스코핑과 화살표 함수를 지원하기 때문에 코드를 변환하지 않고 이러한 결과물을 만들었다. 만약 인터넷 익스플로러도 지원해야 한다면 바벨 설정에 브라우져 정보만 하나 더 추가하면 된다.
babel.config.js :
module.exports = { presets: [ [ '@babel/preset-env', { targets: { chrome: '79', ie: '11' // ie 11까지 지원하는 코드를 만든다 } } ] ] }
5-2. 폴리필
이번엔 변환과 조금 다른 폴리필에 대해 알아보자.
ECMASCript2015의 Promise 객체를 사용하는 코드다.
app.js :
new Promise();
바벨로 처리하면 어떤 결과가 나올까?
> npx babel app.js
"use strict";
new Promise();env 프리셋으로 변환을 시도했지만 Promise 그대로 변함이 없다. target에 ie 11을 설정하고 빌드한 것인데 인터넷 익스플로러는 여전히 프라미스를 해석하지 못하고 에러를 던진다.
브라우저는 현재 스코프부터 시작해 전역까지 Promise라는 이름을 찾으려고 시도할 것이다. 그러나 스코프 어디에도 Promise란 이름이 없기 때문에 레퍼런스 에러를 발생하고 프로그램이 죽은 것이다.
플러그인이 프라미스를 ECMAScript5 버전으로 변환할 것으로 기대했는데 예상과 다르다. 바벨은 ECMAScript2015+를 ECMAScript5 버전으로 변환할 수 있는 것만 빌드한다. 그렇지 못한 것들은 “폴리필“이라고 부르는 코드 조각을 추가해서 해결한다.
가령 ECMAScript2015의 블록 스코핑은 ECMASCript5의 함수 스코핑으로 대체할 수 있다. 화살표 함수도 일반 함수로 대체할 수 있다. 이런 것들은 바벨이 변환해서 ECMAScript5 버전으로 결과물을 만든다.
한편 프라미스는 ECMAScript5 버전으로 대체할 수 없다. 다만 ECMAScript5 버전으로 구현할 수는 있다(참고: core-js promise).
env 프리셋은 폴리필을 지정할 수 있는 옵션을 제공한다.
babel.config.js :
module.exports = { presets: [ [ '@babel/preset-env', { useBuiltIns: 'usage', // 폴리필 사용 방식 지정 corejs: { // 폴리필 버전 지정 version: 2 } }, ], ], };
useBuiltIns는 어떤 방식으로 폴리필을 사용할지 설정하는 옵션이다. “usage”, “entry”, false 세 가지 값을 사용하는데 기본값이 false 이므로 폴리필이 동작하지 않았던 것이다. 반면 usage나 entry를 설정하면 폴리필 패키지 중 core-js를 모듈로 가져온다(이전에 사용하던 babel/polyfile은 바벨 7.4.0부터 사용하지 않음).
corejs 모듈의 버전도 명시하는데 기본값은 2다. 버전 3과 차이는 확실히 잘 모르겠다. 이럴 땐 그냥 기본값을 사용하는 편이다.
자세한 폴리필 옵션은 바벨 문서의 useBuiltIns와 corejs 섹션을 참고하자.
폴리필이 추가된 결과물을 확인해 보자.
> npx babel app.js
"use strict";
require("core-js/modules/es6.promise");
require("core-js/modules/es6.object.to-string");
new Promise();
core-js 패키지로부터 프라미스 모듈을 가져오는 임포트 구문이 상단에 추가되었다. 이제야 비로소 인터넷 익스플로러에서 안전하게 돌아가는 결과물을 만들었다.
6. 웹팩으로 통합
실무 환경에서는 바벨을 직접 사용하는 것보다는 웹팩으로 통합해서 사용하는 것이 일반적이다. 로더 형태로 제공하는데 babel-loader가 그것이다.
먼저 패키지를 설치하고,
> npm install -D babel-loader
웹팩 설정에 로더를 추가한다.
webpack.config.js :
module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, // node_modules 폴더 예외처리 loader: 'babel-loader', // 바벨 로더를 추가한다 }, ] }, }
.js 확장자로 끝나는 파일은 babel-loader가 처리하도록 설정했다. 사용하는 써드파티 라이브러리가 많을수록 바벨 로더가 느리게 동작할 수 있는데 node_modules 폴더를 로더가 처리하지 않도록 예외 처리했다(참고).
웹팩으로 build 하기 전에 폴리필 사용 설정을 했다면 core-js도 설치해야 한다.
웹팩은 바벨 로더가 만든 아래 코드를 만나면 core-js를 찾을 것이기 때문이다.
require("core-js/modules/es6.promise");
require("core-js/modules/es6.object.to-string");버전 2로 패키지를 추가하자.
> npm i core-js@2
*npm으로 특정 버전의 패키지를 설치하려면 '@버전명'을 붙여준다.
그리고 웹팩으로 빌드하면,
> npm run build
webpack
Hash: a30cff5fbf53027423a0
Version: webpack 4.41.2
Time: 718ms
Built at: 2019. 12. 16. 오전 8:52:05
Asset Size Chunks Chunk Names
main.js 59.7 KiB main [emitted] main
Entrypoint main = main.js
[./src/app.js] 166 bytes {main} [built]미리 등록해 놓은 NPM build 스크립트의 webpack 명령어가 동작한다. './src/app.js'의 엔트리 포인트가 바벨 로더에 의해 빌드되고 결과물이 dist/main.js로 옮겨졌다.
cat ./dist/main.js | grep 'var alert' -A 5
var alert = function alert(msg) {
return window.alert(msg);
};
new Promise();웹팩으로 번들링 되면서 변경된 부분 찾기가 어려울 수 있는데 grep으로 변경된 부분만 확인했다.
SUMMARY
# 바벨은 일관적인 방식으로 코딩하면서, 다양한 브라우저에서 돌아가는 애플리케이션을 만들기 위한 도구다.
# 바벨의 코어는 파싱과 출력만 담당하고 변환 작업은 플러그인이 처리한다.
# 여러 개의 플러그인들을 모아놓은 세트를 프리셋이라고 하는데 ECMAScript+ 환경은 env 프리셋을 사용한다.
# 바벨이 변환하지 못하는 코드는 폴리필이라 부르는 코드 조각을 불러와 결과물에 로딩해서 해결한다.
# babel-loader로 웹팩과 함께 사용하면 훨씬 단순하고 자동화된 프론트엔드 개발환경을 갖출 수 있다.
TODO.1
babel-loader를 구성해 보세요.
더보기npm에 바벨 코어 설치
$ npm i @babel/core
npm에 바벨로더 설치
$ npm i babel-loader
webpack.config.js :
module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: ['babel-loader'] } ] } }
TODO.2
IE11에서도 동작하는 자바스크립트로 변환할수 있게 바벨을 구성하세요.
더보기바벨의 env 프리셋 설치
$ npm i @babel/preset-env
core.js 설치
$ npm i core-js@2
babel.config.js :
module.exports = { presets: [ [ "@babel/preset-env", { targets: { ie: "11" }, useBuiltIns: "usage", corejs: { version: 2 } } ] ] }
※ async, await을 IE에서도 사용하려면 'regenerator-runtime' 라이브러리을 사용해야 한다.
$ npm install regenerator-runtime
이러한 현상이 일어나는 원인,
웹팩이 자바스크립트 파일에 대해서 바벨로더를 실행한다. 실행된 바벨은 'babel.config 파일'을 보고 변환 작업을 시작한다. 그때 변환 기준을 IE 11으로 지정하고 변환하려는 코드에서 async, await 코드가 있다면 해당 코드는 core.js로 변환할 수 없기 때문에 'regenerator-runtime' 라이브러리를 사용해야 한다.
반응형'Front-end > 개발환경' 카테고리의 다른 글
SASS(실습) - 웹팩(Webpack) | 김정환 (0) 2020.06.12 외부 패키지를 관리하는 방법 - NPM | 김정환 (0) 2020.06.10 바벨의 기본 개념 - 바벨(Babel) | 김정환 (0) 2020.06.09 자주 사용하는 플러그인 - 웹팩(Webpack) 기본편 | 김정환 (0) 2020.06.07 플러그인 - 웹팩(Webpack) 기본편 | 김정환 (0) 2020.06.07