본문 바로가기

React/실험실

[React] Babel

0. Babel? 

Babel은 입력과 출력이 모두 자바스크립트 코드인 컴파일러이다. 

일반적인 컴파일러는 고수준의 언어를 저수준의 언어로 변환하는 것과 다른 점이 있다. 

초기엔 ES6 코드만 ES5 코드로 변환해주지만, 현재는 리액트의 JSX, 타입 스크립트와 같은 정적 타입 언어, 

코드 압축 등의 단계에 있는 문법도 변환해준다. 

 

Babel을 실행하는 방법은 4가지가 있다. 

  • @babel/cli로 실행하기
  • 웹팩에서 babel-loader로 실행하기
  • @babel/core를 직접 실행하기 
  • @babel/register로 실행하기 

 

이번엔 @babel/register를 제외하고 적용하는 방법을 알아본다. 

 

1. 준비단계 

패키지 설치

npm install @babel/core @babel/cli @babel/plugin-transform-arrow-functions @babel/plugin-transform-template-literals @babel/preset-react

Babel을 실행하기 위해선 @babel/core 패키지를 필수로 설치해야 한다. 

그 외 두 개의 플러그인과 프리셋 하나를 설치했다. 

 

컴파일 코드 작성 

const element = <div>babel test</div>;                  --- 1
const text = `element type is ${element.type}`;         --- 2
const add = (a, b) => a + b;                            --- 3

1 : 리액트 프리셋을 이용해 JSX 문법을 변환할 예정이다. 

2 : 템플릿 리터럴 플러그인을 이용해서 템플릿 리터럴 코드를 변환할 예정이다. 

3 : 화살표 함수 플러그인을 이용해서 화살표 함수를 변환할 예정이다. 

 

2. @babel/cli로 실행하기 

npx babel src/code.js --presets=@babel/preset-react --plugins=@babel/plugin-transform-template-literals,@babel/plugin-transform-arrow-functions

바벨을 실행하면 콘솔에 아래와 같은 내용이 출력된다. 

 

const element = /*#__PURE__*/React.createElement("div", null, "babel test"); -- 1
const text = "element type is ".concat(element.type);                        -- 2

const add = function (a, b) {                                                -- 3
  return a + b;
};

1 : JSX 문법이 createElement 함수 호출로 변환되었다. 

2 : 템플릿 리터럴은 문자열의 concat 메서드 호출로 변환된다. 

3 : 화살표 함수는 일반 함수로 변환된다. 

 

@babel/cli로 보는 것과 같이 거의 모든 설정값을 적용할 수 있지만, 설정할 내용이 많을 경우 또는 실행 환경에 따라 

설정값이 다른 경우 설정 파일로 만들어서 관리하는 것이 좋다. 

 

babel.config.js

const presets = ["@babel/preset-react"];
const plugins = [
  "@babel/plugin-transform-template-literals",
  "@babel/plugin-transform-arrow-functions",
];

module.exports = { presets, plugins };

앞서 @babel/cli 명령어로 입력했던 설정과 같은 내용이다.  자바스크립트 파일이기 때문에 동적으로 설정값을 만들 수 있다.

 

이제 간소화된 명령어로 실행할 수 있다. 

npx babel src/code.js

 

컴파일된 결과를 파일로 저장하고 싶다면 아래와 같이 입력할 수 있다.

npx babel src/code.js --out-file dist.js
npx babel src --out-dir dist

첫 번째 명령어는 파일 단위로 처리하고, 두 번째 명령어는 폴더 단위로 처리한다. 

 

3. 웹팩의 babel-loader로 실행하기 

웹팩을 이용하기 때문에 추가로 웹팩 패키지도 함께 설치해야 한다. 

npm install webpack webpack-cli babel-loader
const path = require("path");

module.exports = {
  entry: "./src/code.js",                             --- 1
  output: {                                           --- 2
    path: path.resolve(__dirname, "dist"),
    filename: "code.bundle.js",
  },

  module: { 
    rules: [{ test: /\.js$/, use: "babel-loader" }],  --- 3
  }, 

  optimization: { minimizer: [] },                    
};

1 : 웹팩의 번들링(bundling)할 파일을 지정한다. 

2 : 번들링 된 결과를 dist/code.bundle.js 파일로 저장한다. 

3 : 자바스크립트 파일을 babel-loader가 처리하도록 설정한다. 

    babel-loader는 바벨의 설정 파일을 이용하므로 이전에 만들어 놓은 babel.config.js 파일의 내용이 설정값으로

    사용된다. 

 

※ 번들링? 

기본적으로 여러 개로 흩어져 있는 파일들을 압축, 난독화 등을 하여 하나의 파일로 모아주는 역할

 

/******/ (() => { // webpackBootstrap
var __webpack_exports__ = {};
const element = /*#__PURE__*/React.createElement("div", null, "babel test");
const text = "element type is ".concat(element.type);

const add = function (a, b) {
  return a + b;
};
/******/ })()
;

code.js에 작성한 부분 외에 앞부분에는 웹팩의 런타임 코드가 추가되며, 뒷부분에는 바벨이 생성한 코드가 나온다.

 

4. @babel/core를 직접 이용하기 

@babe/cli와 babel-loader는 모두 @babel/core를 사용해서 바벨을 실행한다. 

이번에는 @babel/core를 직접 사용하는 코드를 작성해서 실행해보자 

runBabel.js

const babel = require("@babel/core");              --- 1
const fs = require("fs");

const filename = "./src/code.js";
const source = fs.readFileSync(filename, "utf8");  --- 2
const presets = ["@babel/preset-react"];           --- 3
const plugins = [
  "@babel/plugin-transform-template-literals",
  "@babel/plugin-transform-arrow-functions",
];
const { code } = babel.transformSync(source, {     --- 4
  filename,
  presets,
  plugins,
  configFile: false,                               --- 5
});
console.log(code);                                 --- 6

1 : @babel/core 모듈을 가져온다. 

2 : 컴파일할 내용을 가져온다. 

3 : Babel 플러그인과 프리셋을 설정한다. 

4 : transformSync 함수를 호출해서 Babel을 실행한다. 

5 : babel.config.js 설정 파일을 사용하지 않도록 한다. 

6 : 변환된 코드를 콘솔에 출력한다. 파일로 저장하길 원한다면 fs 모듈을 이용하면 된다. 

 

node runBabel.js

 

@babel/core 모듈을 직접 사용하는 방식은 자유도가 다른 방식에 비해서 높다는 장점이 있다. 

// 설정 1
const presets = ['@babel/preset-react'];
const plugins = ['@babel/plugin-transform-template-literals'];

// 설정 2
const presets = ['@babel/preset-react'];
const plugins = ['@babel/plugin-transform-arrow-functions'];

같은 코드에 두 가지 설정을 적용한다고 생각해보다 

@babel/cli 또는 babel-loader를 이용한다면 Babel을 두 번 실행해야 한다. @babel/core를 사용하면 Babel을

효율적으로 실행할 수 있다. 

 

Babel은 컴파일 시 세 단계를 거친다. 

  • 파싱 단계 : 입력된 코드로부터 AST(abstract syntax tree)를 생성한다. 
  • 변환 단계 : AST를 원하는 형태로 변환한다. 
  • 생성 단계 : AST를 코드로 출력한다. 

AST코드의 구문(syntax)이 분석된 결과를 담고 있는 구조체이다. 

코드가 같다면 AST도 같기 때문에 같은 코드에 대해서 하나의 AST를 만들어 놓고 재사용할 수 있다. 

 

const babel = require("@babel/core");
const fs = require("fs");

const filename = "./src/code.js";
const source = fs.readFileSync(filename, "utf8");
const presets = ["@babel/preset-react"];

const { ast } = babel.transformSync(source, {                    --- 1
  filename,
  ast: true,
  code: false,
  presets,
  configFile: false,
});

const { code: code1 } = babel.transformFromAstSync(ast, source, { --- 2
  filename,
  plugins: ["@babel/plugin-transform-template-literals"],
  configFile: false,
});
const { code: code2 } = babel.transformFromAstSync(ast, source, { --- 3
  filename,
  plugins: ["@babel/plugin-transform-arrow-functions"],
  configFile: false,
});
console.log("code1 : ", code1);
console.log("code2 : ", code2);

1 : 코드는 생성하지 않고 AST만 생성한다. 하지만 프리셋은 두 설정 모두 동일하므로 AST를 만들 때 해당 프리셋을

    미리 적용한다. 

2 : 만들어진 AST로부터 첫 번째 설정의 플러그인이 반영된 코드를 생성한다. 

3 : 마찬가지로 두 번째 설정이 적용된 코드를 생성한다. 

 

설정의 개수가 많아질수록 효율이 높아진다. 

 

깃허브

https://github.com/SeoJaeWan/test-bebel

 

GitHub - SeoJaeWan/test-bebel

Contribute to SeoJaeWan/test-bebel development by creating an account on GitHub.

github.com

 

반응형

'React > 실험실' 카테고리의 다른 글

[React] Babel과 Polyfill  (0) 2022.04.06
[React] Babel - 깊은 설정  (0) 2022.04.05
[React] Webpack 환경에서 환경변수 사용  (1) 2022.03.29
[React] Code Splitting  (1) 2022.03.24
[React] html-webpack-plugin?  (1) 2022.03.23