Babel

Seju·2024년 3월 1일
1

JavaScript

목록 보기
28/28
post-thumbnail

개요


React로 프로젝트를 세팅하고 개발에 임하면서 React가 제공하는 Hook API나, 리액트에서 사용되는 라이브러리등을 공부해 프로젝트에 적용했었다.
그러나, 이러한 React 프로젝트를 사용할 수 있도록 도와주는 라이브러리들(Bable,WebPack,vite 등등..)은 항상 React 패키지 설치 시 자동으로 설치되다보니 이러한 모듈러나 트랜스파일러등이 어떻게 동작하는지 확인하지 않고 개발에 임했었다.
이번 글을 계기로 다양한 모듈러나 트랜스파일러등을 분석하고 작성할 생각이다.

이 글은 바벨 공식문서를 참고해 작성한 문서입니다!


바벨이란?


Bable은 JavaScript 컴파일러입니다.

  • 여기서 컴파일러란 사람이 읽을 수 있는 용어(=프로그래밍 언어)를 컴퓨터가 읽을 수 있는 용어(=기계어)로 중간에서 변환해주는 프로그램을 뜻합니다.
  • 바벨은 과거 브라우저에 환경에서 지원하지 않는 ES6 문법을 이전 버전과 호환될 수 있는 JavaScript 버전으로 변환되는데 사용하는 툴체인입니다.

Babel이 제공하는 주요 기능들
1. 최신 JavaScript로 문법 변환 : 위에서 써있듯이 최신 JavaScript문법을 구형 브라우제어도 동작 가능케 하는 ES5 코드로 변환하는 역할을 합니다.
2. 폴리필 기능 : Bable은 폴리필 기능을 통해 구형 브라우저에 지원하지 않는 최신 JavaScript API(ex:Promise, Fetch API, Spread Syntax)를 사용할 수 있게합니다.

JSX in Bable

React 개발 시 JSX 문법은 필수적으로 사용된다고 해도 과언이 아닙니다.

  • Babel은 이러한 JSX 구문을 이해하고 자바스크립트 코드로 변환할 수 있게됩니다.
    • JSX는 표준 JavaScript가 아니므로 브라우저가 이해할 수 없습니다.
  • Babel은 이러한 JSX 코드를 받고 브라우저 이해할 수 있는 일반 JavaScript로 변환합니다.
const element = <h1>Hello, world!</h1>;

/* 바벨 트랜스파일러에 의해 다음과 같이 컴파일 됩니다.*/
const element = React.createElement('h1', null, 'Hello, world!');


Babel 트랜스파일러 적용해보기

  • 먼저, 프로젝트 내 Babel 패키지들 설치되어야 합니다.
pnpm i -D @babel/core @bable/cli @babel/preset-env
  • 각 패키지들이 하는 역할에 대해서 간략히 알아보겠습니다.

@bable/core

  • Bable의 핵심기능들을 제공하는 역할을 합니다.
    • JavaScript 코드 파싱 -> AST(추상 구문트리)로 변환 -> 플러그인 혹은 프리셋을 적용 -> 다시 과거문법으로 트랜스파일링 된 JavaScript 코드로 변환

@bable/cli

  • Bable을 커맨드라인에서 사용할 수 있게 하는 패키지이며, 해당 패키지를 통해 소스 코드를 트랜스파일하고 결과를 출력 디렉토리에 저장할 수 있습니다.

@bable/preset-env

  • 개발자가 지정한 환경에 맞게 최신 JavaScript를 변환해주는 Babel 프리셋입니다.
    • 예를 들어, 특정 버전의 브라우저를 지원하도록 설정할 수 있으며, 이에 따라 필요한 플러그인들을 자동으로 결정하여 적용합니다.
  • 아래는 하위 브라우저 호환을 기대하는 ES6 문법이 사용된 자바스크립트 코드입니다.
const bable = "Hellow World";
const bableObject = {
  name: "babel",
  version: 7,
};

const copyBable = {...bableObject};
  • Bable로 컴파일을 위해 package.json에 컴파일 명령어를 새로이 작성합니다.
  • src 디렉토리 내부 JavaScript 파일을 컴파일 한 후 dist라는 새로운 디렉토리에 결과를 저장합니다.
{
  "name": "babel",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "compile": "babel src -d dist"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/cli": "^7.23.9",
    "@babel/core": "^7.24.0",
    "@babel/preset-env": "^7.24.0"
  }
}

컴파일 전 추가설정 (Preset 설정하기)

  • 해당 명령어만으로는 바벨은 아무것도 컴파일하지않습니다.
  • 하위 브라우저 호환 가능한 코드로 컴파일하기 위해선 아까 설치한 패키지 @bable/preset-env에 대한 설정이 필요합니다.

babel.config.json 파일 생성 및 사전 설정 추가하기

  • 프로젝트 루트에 bable.config.json 파일을 생성합니다.
  • 그리고 아래와 같이 패키지를 등록해줍니다.
  • modules : false로 설정한 이유는, ES6 모듈을 다른 모듈타입(=Cjs)로 변환하는것을 방지하기 위함입니다.
{
  "presets": [["@babel/preset-env", {"modules": false}]]
}
  • 등록된 스크립트를 기반으로 컴파일해보겠습니다.
pnpm run compile

_ dist 폴더 내 컴파일 된 index.js파일_

  • dist 폴더가 새로이 생성되었고 그안에 index.js파일이 컴파일되었습니다. 이를 확인해보겠습니다.
function _typeof(o) {
  "@babel/helpers - typeof";
  return (
    (_typeof =
      "function" == typeof Symbol && "symbol" == typeof Symbol.iterator
        ? function (o) {
            return typeof o;
          }
        : function (o) {
            return o &&
              "function" == typeof Symbol &&
              o.constructor === Symbol &&
              o !== Symbol.prototype
              ? "symbol"
              : typeof o;
          }),
    _typeof(o)
  );
}
function ownKeys(e, r) {
  var t = Object.keys(e);
  if (Object.getOwnPropertySymbols) {
    var o = Object.getOwnPropertySymbols(e);
    r &&
      (o = o.filter(function (r) {
        return Object.getOwnPropertyDescriptor(e, r).enumerable;
      })),
      t.push.apply(t, o);
  }
  return t;
}
function _objectSpread(e) {
  for (var r = 1; r < arguments.length; r++) {
    var t = null != arguments[r] ? arguments[r] : {};
    r % 2
      ? ownKeys(Object(t), !0).forEach(function (r) {
          _defineProperty(e, r, t[r]);
        })
      : Object.getOwnPropertyDescriptors
      ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t))
      : ownKeys(Object(t)).forEach(function (r) {
          Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r));
        });
  }
  return e;
}
function _defineProperty(obj, key, value) {
  key = _toPropertyKey(key);
  if (key in obj) {
    Object.defineProperty(obj, key, {
      value: value,
      enumerable: true,
      configurable: true,
      writable: true,
    });
  } else {
    obj[key] = value;
  }
  return obj;
}
function _toPropertyKey(t) {
  var i = _toPrimitive(t, "string");
  return "symbol" == _typeof(i) ? i : String(i);
}
function _toPrimitive(t, r) {
  if ("object" != _typeof(t) || !t) return t;
  var e = t[Symbol.toPrimitive];
  if (void 0 !== e) {
    var i = e.call(t, r || "default");
    if ("object" != _typeof(i)) return i;
    throw new TypeError("@@toPrimitive must return a primitive value.");
  }
  return ("string" === r ? String : Number)(t);
}
var bable = "Hellow World";
var bableObject = {
  name: "babel",
  version: 7,
};
var copyBable = _objectSpread({}, bableObject);
  • 기존 ES6구문에서 지원되지않는 것들(Spread Syntax, let, const)등이 바벨 자체의 유틸리티 함수로 만들어져 적용되는 모습을 확인할 수 있습니다!
profile
Talk is cheap. Show me the code.

0개의 댓글