BabelJS - Babel Plugins

BabelJS is a javascript compiler that changes the syntax of the code given based on presets and plugins available. The flow of babel compilation involves the following 3 parts −
parsing
transforming
printing
The code given to babel is given back as it is with just the syntax changed. We have already seen presets being added to .babelrc file to compile code from es6 to es5 or vice-versa. Presets are nothing but a set of plugins. Babel will not change anything if presets or plugins details are not given during compilation.
Let us now discuss the following plugins −
transform-class-properties
Transform-exponentiation-operator
For-of
object rest and spread
async/await
Now, we will create a project setup and work on few plugins, which will give clear understanding of the requirements of plugins in babel.
npm init

We have to install the required packages for babel – babel cli, babel core, babel-preset, etc.
npm install babel-cli babel-core babel-preset-es2015 --save-dev

npm install @babel/cli @babel/core @babel/preset-env --save-dev

Create a js file in your project and write your js code.
Observe the codes given below for this purpose −
main.js
class Person {
   constructor(fname, lname, age, address) {
      this.fname = fname;
      this.lname = lname;
      this.age = age;
      this.address = address;
   }

   get fullname() {
      return this.fname + "-" + this.lname;
   }
}
var a = new Person("Siya", "Kapoor", "15", "Mumbai");
var persondet = a.fullname;
Right now, we have not given any preset or plugin details to babel. If we happen to transpile the code using command −
npx babel main.js --out-file main_out.js

main_out.js
class Person {
   constructor(fname, lname, age, address) {
      this.fname = fname;
      this.lname = lname;
      this.age = age;
      this.address = address;
   }

   get fullname() {
      return this.fname + "-" + this.lname;
   }
}
var a = new Person("Siya", "Kapoor", "15", "Mumbai");
var persondet = a.fullname;
We will get the code as it is. Let us now add preset to .babelrc file.
Note − Create .babelrc file inside the root folder of your project.
.babelrc for babel 6
.babelrc for babel 7
{
   "presets":["@babel/env"]
}
We have already installed the presets; now let us run the command again −
npx babel main.js --out-file main_out.js

main_out.js
"use strict";

var _createClass = 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); 
      }
   }
   return function (Constructor, protoProps, staticProps) { 
      if (protoProps) defineProperties(Constructor.prototype, protoProps); 
      if (staticProps) defineProperties(Constructor, staticProps); 
      return Constructor; 
   }; 
}();

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

var Person = function () {
   function Person(fname, lname, age, address) {
      _classCallCheck(this, Person);

      this.fname = fname;
      this.lname = lname;
      this.age = age;
      this.address = address;
   }

   _createClass(Person, [{
      key: "fullname",
      get: function get() {
         return this.fname + "-" + this.lname;
      }
   }]);
   return Person;
}();

var a = new Person("Siya", "Kapoor", "15", "Mumbai");
var persondet = a.fullname;
In ES6, class syntax is as follows
class Person {
   constructor(fname, lname, age, address) {
      this.fname = fname;
      this.lname = lname;
      this.age = age;
      this.address = address;
   }

   get fullname() {
      return this.fname + "-" + this.lname;
   }
}

There is constructor and all the properties of the class are defined inside it. Incase, we need to define class properties outside the class we cannot do so.
class Person {
   name = "Siya Kapoor";

   fullname = () => {
      return this.name;
   }
}
var a = new Person();
var persondet = a.fullname();
console.log("%c"+persondet, "font-size:25px;color:red;");
If we happen to compile the above code, it will throw an error in babel. This results in the code not getting compiled.
To make this work the way we want, we can make use of babel plugin called babel-plugin-transform-class-properties. To make it work, we need to install it first as follows −
npm install --save-dev babel-plugin-transform-class-properties

npm install --save-dev @babel/plugin-proposal-class-properties

Add the plugin to .babelrc file for babel 6 −
.babelrc for babel 7
{
   "plugins": ["@babel/plugin-proposal-class-properties"]
}
Now, we will run the command again.
npx babel main.js --out-file main_out.js

main.js
class Person {
   name = "Siya Kapoor";

   fullname = () => {
      return this.name;
   }
}
var a = new Person();
var persondet = a.fullname();
console.log("%c"+persondet, "font-size:25px;color:red;");
Compiled to main_out.js
class Person {
   constructor() {
      this.name = "Siya Kapoor";

      this.fullname = () => {
         return this.name;
      };
   }
}
var a = new Person();
var persondet = a.fullname();
console.log("%c"+persondet, "font-size:25px;color:red;");
Output
Following is the output we get when used in a browser −
** is the operator used for exponentiation in ES7. Following example shows the working of same in ES7. It also shows how to transpile code using babeljs.
let sqr = 9 ** 2;
console.log("%c"+sqr, "font-size:25px;color:red;");
To transpile the exponentiation operator, we need a plugin to be installed as follows −
Packages for babel 6
npm install --save-dev babel-plugin-transform-exponentiation-operator

Packages for babel 7
npm install --save-dev @babel/plugin-transform-exponentiation-operator

Add the plugin details to .babelrc file as follows for babel 6 −
{
   "plugins": ["transform-exponentiation-operator"]
}
.babelrc for babel 7
{
   "plugins": ["@babel/plugin-transform-exponentiation-operator"]
}
command
npx babel exponeniation.js --out-file exponeniation_out.js

exponeniation_out.js
let sqr = Math.pow(9, 2);
console.log("%c" + sqr, "font-size:25px;color:red;");
Output
The packages required for the plugins in babel6 and 7 are as follows −
npm install --save-dev babel-plugin-transform-es2015-for-of

npm install --save-dev @babel/plugin-transform-for-of

.babelrc for babel6
{
   "plugins": ["transform-es2015-for-of"]
}
.babelrc for babel7
{
   "plugins": ["@babel/plugin-transform-for-of"]
}
forof.js
let foo = ["PHP", "C++", "Mysql", "JAVA"];
for (var i of foo) {
   console.log(i);
}
npx babel forof.js --out-file forof_es5.js

Forof_es5.js
let foo = ["PHP", "C++", "Mysql", "JAVA"];
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;

try {
   for (var _iterator = foo[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
      var i = _step.value;

      console.log(i);
   }
} catch (err) {
   _didIteratorError = true;
   _iteratorError = err;
} finally {
   try {
      if (!_iteratorNormalCompletion && _iterator.return) {
         _iterator.return();
      }
   } finally {
      if (_didIteratorError) {
         throw _iteratorError;
      }
   }
}
Output
The packages required for the plugins in babel6 and 7 are as follows −
npm install --save-dev babel-plugin-transform-object-rest-spread

npm install --save-dev @babel/plugin-proposal-object-rest-spread

.babelrc for babel6
{
   "plugins": ["transform-object-rest-spread"]
}
.babelrc for babel7
{
   "plugins": ["@babel/plugin-proposal-object-rest-spread"]
}
o.js
let { x1, y1, ...z1 } = { x1: 11, y1: 12, a: 23, b: 24 };
console.log(x1);
console.log(y1);
console.log(z1);

let n = { x1, y1, ...z1};
console.log(n);
npx babel o.js --out-file o_es5.js

o_es5.js
var _extends = Object.assign || function (target) {
   for (var i = 1; i < arguments.length; i++) {
      var source = arguments[i]; for (var key in source) {
         if (Object.prototype.hasOwnProperty.call(source, key)) {
            target[key] = source[key]; 
         } 
      } 
   } 
   return target; 
};

function _objectWithoutProperties(obj, keys) {
   var target = {};
   for (var i in obj) {
      if (keys.indexOf(i) >= 0) continue;
      if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
      target[i] = obj[i];
   }
   return target;
}

let _x1$y1$a$b = { x1: 11, y1: 12, a: 23, b: 24 },
   { x1, y1 } = _x1$y1$a$b,
   z1 = _objectWithoutProperties(_x1$y1$a$b, ["x1", "y1"]);
console.log(x1);
console.log(y1);
console.log(z1);

let n = _extends({ x1, y1 }, z1);
console.log(n);
Output
We need the following packages to be installed for babel 6 −
npm install --save-dev babel-plugin-transform-async-to-generator

npm install --save-dev @babel/plugin-transform-async-to-generator

.babelrc for babel 6
{
   "plugins": ["transform-async-to-generator"]
}
.babelrc for babel 7
{
   "plugins": ["@babel/plugin-transform-async-to-generator"]
}
async.js
let timer = () => {
   return new Promise(resolve => {
      setTimeout(() => {
         resolve("Promise resolved after 5 seconds");
      }, 5000);
   });
};
let out = async () => {
   let msg = await timer();
   console.log(msg);
   console.log("hello after await");
};

out();
npx babel async.js --out-file async_es5.js

async_es5.js
function _asyncToGenerator(fn) {
   return function () {
      var gen = fn.apply(this, arguments);
      return new Promise(function (resolve, reject) {
         function step(key, arg) {
            try {
               var info = gen[key](arg);
               var value = info.value; 
            } catch (error) {
               reject(error);
               return; 
            } if (info.done) {
               resolve(value); 
            } else {
               return Promise.resolve(value).then(function (value) {
                  step("next", value);
               },
               function (err) {
                  step("throw", err); }); 
            }
         } return step("next"); 
      });
   };
}

let timer = () => {
   return new Promise(resolve => {
      setTimeout(() => {
         resolve("Promise resolved after 5 seconds");
      }, 5000);
   });
};
let out = (() => {
   var _ref = _asyncToGenerator(function* () {
      let msg = yield timer();
      console.log(msg);
      console.log("hello after await");
   });

   return function out() {
      return _ref.apply(this, arguments);
   };
})();
out();
We have to make use of polyfill for the same as it will not work in browsers where promises are not supported.
Output
 Print
 Add Notes
 Bookmark this page