바벨(Babel)

JaeungE·2021년 11월 15일
1

개발자의 친구들

목록 보기
3/5
post-thumbnail

Babel이 뭐지?

ES6 에서 등장한 const, let 부터 시작해서 ES8의 async/await 까지, 이제 JavaScript를 이용한 개발이라면 자연스럽게 사용하고 있는 키워드들이다.

하지만 골칫덩이 IE11 님 께서는 ES6 문법의 11% 정도밖에 지원하지 않는다. 사실상 ES6 이상의 편리한 키워드들을 사용할 수 없다는 얘기이다.

이 외에도 다양한 브라우저 환경에서 모두 최신 문법을 지원하지는 않기 때문에 크로스 브라우징 이슈가 생기게 되는데, 이를 해결하기 위해 상위 버전의 문법으로 개발한 코드를 하위 버전의 코드로 변환시켜주는 트랜스파일러(Transfiler). Babel이 탄생하게 되었다!



Babel의 동작 흐름

Babel은 세 과정을 통해 새로운 코드를 만들어낸다.

1. 파싱(Parsing)
2. 변환(Transformation)
3. 코드 생성(Code Generation)

파싱(Parsing)

Babel은 코드를 좀 더 편하게 변환하기 위해 기존의 코드를 추상 구문 트리(Abstract Syntax Tree)의 형태로 만들게 되는데, 이 과정을 파싱(Parsing) 이라고 한다.

const add = (a, b) => a + b;

console.log(add(5, 10));

예를 들면 위의 화살표 함수 코드가 파싱 단계를 거치면 아래처럼 바뀌게 된다.

코드가 어떻게 AST 형태로 바뀌는지 궁금하다면 AST explorer를 이용해보자!


변환(Transformation)

파싱(Parsing) 과정을 통해 소스코드가 추상 구문 트리의 형태로 바뀌었다면, 이제 코드가 어떻게 하위 문법으로 변환되어야 하는지 기술하는 단계가 바로 변환(Transformation) 단계이다.

이 단계에서 pluginpreset을 기준으로, 기존 코드의 내용이 브라우저의 환경에 따라 어떻게 바뀌어야 하는지를 알려주는 새로운 추상 구문 트리를 생성한다.

여기서 plugin은 특정 문법을 어떻게 변환해야 하는지에 대한 내용을 담고있는 것이고, preset은 단지 여러 plugin들을 하나로 합쳐놓은 것이다.


코드 생성(Code Generation)

변환(Transformation) 단계에서 생성된 새로운 추상 구문 트리를 바탕으로, 실제로 하위 문법으로 변환된 코드를 생성하는 단계이다.

파싱(Parsing) 단계에서 예제로 사용한 코드를 아래와 같이 변환시킬수 있다.

"use strict";

var add = function add(a, b) {
  return a + b;
};

console.log(add(5, 10));

그렇다면 실제로 Babel을 어떻게 사용하는지 알아보자!😉



Babel 기초 사용법!

일단 Babel을 사용하기 전에 변환할 소스코드 파일을 먼저 생성해보자.

src main.js

src add.js

기존 파일과 변환된 파일의 구분을 위해 /src/js 디렉터리 안에 원본 파일을 생성하였다.

이제 ES6 문법을 사용한 코드를 변환하기 위해 Babel을 설치하자.

npm init -y
npm install -D @babel/core @babel/cli

npm으로 설치가 가능하고, 변환에 필요한 기초 준비물은 @babel/core 패키지와 @babel/cli 패키지다.

@babel/core는 Babel 실행에 필수적인 패키지이고, @babel/cli 패키지는 Babel을 cli 환경에서 실행 가능하게 만들어주는 패키지이다.

정상적으로 설치되었다면 "devDependencies"에 다음과 같이 패키지가 등록되어있다.

이제 babel을 이용해 코드를 변환시킬 차례다. 다음 명령을 통해 babel을 실행해보자!

npx babel ./src/js -d ./dist/js

정상적으로 실행되었다면 Successfully compiled n files with Babel 과 같은 문구가 출력된다.

이제 변환된 결과물을 확인하러 가보자!

....오잉?! 소스코드의 상태가....!

dist main.js

dist add.js

그러나 아무일도 일어나지 않았다....

놀랍게도 main.js의 공백 라인이 사라진 것 외에는 아무런 차이가 없다.

사실 버그가 아니라 위에서 설명했던 변화(Transformation) 단계에서 쓰일 plugin이나 preset을 지정해주지 않았기 때문이다.


플러그인(Plugin)

원하는 코드를 얻고싶으면 그에 해당하는 plugin이 필요하다는 것을 알게되었다.

위의 코드에서는 block-scope 키워드인 const, Arrow-funtion, 모듈화를 위한 import/export 키워드를 사용했으니 그에 맞는 plugin 들을 설치해야 한다.

필요한 패키지의 이름은 다음과 같다.

@babel/plugin-transform-modules-commonjs
@babel/plugin-transform-block-scoping
@babel/plugin-transform-arrow-functions

패키지 이름도 알았으니 바로 설치해보자.

npm i -D @babel/plugin-transform-modules-commonjs @babel/plugin-transform-block-scoping @babel/plugin-transform-arrow-functions

더 다양한 plugin의 정보는 Plugins List - babel을 참고하도록 하자!


plugin의 설치가 완료되었으면, 이제 적용해볼 차례다. 실행 명령에 어떤 플러그인을 사용할지만 명시해주면 된다.

npx babel ./src/js -d ./dist/js --plugins=@babel/plugin-transform-modules-commonjs,@babel/plugin-transform-block-scoping,@babel/plugin-transform-arrow-functions

이제 결과를 확인하러 가보자!


dist main.js

dist add.js


무언가 조금 괴상해진 것 같지만, 정상적으로 동작하는 코드다.

이제 plugin을 통해 변환한 것 까지는 좋은데, 변환하려고 할 때 마다 cliplugin을 하나 하나 쓰기는 현실적으로 힘들다...

그래서 수고로움을 덜기 위해 Babel은 설정파일을 통해 사용할 pluginpreset을 지정해주는 것이 가능하다.


Babel 설정

Babel의 설정 파일은 상황에 따라 파일명 및 확장자가 달라질 수 있지만, 이번 예제에서는 babel.config.js로 설정하겠다.

프로젝트의 루트 디렉터리에 babel.config.js 파일을 생성하고 다음처럼 plugins 변수에 배열 리터럴로 사용할 plugin들을 나열하기만 하면 된다.

이후 다음 명령으로 간단하게 plugin을 포함한 변환이 가능하다.

npx babel ./src/js -d ./dist/js

이렇게 plugin을 사용해도 되지만, 자주 사용하는 pluginpreset으로 묶어서 사용하면 더 편해진다.


프리셋(preset)

preset은 여러 plugin들의 묶음이다. 위의 plugin들을 묶어서 나만의 preset을 만들어보자.

plugins 프로퍼티를 가진 객체를 반환하는 함수를 export 해주는 js파일을 생성하면 된다.

새로운 preset을 만들었으니 babel.config.js 파일도 다음과 같이 수정해주자.

plugin 설정과 같은 방식으로 presets 배열 변수를 export 하면 된다.

위처럼 커스텀 프리셋을 만드는 방법도 있지만, 모듈 크기에 민감하지 않다면 바벨에서 제공해주는 @babel/preset-env 프리셋을 install 해서 사용해도 좋다!


브라우저에서의 모듈 문제

여태까지 Babel의 기초적인 사용법을 알아보았고, 변환된 코드도 정상적으로 실행되었다.

하지만 브라우저에서도 똑같이 작동할까? 한 번 확인해보자.

main.html 파일을 만들고, Babel이 변환한 main.js 파일을 로드한다.

그리고 main.html을 실행하면 위와 같은 에러를 발생시키는데, main.js의 3번째 라인에서 참조 에러가 발생하고 있다. 확인해보자.

require() 메서드에서 에러가 발생중이다.

node.js 환경에서는 정상적으로 실행됐지만 브라우저에서는 에러가 발생하는 이유는, 브라우저 환경에서는 CommonJS 방식의 모듈 로드를 지원하지 않기 때문이다.

plugin@babel/plugin-transform-modules-commonjs을 제외해서 import/export 를 변환하지 않도록 하는 방법도 있지만, import/export는 ES6 문법이므로 Babel을 사용한 의미가 없어진다.

하지만 위의 문제점은 의존 모듈들을 하나의 파일로 번들링 해주는 Webpack을 이용하면 해결이 가능하다.





참고자료

What is Babel? - Babel
https://babeljs.io/docs/en/


Presets - Babel
https://babeljs.io/docs/en/presets


Usage Guide - Babel
https://babeljs.io/docs/en/usage


Configure Babel - Babel
https://babeljs.io/docs/en/configuration


Babel | PoiemaWeb
https://poiemaweb.com/es6-babel-webpack-1


바벨(Babel)의 동작 원리 및 흐름
https://moonformeli.tistory.com/28

0개의 댓글