Babel

What Babel 7 does and doesn’t do

Babel 7 will not transpile any of the following out of the box:

If you want to use any of these, you should either bring in your own polyfills for what you need, or you should include corejs with Babel.

Babel 7 will transpile the following out of the box:

There are plugins for each of these but they do not appear to be necessary. It looks like Babel is trying to steer towards transpiling syntax and keyword features, and not functions or objects, which need to be polyfilled.

Babel, JavaScript

Running Babel should be the one of the last stages of your front end build

After recently upgrading from Babel 6 to 7.4 for a project, I decided to check over the outputted file to make sure all was well.

I started by looking for the basics – was const getting changed to var? Yes it was. Were ES6 classes being converted to functions? Yes they were. And were object spreads being transpiled down? Yes they were, but this was now being done in a different way to Babel 6.

In Babel 7.4, using an object spread operator will result in Babel injecting a polyfill function called _objectSpread into the top of the outputted JavaScript file. This function will then be called wherever you are using an object spread. E.g:

Input:

function someOtherTest () {
  const p1 = {
    name: 'p1'
  };
  
  const combinedP1 = {
    height: 100,
    ...p1
  }
}

Results in the following, after being run through Babel:

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(source, true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(source).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }

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 someOtherTest() {
  var p1 = {
    name: 'p1'
  };

  var combinedP1 = _objectSpread({
    height: 100
  }, p1);
}

Here’s a link to see this in action on the Babel repl.

As you can see, it’s a lot more code, but is a tax that some of us have to pay in order to support some older browsers.

And this is where we need to be careful. Most front end build processes typically follow this flow:

  • Gather the source js files
  • Combine them into one file
  • Minify the single combined file
  • Write the output to disk

What you do not want to do, is to run Babel before the output has been combined into one file. If you follow this pattern:

  • Gather the source js files
  • Transpile them using Babel
  • Combine them into one file
  • Minify the single combined file
  • Write the output to disk

You will end up with some serious bloat! In every file that you have used the object spread operator in, Babel will inject a locally scoped _objectSpread function. So you could easily end up with multiple copies of the exact same polyfill function.

This is the web, and we don’t like unnecessary bloat – so the correct workflow for your front end build is:

  • Gather the source js files
  • Combine them into one file
  • Transpile them using babel
  • Minify the single combined file
  • Write the output to disk

This way, you’ll only get polyfill functions injected once into your outputted JS, even if the polyfill is used multiple times.