많은 사람이 처음 리액트 개발을 할 때 Facebook(현 Meta)이 제공하는 create-react-app (이하 CRA)을 사용하고 있습니다.
CRA는 번거로울 수 있는 초기 세팅을 모두 해 주기에 분명 편리하지만 리액트 앱을 자기 입맛대로 수정하려는 개발자에게는 일종의 족쇄이며 앱이 어떻게 빌드되는지 이해하고자 하는 주니어 개발자에게도 CRA를 사용하지 않는 리액트 앱의 빌드는 한 번쯤 시도해 볼 만한 일입니다.
그렇다면 CRA가 무엇을 잡아주기에 우리가 편하게 리액트 앱을 개발할 수 있는 걸까요? 그 질문에 대한 답을 내 보도록 합시다.
이젠 더 이상
yarn eject
를 두려워하지 말자!
Babel 은 자바스크립트 컴파일러입니다. 하지만 이 컴파일러는 입출력이 모두 자바스크립트 코드란 점에서 조금 특이한데 (트랜스파일러라고도 합니다), ES6+ 기반의 자바스크립트 코드를 ES5 스펙에 맞도록 컴파일할 뿐 아니라 현재는 리액트의 JSX 문법, 코드 압축, TypeScript 등 정말 많은 일을 합니다.
아래와 같은 ES6+ 스타일의 코드가 있다고 합시다. (ES6의 arrow-function 문법 사용)
const add = (a, b) => {
return a + b;
}
이 채-신 코드는 바벨이 바꿔 버렸으니 안심하라구!
"use strict";
var add = function add(a, b) {
return a + b;
};
이걸로 전부 해결된 것처럼 보이지만 Babel은 번역을 위한 수단일 뿐 실제 스펙에 대응하는 것은 플러그인입니다. 위에서 바벨이 바꿔 주었다 했지만 사실 플러그인과의 콜라보인 것이며, 바벨만 믿고 최신 자바스크립트 프레임워크와 스펙을 갖다 쓰다간 에러의 철퇴를 맞고 쫓겨납니다. 이 쪽은 플러그인과 프리셋이 해결합니다.
위에서 설명한 것과 같이 Babel이 제대로 코드를 번역하려면 플러그인의 도움이 필요합니다. 각 플러그인은 npm 패키지로 배포됩니다. 우선 대표적인 ES6 문법인 arrow-function을 번역하기 위한 플러그인인 plugin-transform-arrow-functions을 사용해 봅시다.
우선 실습에 들어가기 앞서 Babel 기본 모듈을 설치하고,
yarn add @babel/core @babel-cli -D
그런 뒤 arrow-function을 변환하기 위한 플러그인을 설치합니다.
yarn add @babel/plugin-transform-arrow-functions -D
하지만 이것만으로는 Babel이 이 플러그인을 사용하지는 않습니다. 플러그인을 사용할 거라고 Babel한테 알려주어야 하는데, 그 설정 파일이 .babelrc (혹은 babel.config.js)입니다.
babel.config.js는 전역 설정, .babelrc는 지역 설정으로 사용합니다. 가령, 동일한 설정이 두 파일에서 서로 다르게 작성되어 있다면 지역 설정이 우선하게 됩니다.
.babelrc는 아래와 같이,
{
"plugins": ["@babel/plugin-transform-arrow-functions"],
"presets": []
}
babel.config.js는 아래와 같이 작성합니다.
module.exports = function (api) {
api.cache(true);
const presets = [];
const plugins = ['@babel/plugin-transform-arrow-functions'];
return { presets, plugins };
}
여기까지 작성하고 아무 파일이나 트랜스파일해 봅시다. 아래는 그 결과입니다.
이 방법으로 플러그인을 추가해 각 스펙에 대응할 수 있지만 일일이 플러그인을 추가한다는 건 여간 귀찮은 일이 아닙니다.
굉장히 머리아픈 일입니다. 눈썰미가 좋은 사람은 벌써 눈치챘겠지만 그런 우리를 위해 프리셋이란 게 있습니다.
프리셋은 플러그인의 집합(번들)입니다. 앞서 리액트와 같은 스펙에 대응하려면 플러그인을 직접 설치해야 한다고 했지만 이 프리셋을 이용하면 간단하게 해결할 수 있습니다. 프리셋이 해당 스펙에 대응하도록 플러그인을 모아 놨으니까요.
이 중 Babel이 제공하는 공식 프리셋은 아래와 같습니다.
기존에는 babel-preset-env와 같이 제공하고 연도별로 따로 제공하였으나 Babel 7부터 스코프 패키지로 변경됨과 동시에 @babel/preset-env로 통합되었습니다. 사용자 입장에서는 신경쓸 일이 많이 줄어든 것.
preset-env는 ES6+ 스펙을 번역하기 위한 프리셋이고, 나머지는 각각 Flow, React, TypeScript에 대응하는 프리셋입니다.
yarn add @babel/preset-env -D
그리고 바벨 설정 파일에 프리셋을 추가하면 끝납니다.
{
"presets": ["@babel/preset-env"]
}
혹은 React 앱을 위한 프리셋이 필요하다면 아래와 같이 작성하면 됩니다.
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
그리고 빌드하면 ES6+ 스펙의 코드가 바벨을 통해 ES5로 변환됩니다(기본값). 10년 묵은 체증이 쑥 내려가는 기분.
이처럼 정말 간단하게 코드를 변환할 수 있습니다. preset-env는 설정을 통해 지원하는 브라우저 버전도 설정 가능한데, 이는 별도의 포스트에서 다루겠습니다.
여기까지 CRA 없이 리액트 앱을 빌드하기 위한 첫 단계를 통과했습니다.
그러나 Babel을 단독으로 쓰기보다는 Webpack과 연결하면 babel-loader를 통해 여러 의존성을 가진 모듈을 합쳐 줄 수 있어 매우 유용합니다. 다음에는 Babel과 함께 사용하는 Webpack에 대해 다루겠습니다.