Client/React.js

[React.js] Babel / Webpack: 트랜스 컴파일러와 JS 모듈 번들러

ooeunz 2020. 7. 26. 12:37
반응형

React.js를 공부하다 보면 필연적으로 한 번씩 듣게 되는 키워드가 바로 바벨과 웹팩입니다. 이 둘에 대해 자세히 알지 못하더라도 당장 리액트 개발을 하지 못하는 것은 아닙니다. 왜냐하면 리액트 팀에서 번거로운 바벨과 웹팩 설정을 create-react-app이라는 프로젝트를 통해서 아주 간편하게 설정하고 끝낼 수 있도록 도움을 주고 있기 때문입니다. 하지만 앞선 포스팅에서 이야기했듯이, 단순히 프레임워크 자체를 이해하기보다는 그 원리를 이해하고 더 나은 개발자가 되기 위해선 babel과 webpack이 왜 필요하고, 어떤 일을 하는지에 대해서 알고 넘어가 필요가 있습니다. 해당 포스팅에서는 바벨과 웹팩을 아주 간단하게 소개하고, 어떤 역할을 하는지에 대해서 살펴보도록 하겠습니다. (이후 좀 더 심화된 내용은 다른 포스팅에서 다루도록 하겠습니다.)

 

바벨(babel)이란?

바벨이란 자바스크립트 코드를 변환해주는 트랜스 컴파일러입니다. 자바스크립트는 컴파일 언어가 아닌데 웬 트랜스 컴파일러?라고 생각하실 수 있습니다. 처음 ES6 문법이 세상에 나왔을 때 대부분의 브라우저는 ES5이하의 버전만 지원을 하고 있었습니다. 하지만 ES6 문법에 대한 개발자들의 수요가 엄청나게 올라감으써 ES6문법으로 개발을 했지만 모든 브라우저에서 호환이 돼야 했던 방법이 필요했습니다. 이때 필요한 것이 바로 babel입니다. 바벨은 최신 자바스크립트 문법을 지원하지 않는 환경에서도 최신 문법을 사용할 수 있도록 지원합니다. 즉 ES6 문법으로 개발했지만, 바벨을 사용할 경우 ES5문법만 지원하는 브라우저에 알맞게 ES6문법을 ES5 문법으로 번역해줍니다. 또한 바벨은 최신 자바스크립트 문법을 사용하는 용도 외에도 다양하게 사용될 수 있는데, 바로 React.js의 JSX 문법이 바로 그 대표적인 예시입니다. 바벨은 JSX 문법으로 작성된 코드를 createElement 함수를 사용한 리액트 코드로 변환시켜 줍니다. (또한 동시에 주석도 없애줍니다.) 이게 무슨 말인지 아래의 코드에서 살펴보도록 하겠습니다.

 

※ 해당 포스팅에서는 JSX문법에 대해 따로 설명하지 않습니다. JSX문법을 알고 있다는 가정하에 설명됩니다.

JSX문법은 Javascript 문법과 HTML문법을 적절히 합쳐놓은 것으로, 어렵지 않게 습득할 수 있으니 사전에 공부해두시기 바랍니다.

 

아래의 코드는 우리가 흔히 알고 있는 JSX 문법을 사용하여서 버튼을 +클릭하면 count가 증가하고 -버튼을 누르면 count가 감소하는 간단한 프로젝트 코드입니다. 그런데 이렇게 JSX로 개발하다 보면 한번쯤 이런 생각이 들지 않으셨나요? JSX는 javascript 코드가 아닌데, (결국엔 런타임 시에 javsscript로 동작할 텐데) 어떻게 JSX문법을 이해하고 동작하는 거지?

class LikeButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = { liked: false };
  }
  render() {
    const text = this.state.liked ? '좋아요 취소' : '좋아요';
    return (
      <button onClick={() => this.setState({ liked: true })}>
        {text}
      </button>
    );
  }
}

class Container extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }
  render() {
    return (
      <div>
        <LikeButton />
        <div style={{ marginTop: 20 }}>
          <span>현재 카운트: </span>
          <span>{this.state.count}</span>
          <button
            onClick={() => this.setState({ count: this.state.count + 1 })}
          >
            증가
          </button>
          <button
            onClick={() => this.setState({ count: this.state.count - 1 })}
          >
            감소
          </button>
        </div>
      </div>
    );
  }
}

이러한 의문에 대한 해답이 바로 Babel에 있습니다. 바벨은 위와 같이 우리가 JSX문법으로 작성한 코드를 Node.js가 알아들을 수 있도록 javascript 문법으로 번역해줍니다. 위의 코드를 Babel이 javascript 코드로 변환하면 아래와 같습니다.

 

class LikeButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = { liked: false };
  }
  render() {
    const text = this.state.liked ? '좋아요 취소' : '좋아요';
    return React.createElement(
      'button',
      { onClick: () => this.setState({ liked: true }) },
      text,
    );
  }
}

class Container extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }
  render() {
    return React.createElement(
      'div',
      null,
      React.createElement(LikeButton),
      React.createElement(
        'div',
        { style: { marginTop: 20 } },
        React.createElement('span', null, '현재 카운트: '),
        React.createElement('span', null, this.state.count),
        React.createElement(
          'button',
          { onClick: () => this.setState({ count: this.state.count + 1 }) },
          '증가',
        ),
        React.createElement(
          'button',
          { onClick: () => this.setState({ count: this.state.count - 1 }) },
          '감소',
        ),
      ),
    );
  }
}

const domContainer = document.querySelector('#react-root');
ReactDOM.render(React.createElement(Container), domContainer);

 

무엇이 달라졌는지 눈치채셨나요? JSX문법으로 작성된 모든 코드들이 React.createElement라는 처음 보는 자바스크립트 코드로 변환되었습니다. createElement 함수는 React Library안의 함수로 구조는 다음과 같습니다.

 

React.createElement(component, props, ...children) => ReactElement

 

첫 번째 매개변수 component는 일반적으로 문자열이나 React Component가 들어옵니다. component의 인자가 문자열이면 HTML 태그에 해당하는 dom 요소를 생성하게 됩니다. 예를 들어 문자열 'span'를 입력하게 되면 HTML span 태그가 생성됩니다.

 

두 번째 매개변수 props 컴포넌트가 사용하는 데이터를 나타냅니다. dom 요소의 경우 style, className 등의 데이터가 사용될 수 있습니다.

 

세 번째 매개변수 ...children은 해당 컴포넌트가 감싸고 있는 child  component를 가리킵니다. 예를 들어 div 태그가 p태그 두 개를 감싸고 있다면 아래와 같은 형태가 됩니다.

React.createElement(
  'div',
  null,
  React.createElement('p', null, '첫 번째 p태그'),
  React.createElement('p', null, '두 번째 p태그'),
)

 해당 react 코드는 javascript에 의해서 dom element를 생성하게 되고 최종적으로 아래와 같은 html 태그가 됩니다.

<div>
  <p>첫 번째 p태그</p>
  <p>두 번째 p태그</p>
</div>

 

이와 같이 React.js는 Javascript로 dom element를 생성하고 다루는 문법을 Library 형태로 추상화한 기술입니다. JSX 문법과 같은 생소한 문법이고, 기존의 방식과 다른 재사용화 패턴이 익숙하지 않더라도 라이브러리를 뜯어보면 결국에는 우리가 알고 있는 javascript를 기반으로 작성되어 있습니다. (때문에 바닐라 javascript로 먼저 개발해보지 않고 react부터 개발을 하는 것은 위험한 행동입니다.)

 

 

웹팩(webpack)이란?

웹팩은 자바스크립트로 만든 프로그램을 배포하기 좋은 형태로 묶어주는 툴입니다. 배포하기 좋은 형태라는 말이 잘 안 와 닿을 수 있지만 2000년대 초 초기의 웹 페이지를 배포하는 방식을 생각하면 쉽게 이해할 수 있습니다. 당시에는 웹 페이지가 전환될 때마다 새로운 
HTML 파일을 요청해서 화면을 새로 그리는 방식(리렌더링)이었습니다. 그 당시에는 javascript는 돔을 조작하는 아주 간다한 역할만을 수행하였기 때문에 코드 자체의 양이 많지 않았습니다. 하지만 Ajax가 나타나고 현재에 이르러 SPA(Single Page Application)으로 전환되면서 한 페이지당 javascript 파일이 수 십, 수백 개가 필요하게 되었습니다.

 

이에 따라 ESM(ES6의 모듈 시스템)과 commonJS와 같은 외부 javascript 파일을 import 하고 export 함으로써 파일을 분리하여 작성하고 이후에 webpack을 이용해서 하나의 파일로 합치게 되었습니다.

 

요약하자면 위의 이미지와 같이 복잡해질 대로 복잡해진 파일들을 간편하게 패키징 해주는 기능을 해주는 것입니다.

 

create-react-app

create-react-app은 앞에서 잠깐 언급한 적이 있습니다. react 팀에서 이러한 babel과 webpack, css 후처리나 그 박의 다양한 테스트 시스템을 모두 묶어서 개발 환경을 손쉽게 구축할 수 있도록 해주는 프로젝트입니다.

 

create-react-app을 사용하는 방법은 아래의 명령어를 터미널에 입력하면 됩니다.

npx create-react-app <Project 이름>

 

npx는 create-react-app이 해당 개발환경에 설치되어 있지 않더라도 자동으로 가져와서 실행하는 기능을 해줍니다. 위의 명령어를 입력해준 다음 Project 이름으로 지정한 폴더로 이동한 다음 npm start 혹은 yarn start 명령어로 react 프로젝트를 간편하게 실행시킬 수 있습니다.

반응형