Babel 플러그인

차세대 JavaScript 컴파일 확장

클래스 필드 선언

ES 표준에 제안 된 클래스 필드 선언(class field declarations) 구문을 사용하면 클래스 문법 사용 시 편리하게 스태틱, 인스턴스 멤버를 추가해 사용할 수 있습니다. 하지만 이 기능을 현재 제안된 기술로 @babel/preset-env 사전 설정에는 포함되어 있지 않아 사용할 수 없습니다.

class Button {
  constructor(props) {
    this.props = { ...this.constructor.defaultProps, ...props };
  }
  
  // 클래스 멤버
  static defaultProps = {
    type: 'button'
  };
  
  // 인스턴스 멤버
  displayProps = () => {
    console.log(this.props);
  };
}

클래스 필드 선언을 사용하기 위해 @babel/plugin-proposal-class-properties 플러그인 패키지를 설치합니다.

npm i -D @babel/plugin-proposal-class-properties

설치한 플러그인을 사용하기 위한 설정을 babel.config.json 파일에 추가합니다.

{
  "plugins": [
    "@babel/plugin-proposal-class-properties"
  ]
}

start 명령을 실행해 컴파일 하면, 클래스 필드 선언 구문을 호환 가능한 코드로 출력해줍니다.

npm start
"use strict";

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

var Button = function Button(props) {
  var _this = this;

  _classCallCheck(this, Button);

  _defineProperty(this, "displayProps", function () {
    console.log(_this.props);
  });

  this.props = _objectSpread(_objectSpread({}, this.constructor.defaultProps), props);
};

_defineProperty(Button, "defaultProps", {
  type: 'button'
});

비공개 멤버

ES 표준에 제안 된 비공개 멤버(private methods) 구문을 사용하면 클래스 문법 사용 시 편리하게 비공개 멤버를 추가해 (JAVA의 private 접근 제어자처럼) 사용할 수 있습니다. 하지만 이 기능을 현재 제안된 기술로 @babel/preset-env 사전 설정에는 포함되어 있지 않아 사용할 수 없습니다.

class Button {
  constructor(props) {
    this.props = props ?? { ...this.constructor.defaultProps, ...props };
  }
  
  // 비공개 멤버 (클래스 외부에서 접근 불가능)
  #API_TOKEN = 'token-fkjw2jicjx8kjvwdijf3';

  static defaultProps = {
    type: 'button'
  };

  fetchData() {
    // 클래스 또는 인스턴스 멤버는 비공개 멤버에 접근 가능
    fetch(`https://api.dev?token=${this.apiToken}`)
      .then((res) => console.log(res))
      .catch((error) => console.error(error.message));
  }

  displayProps = () => {
    console.log(this.props);
  };
}

클래스 필드 선언을 사용하기 위해 @babel/plugin-proposal-private-methods 플러그인 패키지를 설치합니다.

npm i -D @babel/plugin-proposal-private-methods

설치한 플러그인을 사용하기 위한 설정을 babel.config.json 파일에 추가합니다.

{
  "plugins": [
    "@babel/plugin-proposal-private-methods"
  ]
}

start 명령을 실행해 컴파일 하면, 클래스 필드 선언 구문을 호환 가능한 코드로 출력해줍니다.

npm start
"use strict";

function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }

function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

function _classPrivateFieldGet(receiver, privateMap) { var descriptor = privateMap.get(receiver); if (!descriptor) { throw new TypeError("attempted to get private field on non-instance"); } if (descriptor.get) { return descriptor.get.call(receiver); } return descriptor.value; }

var _API_TOKEN = new WeakMap();

var Button = /*#__PURE__*/function () {
  function Button(props) {
    var _this = this;

    _classCallCheck(this, Button);

    _API_TOKEN.set(this, {
      writable: true,
      value: 'token-fkjw2jicjx8kjvwdijf3'
    });

    _defineProperty(this, "displayProps", function () {
      console.log(_this.props);
    });

    this.props = props !== null && props !== void 0 ? props : _objectSpread(_objectSpread({}, this.constructor.defaultProps), props);
  }

  _createClass(Button, [{
    key: "apiToken",
    get: function get() {
      return _classPrivateFieldGet(this, _API_TOKEN);
    }
  }, {
    key: "fetchData",
    value: function fetchData() {
      fetch("https://api.dev?token=".concat(this.apiToken)).then(function (res) {
        return console.log(res);
      }).catch(function (error) {
        return console.error(error.message);
      });
    }
  }]);

  return Button;
}();

_defineProperty(Button, "defaultProps", {
  type: 'button'
});

참고

살펴본 Babel 플러그인 외에도 다양한 플러그인을 사용할 수 있습니다.

Last updated