안녕하세요 바벨에 대한 포스팅입니다!
바벨(Babel)은 최신 또는 구식 브라우저환경에서 ECMAScript 2015+ 코드를 호환 가능한 JavaScript 버전으로 변환하는 데 주로 사용되는 자바스크립트 컴파일러입니다.
또, 입력과 출력 모두 자바스크립트 코드인 컴파일러입니다.
즉, 바벨이 최신 자바스크립트 코드를 지원하지 않는 explorer같은 브라우저에서 최신 자바스크립트 코드를 구버전 자바스크립트 코드로 호환 가능하도록 변환해줍니다. 이 기능이 바벨의 주된 기능이지만, 현재는 바벨을 이용해서 JSX문법(리액트), 타입스크립트 같은 정적 타입언어, 코드압축, 제안 단계(proposal : 정식문법아닌 것) 문법 등을 사용할 수 있게 해줍니다.
다음은 바벨을 실행하는 네가지 방법입니다.
- @babel/cli로 실행하기
바벨을 이용하는 첫 번째 방법입니다.
프로젝트를 생성해보겠습니다.
npm init -y
기본 설정을 사용하는 옵션 -y를 적용해, 초기화 합니다.
바벨 관련 패키지들을 설치해보겠습니다.
npm i @babel/core
@babel/cli
@babel/plugin-transform-arrow-functions
@babel/plugin-transform-template-literals
@babel/preset-react
~보기쉽게 줄 단위로 띄어썼습니다.~
@babel/core은 바벨을 이용하기 위한 필수 패키지입니다.
@babel/cli는 명령줄에서 바벨을 사용하기위해 설치합니다.
@babel/plugin 관련해서 arrow-functions, template-literals 플러그인을 설치했습니다. plugin들을 간편하게 묶음으로 제공하는 presets를 설치해도 됩니다.
@babel/preset-react로 JSX파일을 컴파일 하기위해 리액트관련 preset을 설치했습니다.
먼저 ECMA2015이상의 간단한 모던 자바스크립트 코드를 작성해볼텐데, 위에서 설치한 패키지에서 보이는 것 처럼 arrow-functions, template-literals, react의 JSX코드가 바벨로 컴파일 되는 것을 확인해보겠습니다.
const element = <div>babel test</div>
const text = `element type is ${element.type}`
const add = (a,b) => a+b;
첫 줄부터 JSX코드, 템플릿리터럴, 화살표함수입니다.
CLI환경에서 실행해보겠습니다 npx babel로 실행하고 --preset, --plugin 옵션을 이용해 컴파일시 필요한 플러그인과 프리셋을 전달해야 합니다.
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");
const text = "element type is ".concat(element.type);
const add = function (a, b) {
return a + b;
};
JSX코드는 React.createElement함수로, 템플릿리터럴은 concat함수로, 화살표 함수는 일반 함수로 변환됐습니다.
JSX코드, 템플릿리터럴, 화살표함수가 모두 정상적으로 레거시 자바스크립트 코드로 컴파일 되도록, 컴파일시에 필요한 plugin과 preset을 옵션을 통해 작성하지 않으면 (Unexpected token Error)가 발생합니다.
매 번 명령줄에 긴 옵션을 넣는건 불편하기 때문에 당연히 설정파일을 이용할 수 있습니다.
바벨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};
이제 "npx babel 실행파일" 명령어만 입력하면 컴파일이 실행됩니다.
npx babel src/code.js --out-dir dist
npx babel src/code.js --out-file dist.js
--out-dir 과 --out-file 옵션을 이용해 각각 폴더의 하위에 동일한 파일이름으로 파일을 출력하거나, 파일 단위로 출력 할 수 있습니다.
바벨을 이용하는 두 번째 방법입니다.
webpack은 정적파일들을 하나로 묶어주는 역할을 하는 모듈 번들러입니다.
먼저 webpack관련 패키지를 설치합니다.
npm i webpack webpack-cli babel-loader
이어서 설정파일인 webpack.config.js를 생성하고 작성합니다.
// webpack.config.js
const path = require('path')
module.exports = {
entry : './src/code.js',
output : {
path : path.resolve(__dirname, 'dist'),
filename : 'code.bundle.js'
},
module : {
rules : [{test : /\.js$/, use: 'babel-loader'}],
},
optimization : {minimizer : []}
}
가장 윗줄에서 path는 nodejs의 핵심모듈이며, 경로 관련해서 다양한 기능을 제공합니다.
모듈로 내보내는 객체를 보겠습니다.
entry는 번들링할 모듈의 진입점 되는 파일입니다.
output은 번들링 후 출력할 파일의 경로와 파일이름을 저장합니다.
module.rules에는 배열형태로 되어있는데, 이 배열의 객체 요소의 test에는 정규표현식으로 대상이 되는 파일의 형식을, use에는 그 대상파일에 적용할 loader를 작성합니다. 여기에서는 .js로 끝나는 자바스크립트 파일에 대해 babel-loader가 사용되도록 했으며, babel-loader는 바벨의 설정파일을 사용하므로, 아까 만들었던 babel.config.js파일의 내용을 설정값으로 이용합니다.
npx webpack
우리는 설정파일에 설정을 모두 작성했으므로, 간단하게 npx webpack을 입력하면 번들링이 수행됩니다.
바벨을 이용하는 세 번째 방법입니다.
작성했던 설정파일들을 보면 자바스크립트파일로 작성했었습니다.
동적으로 설정파일을 다룰 수 있다는 말이기도 합니다.
이 번에는 @babel/core를 직접 이용해보겠습니다.
// runBabel.js
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 plugins = [
'@babel/plugin-transform-template-literals',
'@babel/plugin-transform-arrow-functions'
];
const {code} = babel.transformSync(source,{
filename,
presets,
plugins,
configFile: false
});
console.log(code)
가장 먼저 @babel/core모듈을 가져옵니다. 파일을 읽기위해 fs모듈도 가져옵니다.
source변수에 fs.readFileSync 메서드를 이용해 파일을 읽습니다.
presets와 plugins에 설정내용을 담고, transformSync메서드를 호출해 바벨을 실행합니다.
configFile속성은 babel.config.js설정파일을 이용할지 여부를 작성합니다. 여기에서는 코드에 이미 내용이 포함되어있으므로 false로 작성합니다.
마지막줄은 code속성을 콘솔에 출력하는 것인데, 파일로 따로 출력하고싶다면 fs모듈을 이용하면 됩니다.
node runBabel.js
명령어를 입력하면 콘솔에 출력되는 것을 확인할 수 있습니다.
이 방식은 하나의 코드에대해 다른 설정을 적용할 수 도 있어 자유도가 높습니다.
바벨은 컴파일시 세 단계를 거칩니다.
- 파싱(parse) 단계 : 입력된 코드로부터 AST(abstract syntax tree)를 생성합니다.
AST는 코드의 구문(syntax)가 분석된 결과를 담고 있는 구조체입니다. 코드가 같다면 AST도 같습니다.
따라서, AST를 생성해놓고 재사용할 수 있습니다.
구체적으로 사용하는 방법은 다음에 포스팅에서 알아보겠지만,
아까 작성했던 runBabel.js에서 babel.transformSync함수를 호출해서 code를 객체비구조화로 할당해 콘솔에 출력했던 것과 달리
babel.transformSync함수의 ast속성을 객체비구조화로 할당하고, 재사용 하는 것입니다.
이 ast를 이용해 다른 옵션을 주고 babel.transformFromAstSync함수를 실행하면 코드를 각각 다르게 컴파일 할 수있습니다.
다음에 포스팅에서 자세하게 알아보겠습니다!!