Compile Frontend JavaScript with Babel and Gulp

Using ECMAScript functions on the frontend the quick and dirty way.

As you may have already deduced from the occasional glaring holes in my programming knowledge, I haven’t spent as much of my life programming than, well, anybody who haphazardly threw away an 8-year product management career. Apparently, a lot can happen in 8 years... especially when it comes to JavaScript.
Putting aside that whole server-side  NodeJS thing or whatever it’s called, there’s years worth of mindfucks for those of us who fairly recently returned to dev. In our absence, the world has been Grunting, Gulping, Yarning and even NPMing. Let’s assume we’ve gotten past all of that... phew. Oh wait, I forgot to mention the monstrosity of “hey by way there’s this mess of a hardly-explained (protocol? organization? Fancy Github Repo?) called Babel that we all depend on to do meaningful shit in the browser these days.”

If you’re here because you’re trying to figure what the hell all these ‘const’ and ‘import’ keywords are doing in modern-day browser JavaScript, consider this half focus-group and half getting-started tutorial. For the rest of you experienced JS devs out there, perhaps you should stay. No, by all means, I’d like you to sit here and think about the kind of ecosystem you’ve decided to patch together. Do it; otherwise, I might just give Kik a call to see what other tiny NPM modules they’d like to arbitrarily demand the removal of... remember that? Exactly. Now think about what you’ve done.

ECMAScript and the Backwards-Compatible Web

Any Actionscript veterans in the house? No? Just me? Great. Anyway, There’s something that ActionScript, JavaScript, and a bunch of Whateverscripts have in common: they’re all implementations of ECMAScript: the ancestral equivalent of comparing Latin to Spanish or French, but just one added detail: ECMAScript is still a living language, and constantly improving. If some nation of cool cats still spoke Latin as an active language and were constantly coming up with sick new slang terms, those speaking French or Spanish would be powerless to come up with phrases nearly as cool as “lit” or "fam"  (or whatever those Latin equivalents would be).

The problem is web browsers are inherently backward-compatible monstrosities. Most revenue-generating companies look at their >5% user base using Internet Explorer three and a half, and think “oh my god, that’s five percent of our potential revenue” (it isn’t, but whatever). That’s where we stand.

New features? For the INTERNET?

I remember one particular weekend I rented a hotel room for the sole purpose of wrapping up an app based on MongoDB Stitch at the time. I was pretty confident I had it all figured out, but found, something about Mongo’s quick start guides felt off (I mean, more off than the rest of their nearly unreadable docs). Why did Mongo insist on inline JavaScript? Haven’t we evolved past the days where PHP, HTML, CSS, and JS all lived on the same page?

As everybody-who-wasn’t-me at time already knows, JavaScript has been reaping the benefits of new evolutions in ECMAScript over the years, but there’s a catch: only the most modern browsers know what the hell to do with these new features (duh), and they only do so with the dreaded  blocks thrown on HTML pages. Attempting to use modern ECMA features in a linked JS file which hasn’t been pre-compiled is like dividing by zero. Seriously, you might die.

Babel to the Rescue

More research only lead to more questions. Who is this Browserify wizard and why is he dead? What is Webpack doing to fund all their highly produced branding, and why would anybody purchase a Webpack T-shirt? Finally, the biggest question of all: who the hell is this Babel guy who gives off as an electric explosion in your face on hard drugs?

I can't even the difference between a compiler and a Marvel franchise anymore. 

I think it was at this point in my journey of catching up on the last decade where I went truly mad and began pacing around my room, verbally assaulting inanimate objects, and eventually even found myself washed up in a Wendys down the street, shivering and crying to myself.

Now that I've been released from the psyche ward and are free to wander the streets again, I've managed to piece together a bare-minimum understanding of what the hell is going on.

What the Hell is Going On

Because Javascript as a language is destined to be backwards compatible to a year when OJ Simpson was on trial and Windows 95 was considered cutting-edge technology, Babel aims to "improve" browser Javascript. Because we can't actually improve or change the underlying technology, Babel looks at new-fangled ECMA syntax (containing words like require,  const or promise) and compiles logic equivalent to these features with vanilla Javascript. If that sounds similar to how Gulp takes CSS preprocessors (like LESS or SASS) and turns those files into interpretable browser code, well, that's exactly what happens.

Gulp is not be the only way to utilize new ECMAScript features. Babel syntax can be compiled a number of ways, such as Babel's CLI, or from Server-side JS, or Webpack if you're Mister-Fancy-Pants. In fact, the trend across the board is that compiling your site with modules via Webpack is winning dramatically. For all we know, this could be the last Babel Gulp tutorial ever written.

Right now we're focusing on the ability to use ECMAScript features on the frontend; a common use-case for things like... well... theming the presentation layer for a blog. If we can pull it off with Gulp, you probably won't struggle much with future methods.

Babel NPM Packages

Alright, so Babel isn't just a single NPM package. It's a lot. Let's see what's there in a basic package.json:

{
  "name": "example",
  "scripts": {
    "build": "babel src -d lib"
  },
  "presets": [
    "env"
  ],
  "engines": {
    "node": "8.12.0"
  },
  "dependencies": {
    "@babel/polyfill": "^7.0.0",
    "@babel/runtime": "^7.1.2",
    "@babel/runtime-corejs2": "^7.1.2",
    "babel-runtime": "^6.26.0",
    "gulp-resolve-dependencies": "^2.2.0",
    "gulp-sourcemaps": "^2.6.4",
    "gulp-uglify-es": "^1.0.4",
  },
  "devDependencies": {
    "@babel/cli": "^7.1.2",
    "@babel/core": "^7.1.2",
    "@babel/plugin-syntax-dynamic-import": "^7.0.0",
    "@babel/plugin-transform-runtime": "^7.1.0",
    "@babel/preset-env": "^7.1.0",
  }
}

Let's not go through all these in detail- in fact, let's take a look at our gulpfile.js:

'use strict';

var gulp = require('gulp'),
  concat = require('gulp-concat'),
  autoprefixer = require('gulp-autoprefixer'),
  sourcemaps = require('gulp-sourcemaps'),
  babel = require('gulp-babel'),
  resolveDependencies = require('gulp-resolve-dependencies'),


var paths = {
  scripts: {
    src: 'src/js/*.js',
    dest: 'assets/js'
  }
};

function scripts() {
  return gulp.src(paths.scripts.src)
    .pipe(babel({
          presets: ['@babel/env'],
          plugins: ['@babel/transform-runtime', '@babel/plugin-syntax-dynamic-import']
    }))
    .on('error', console.error.bind(console))
    .pipe(resolveDependencies({
            pattern: /\* @requires [\s-]*(.*\.js)/g
        }))
    .pipe(concat('main.min.js'))
    .pipe(gulp.dest(paths.scripts.dest));
}

Note that I've gone ahead and removed anything from the file that has nothing to do with Babel - everything seen here is strictly relevant to building a 'scripts' task. The gist is this:

babel accepts two arrays:

  • Presets refers to the version of ECMAScript we're targeting, and what we have implies the latest.
  • Plugins allow us to pass any plugins Babel supports; in this case, we're rendering stuff at runtime. Let's not get into it too far.

The rest of the function is simple: we catch errors if any arise, we resolve required dependencies, and then we finally bunch everything into a single file and shove it in our destination folder.

Just to be Clear

When it comes to the best way of achieving ECMAScript 2015 or 2016 etc in the browser,  I'm no expert. As previously mentioned, the understanding I've passed on to you is a sort of bare minimum to start doing great things.

As far as what others are doing, I'd be willing to bet that the vast majority of devs utilizing newer ECMAScript functions are running frameworks like React, while the rest have reached a consensus that Webpack is king and Gulp lame. These things may be true.

No matter, this new found power of ours opens a lot of doors. Just wait until you see what we do with MongoDB Stitch.

Author image
New York City Website
Product manager turned engineer with an ongoing identity crisis. Breaks everything before learning best practices. Completely normal and emotionally stable.

Product manager turned engineer with an ongoing identity crisis. Breaks everything before learning best practices. Completely normal and emotionally stable.