Skip to main content Link Menu Expand (external link) Document Search Copy Copied

바벨을 실행하는 여러 가지 방법

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

@babel/register를 이용하면 Node.js에서 require코드가 실행될 때 동적으로 바벨이 실행되게 할 수 있습니다. 하지만 리액트를 @babel/register와 함께 사용하는 경우는 많지 않으므로 @babel/register를 제외한 나머지 세 방식을 설명할 예정입니다.

먼저 필요한 패키지를 설치합니다. npm install @babel/core @babel/cli @babel/plugin-transform-arrow-functions @babel/plugin-transform-template-literals @babel/preset-react

바벨을 실행하기 위해서는 @babel/core를 필수로 설치해야 합니다. 두 개의 플러그인과 프리셋 하나를 추가로 설치했습니다.

code.js

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

1. @babel/cli로 실행하기

다음 명령어를 실행해 봅니다. npx babel src/code.js --presets=@babel/preset-react --plugins=@babel/plugin-transform-template-literals, @babel/plugin-transform-arrow-functions

바벨 실행 후 콘솔에 출력되는 내용

const element = React.createElement("div", null, "babel test");
const text = "element type is ".concat(element.type);
const add = function (a, b) {
    return a + b;
};
  1. jsx 문법은 createElement 함수 호출로 변환됩니다.
  2. 템플릿 리터럴은 문자열의 concat 메소드 호출로 변환됩니다.
  3. 화살표 함수는 일반 함수로 변환됩니다.

@babel/cli로 거의 모든 설정값을 표현할 수 있지만, 설정할 내용이 많거나 실행 환경에 따라 설정값이 다른 경우에는 설정 파일을 따로 만드는게 좋습니다. 바벨6까지는 .babelrc파일로 설정값을 관리했지만, 바벨7부터는 babel.config.js파일로 관리하는 것을 추천합니다. 두 파일의 차이점은 다음 게시글에서 설명합니다.

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 명령어로 입력했던 설정과 같은 내용입니다. js파일이기 때문에 동적으로 설정값을 만들 수 있습니다. 참고로 바벨6에서는 .babelrc.js파일로 위 코드처럼 작성할 수 있습니다. 이제 명령어는 아래와 같이 간소화됩니다. npx babel src/code.js

컴파일된 결과를 파일로 저장하고 싶다면 다음과 같이 입력해봅니다.

npx babel src/code.js --out-file dist.js // 파일 단위로 처리
npx babel src --out-dir dist // 폴더 단위로 처리

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

웹팩을 이용하기 위해 추가로 패키지를 설치해 봅니다. npm install webpack webpack-cli babel-loader

webpack.config.js

const path = require('path');
module.exports = {
    entry: './src/code.js', // 웹팩으로 번들링할 파일을 지정합니다.
    output: { // 번들링된 결과를 dist/code.bundle.js로 저장합니다.
        path: path.resolve(__dirname, 'dist'),
        filename: 'code.bundle.js',
    },
    module: { // js파일을 bebel-loader가 처리하도록 설정합니다.
        rules: [{ test: /\.js$/, use: 'babel-loader' }], // babel-loader는 바벨의 설정 파일을 이용하므로 이전에 만들어 놓은 babel.config.js 파일의 내용이 설정값으로 사용됩니다.
    },
    optimization: { minimizer: [] }, // 웹팩은 기본적으로 js파일을 압축합니다. 그렇지만 바벨이 제대로 실행됐는지 확인하기 위해 압축 기능을 잠시 끄기로 합니다.
};

npx webpack // 웹팩 실행

code.bundle.js

// ... -> 파일의 앞부분에는 웹팩의 런타임 코드가 추가됩니다.
const element = React.createElement("div", null, "babel test");
const text = "element type is ".concat(element.type);
const add = function (a, b) {
    return a + b;
};
// ... -> 파일의 뒷부분에서는 바벨이 생성한 코드를 확인할 수 있습니다.

3. @babel/core를 직접 실행하기

이전에 살펴봤던 @babel/cli, babel-loader는 모두 @babel/core를 이용해서 바벨을 실행합니다. 이번에는 직접 @babel/core를 사용하는 코드를 작성해서 바벨을 실행해 봅니다.

runBabel.js

const babel = require('@babel/cli'); // @babel/cli 모듈을 가져옵니다.
const fs = require('fs');
const filename = './src/code.js';
const source = fs.readFileSync(filename, 'utf8'); // 컴파일할 파일의 내용을 가져옵니다.
const presets = ['@babel/preset-react']; // 바벨의 플러그인과 프리셋을 설정합니다.
const plugins = [
    '@babel/plugin-transform-template-literals',
    '@babel/plugin-transform-arrow-functions',
]
const { code } = babel.transformSync(source, { // transformSync함수를 호출해서 바벨을 실행합니다.
    filename,
    presets,
    plugins,
    configFile: false, // babel.config.js 설정 파일을 사용하지 않도록 합니다.
});
console.log(code); // 콘솔에 출력, 파일로 저장하기 원한다면 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/core를 사용하면 바벨을 좀 더 효율적으로 실행할 수 있습니다. 바벨은 컴파일 시 다음 세 단계를 거칩니다.

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

AST는 코드의 구문이 분석된 결과를 담고 있는 구조체입니다. 코드가 같다면 AST도 같기 때문에 같은 코드에 대해서 하나의 AST를 만들어 놓고 재사용할 수 있습니다.

runBabel2.js

const babel = require('@babel/cli'); // @babel/cli 모듈을 가져옵니다.
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, {
    filename,
    ast: true,
    code: false, // 코드는 생성하지 않고 AST만 생성합니다. 프리셋은 두 가지 설정 모두 같으므로 AST를 만들 때 해당 프리셋을 미리 적용합니다.
    presets,
    configFile: false,
});
const { code: code1 } = babel.transformFromAstSync(ast, source, {
    filename,
    plugins: ['@babel/plugin-transform-template-literals'], // 만들어진 AST로부터 첫 번째 설정의 플러그인이 반영된 코드를 생성합니다.
    configFile: false,
});
const { code: code2 } = babel.transformFromAstSync(ast, source, { // 두 번째 설정이 적용된 코드를 생성합니다.
    filename,
    plugins: ['@babel/plugin-transform-arrow-functions'],
    configFile: false,
});

설정이 많아질수록 이 방식의 효율은 높아집니다.