babel
포스트
취소

babel

해당 포스트는 babel에 대해 정리한 포스트입니다.
주관적으로 해석한 내용이 들어가 있어서 잘못된 내용이 포함될 수 있습니다.
사용 경험이 거의 없어서 가벼운 내용만 담고 있습니다.

🪄 babel

공식 문서에서는 Babel is a JavaScript compiler.라고 합니다.
컴파일러보다는 트랜스파일러가 조금 더 적확한 표현인 것 같습니다. ( 물론 개인적인 의견입니다… 🥲 )
그러면 컴파일러와 트랜스파일러가 무엇일까요? 그 부분은 컴파일러/인터프리터/트랜스파일러를 참고해주세요!

그러면 트랜스파일러가 어떤 언어를 다른 언어로 바꿔주는 것이라고 이해했는데 이걸 왜 쓰는걸까요?

🐔🍗 babel을 사용하는 이유

우리가 JavaScript를 사용할 때는 일반적으로 최신 문법을 사용하는 것을 선호합니다.

1
const sum = (...args) => args.reduce((acc, curr) => acc + curr);

위처럼 대부분은 function으로 함수 표현식을 작성하는 것보단 화살표 함수로 함수 표현식을 작성하는 것을 더 선호할 것입니다.
( TMI:: 저는 화살표 함수를 굉장히 좋아합니다. )

아무튼 그래서 위처럼 코드를 구성했는데 어떤 브라우저에서는 화살표 함수를 지원하지 않을 수 있습니다.
그런 경우는 어떻게 해야할까요? 특정 브라우저를 위해서 작성했던 모든 화살표 함수를 function으로 바꿔야할까요?

뭐 그렇게 해결할 수 있겠지만 그러면 너무 힘들고 비효율적이죠.
근데 거기에다가 async/await, class같은 문법도 지원하지 않는다면 모두 바꿔주는 것은 엄청난 노가다가 될 것입니다.

이럴 때 사용하는 방법이 babel을 이용한 트랜스파일링입니다.

🕹️ babel을 사용하는 방법

사실 글은 적고 있지만 실제로 사용해 본 적은 거의 없습니다.
최근에는 create-react-app / create-next-app으로만 세팅을 해서 내부적으로 webpack으로 babel이 세팅되어 있어서 제가 건드릴 부분이 없었습니다.
( 사실 webpack에 대한 두려움이 있어서 건드릴 생각을 안합니다…🥲 )

그래도 간단하게 어떤 느낌인지 예시를 들어보겠습니다.

0️⃣ 설치

일단 먼저 npm으로 babel과 원하는 plugin을 설치해야합니다.

1
2
3
4
5
6
7
8
# "babel"을 "cli"로 실행시키기 위해 설치
npm i -D @babel/cli

# "arrow function"을 일반 "function"으로 트랜스파일링할 때 사용하는 플러그인
npm i -D @babel/plugin-transform-arrow-functions

# "JSX"를 "React" 문법으로 바꿔주는 플러그인 ( "React.createElement()"로 바꿔줌 )
npm i -D @babel/plugin-transform-react-jsx

1️⃣ 명령어

기본적으로 cli를 통해서 babel을 적용할 수 있습니다.

  • --plugins=<플러그인1[,플러그인2[,...]]>: 플러그인 적용
  • --out-file <경로>: 트랜스파일링의 결과물 위치 지정
1
2
3
4
5
# (1) "cli"에서만 결과가 출력됩니다. ( "ES6/index.js"는 트랜스파일링할 파일 )
npx babel --plugins @babel/plugin-transform-arrow-functions ES6/index.js

# (2) "ES6/index.js" 파일에 두 가지의 프러그인을 적용해서 "ES5/index.js"에 생성해줘 라는 의미를 갖는 명령어입니다.
npx babel --plugins=@babel/plugin-transform-arrow-functions,@babel/plugin-transform-react-jsx ES6/index.js --out-file ES5/index.js

(1)(2)를 보면서 느껴지는 게 코드가 너무 길고 외우기 힘듭니다.
package.jsonscripts에 작성한다고 쳐도 너무 길고 수정사항을 쉽게 반영하기가 힘든 문제가 있습니다.
이런 불편함을 해결하기 위해서는 babel.config.js를 이용하면 됩니다.

경로가 맞다고 치고 (2)을 실행한다면 아래와 같이 변환됩니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// ES6/index.js
const Commnet = () => <span>message</span>;

const Page = ({ children, isLoggedIn }) => {
  if (!isLoggedIn) return <span>You need to LogIn</span>;

  return (
    <>
      <span>Hello, Babel</span>
      {children}
    </>
  );
};

const App = () => {
  const obj = { x: 1, y: 2, z: 3 };

  return (
    <>
      {/* (3) */}
      <section>
        <Page isLoggedIn>
          <Commnet />
        </Page>
      </section>

      {/* (4) */}
      <section>
        <Page>{Commnet()}</Page>
      </section>

      {/* (5) */}
      <section>
        <Page {...obj} />
      </section>

      {/* (6) */}
      <section>
        <Page x={obj.x} y={obj.y} z={obj.z} />
      </section>
    </>
  );
};

// ES5/index.js
const Commnet = function () {
  return /*#__PURE__*/ React.createElement("span", null, "message");
};
const Page = function ({ children, isLoggedIn }) {
  if (!isLoggedIn)
    return /*#__PURE__*/ React.createElement("span", null, "You need to LogIn");
  return /*#__PURE__*/ React.createElement(
    React.Fragment,
    null,
    /*#__PURE__*/ React.createElement("span", null, "Hello, Babel"),
    children
  );
};
const App = function () {
  const obj = {
    x: 1,
    y: 2,
    z: 3,
  };
  return /*#__PURE__*/ React.createElement(
    React.Fragment,
    null,
    /* (3) */
    /*#__PURE__*/ React.createElement(
      "section",
      null,
      /*#__PURE__*/ React.createElement(
        Page,
        {
          isLoggedIn: true,
        },
        /*#__PURE__*/ React.createElement(Commnet, null)
      )
    ),
    /* (4) */
    /*#__PURE__*/ React.createElement(
      "section",
      null,
      /*#__PURE__*/ React.createElement(Page, null, Commnet())
    ),
    /* (5) */
    /*#__PURE__*/ React.createElement(
      "section",
      null,
      /*#__PURE__*/ React.createElement(Page, obj)
    ),
    /* (6) */
    /*#__PURE__*/ React.createElement(
      "section",
      null,
      /*#__PURE__*/ React.createElement(Page, {
        x: obj.x,
        y: obj.y,
        z: obj.z,
      })
    )
  );
};
  • (3), (4)에 대한 차이가 궁금하다면 지연평가를 읽어보시는 것을 추천드립니다.

  • /*#__PURE__*/는 그냥 주석이 아닌 Tree-Shaking이랑 연관있는 어노테이션입니다.
    ( 해당 함수가 사이드이펙트가 없는 순수 함수라는 것을 증명하는 어노테이션입니다. )

2️⃣ babel.config.js

babel에 대한 기본 세팅을 작성하는 파일입니다.
최상위에 babel.config.js라는 파일만 작성해두면 babel을 실행할 때 자동으로 파일을 읽어서 옵션들을 적용해줍니다.

1
2
3
4
5
6
7
8
// 아래처럼 사용하면 "(2)"에서 적용한 플러그인을 똑같이 적용할 수 있습니다.
const presets = [];
const plugins = [
  "@babel/plugin-transform-arrow-functions",
  "@babel/plugin-transform-react-jsx",
];

module.exports = { presets, plugins };

이제는 아래와 같은 명령어를 수행하면 플러그인들이 자동으로 적용됩니다.

1
npx babel ES6/index.jsx --out-file ES5/index.jsx 
  • presets: 자주 쓰는 유용한 플러그인들을 포함하고 있는 플러그인 ( 스타트팩같은 느낌이죠 )
    ( babel-preset-react을 확인해보시면 어떤 플러그인들이 있고 어떻게 적용하는지 알려줍니다. )

📇 polyfill

구형 브라우저에서 지원하지 않는 기능을 지원해주기 위해서 자겨오는 코드 뭉치입니다.
예를 들면 Promise같은 경우 babel의 트랜스파일링으로 변화시켜줄 수 없습니다.
따라서 Promise의 코드 뭉치를 런타임에 추가시켜줌으로써 문제 없이 동작할 수 있도록 도와주는 것을 의미합니다.

📮 레퍼런스

  1. babel - cli
  2. youtube(옥탑방개발자) - React 라이브러리 개발을 위한 - Babel 이해하기

  3. 1-blue - 지연평가
  4. 1-blue - Tree-Shaking
이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.