Posts [프론트엔드 개발환경의 이해와 실습] 바벨 사용법과 웹팩 통합
Post
Cancel

[프론트엔드 개발환경의 이해와 실습] 바벨 사용법과 웹팩 통합

바벨 사용법과 웹팩 통합

프리셋 사용하기

바벨은 목적에 따라 몇 가지 프리셋을 제공한다.

  • preset-env
  • preset-flow
  • preset-react
  • preset-typescript

preset-envECMAScript2015+를 변환할 때 사용한다. 바벨 7 이전 버전에는 연도별로 각 프리셋을 제공했지만(babel-reset-es2015, babel-reset-es2016, babel-reset-es2017, babel-reset-latest) 지금은 env 하나로 합쳐졌다.(굉장히 깔끔해졌다)

preset-flow, preset-react, preset-typescript는 flow, 리액트, 타입스크립트를 변환하기 위한 프리셋이다.

IE 지원을 위해 env 프리셋을 사용해 보자. 먼저 패키지를 다운로드한다.

1
npm install -D @babel/preset-env

설치한 바벨 설정을 조금만 더 바꿔본다.

  • babel.config.js:
1
2
3
module.exports = {
  presets: ["@babel/preset-env"],
}

그리고 빌드하면,

1
2
3
4
5
6
7
npx babel app.js

"use strict";

var alert = function alert(msg) {
  return window.alert(msg);
};

직접 만든 커스텀 프리셋 my-babel-preset.js와 같은 결과를 출력한다.

env 프리셋 설정과 폴리필

과거에 제공했던 연도별 프리셋을 사용해 본 경험이 있다면 까다롭고 헷갈리는 설정 때문에 애를 먹었을지도 모르겠다. 그에 비해 env 프리셋은 무척 단순하고 직관적인 사용법을 제공한다.

타겟 브라우져

우리 코드가 크롬 최신 버전(2019년 12월 기준)만 지원하다고 하자. 그렇다면 인터넷 익스플로러를 위한 코드 변환은 불필요하다. target 옵션에 브라우져 버전명만 지정하면 env 프리셋은 이에 맞는 플러그인들을 찾아 최적의 코드를 출력해 낸다.

참고로 javascript문법별 브라우저 지원 현황을 알기 위해 can i use라는 사이트를 활용하자.

  • babel.config.js
1
2
3
4
5
6
7
8
9
10
11
12
module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        targets: {
          chrome: "79", // 크롬 79까지 지원하는 코드를 만든다
        },
      },
    ],
  ],
}
1
2
3
4
5
$ npx babel app.js

"use strict";

const alert = msg => window.alert(msg);

크롬은 블록 스코핑과 화살표 함수를 지원하기 때문에 코드를 변환하지 않고 이러한 결과물을 만들었다. 만약 IE도 지원해야 한다면 바벨 설정에 브라우져 정보만 하나 더 추가하면 된다.

  • babel.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        targets: {
          chrome: "79",
          ie: "11", // ie 11까지 지원하는 코드를 만든다
        },
      },
    ],
  ],
}

IEconst 키워드와 에로우 함수 를 지원하지 않기에 아래 이미지와 같이 변환된 것을 확인할 수 있다.

스크린샷 2022-03-23 오후 9 36 35

폴리필

이번엔 변환과 조금 다른 플리필에 대해 알아보자.

ECMASCript2015Promise 객체를 사용하는 코드다.

  • app.js
1
new Promise()

바벨로 처리하면 어떤 결과가 나올까?

1
npx babel app.js
1
2
3
"use strict";

new Promise();

env 프리셋으로 변환을 시도했지만 Promise 그대로 변함이 없다. target에 ie 11을 설정하고 빌드한 것인데 IE는 여전히 Promise를 해석하지 못하고 에러를 던진다.

브라우져는 현재 스코프부터 시작해 전역까지 Promise 라는 이름을 찾으려고 시도할 것이다. 그러나 스코프 어디에도 Promise란 이름이 없기 때문에 레퍼런스 에러를 발생하고 프로그램이 죽은 것이다.

플러그인이 PromiseECMAScript5 버전으로 변환할 것으로 기대했는데 예상과 다르다. 바벨은 ECMAScript2015+ECMAScript5 버전으로 변환할 수 있는 것만 빌드한다. 그렇지 못한 것들은 “폴리필”이라고 부르는 코드조각을 추가해서 해결한다.

가령 ECMAScript2015의 블록 스코핑은 ECMASCript5의 함수 스코핑으로 대체할 수 있다. 화살표 함수도 일반 함수로 대체할 수 있다. 이런 것들은 바벨이 변환해서 ECMAScript5 버전으로 결과물을 만든다.

한편 프라미스는 ECMAScript5 버전으로 대체할 수 없다. 다만 ECMAScript5 버전으로 구현할 수는 있다.(참고: core-js promise)

env 프리셋은 폴리필을 지정할 수 있는 옵션을 제공한다.

  • babel.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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과 차이는 확실히 잘 모르겠지만 이럴 땐 그냥 기본값을 사용하면 된다.

자세한 폴리필 옵션은 바벨 문서의 useBuiltInscorejs 섹션을 참고하자.

폴리필이 추가된 결과물을 확인해 보자.

1
2
3
4
5
6
7
8
$ npx babel src/app.js

"use strict";

require("core-js/modules/es6.promise");
require("core-js/modules/es6.object.to-string");

new Promise();

core-js 패키지로부터 promise 모듈을 가져오는 임포트 구문이 상단에 추가되었다. 이제야 비로소 IE에서 안전하게 돌아가는 결과물을 만들 수 있게 되었다.

웹팩으로 통합

실무 환경에서는 바벨을 직접 터미널로 입력해서 사용하는 것보다는 웹팩으로 통합해서 사용하는 것이 일반적이다. 로더 형태로 제공하는데 babel-loader가 그것이다.

먼저 패키지를 설치하고,

1
npm install -D babel-loader

웹팩 설정에 로더를 추가한다.

  • webpack.config.js
1
2
3
4
5
6
7
8
9
10
11
module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: "babel-loader", // 바벨 로더를 추가한다
      },
    ],
  },
}

.js 확장자로 끝나는 파일은 babel-loader가 처리하도록 설정했다. ,사용하는 써드파티 라이브라리가 많을수록 바벨 로더가 느리게 동작할 수 있는데 node_modules 폴더를 로더가 처리하지 않도록 예외 처리했다.(참고)

폴리필 사용 설정을 했다면 core-js도 설치해야한다. 웹팩은 바벨 로더가 만든 아래 코드를 만나면 core-js를 찾을 것이기 때문이다.

1
2
require("core-js/modules/es6.promise")
require("core-js/modules/es6.object.to-string")

버전 2로 패키지를 추가하자.

1
npm i core-js@2

그리고 웹팩으로 빌드하면,

1
2
3
4
5
6
7
8
9
10
11
12
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로 옮겨졌다.

1
2
3
4
5
6
7
cat ./dist/main.js | grep 'var alert' -A 5

var alert = function alert(msg) {
  return window.alert(msg);
};

new Promise();

웹팩으로 번들링되면서 변경된 부분 찾기가 어려울수 있는데 grep으로 변경되 부분만 확인할 수 있다.

정리

바벨은 일관적인 방식으로 코딩하면서, 다양한 브라우져에서 돌아가는 어플리케이션을 만들기 위한 도구다.

바벨의 코어는 파싱과 출력만 담당하고 변환 작업은 플러그인이 처리한다.

여러 개의 플러그인들을 모아놓은 세트를 프리셋이라고 하는데 ECMAScript+ 환경은 env 프리셋을 사용한다.

바벨이 변환하지 못하는 코드는 폴리필이라 부르는 코드조각을 불러와 결과물에 로딩해서 해결한다.

babel-loader 로 웹팩과 함께 사용하면 훨씬 단순하고 자동화된 프론트엔드 개발환경을 갖출 수 있다.

출처

This post is licensed under CC BY 4.0 by the author.

[프론트엔드 개발환경의 이해와 실습] 자주 사용하는 웹팩 플러그인

[프론트엔드 개발환경의 이해와 실습] 바벨의 기본 개념