Gulp + Babel + Webpack

I have come to really like using ECMAScript 2015 (ES6). During my ventures I have learned how to use ES6’s import feature with Webpack to compile everything into a single compressed Javascript file.

If you are not familiar with Gulp, Babel, or Webpack. Take some time and get acquainted.

  • http://gulpjs.com
  • https://babeljs.io
  • https://webpack.github.io

My entire gulpfile.js is available at the bottom of this post so that you can see everything in context.

First of all, Webpack is very powerful and can compile ES6 and SASS without Gulp. Webpack is also much more difficult to configure, and frankly I like using Gulp. So here it goes.

You will need to install these NPM packages.
Example:

npm install --save-dev package_name
  • gulp-babel
  • babel-preset-es2015-without-strict
  • gulp-uglify
  • gulp-rename
  • webpack-stream
  • gulp-run-sequence

gulp-babel
Required to compile ES6

gulp-preset-es2015-without-strict
Preset configuration for Babel that does not add global “use strict”

gulp-uglify
Minifies the compiled Javascript files

gulp-rename
Renames files

webpack-stream
Allows use to use the ES6 “import” statement

gulp-run-sequence
Allows us to run Gulp tasks in sequence.

 

This is the directory structure that I use for my build process.

  • source – The source code that I write.
  • compiled – Intermediate compiled code.
  • www – Production ready code.

These are the Gulp tasks that compile the Javascript.


gulp.task('compile_js', function (done) {
  run('babel', 'pack_js', done);
});

gulp.task('babel', function (done) {
  return gulp.src(paths.es6)
    .pipe(babel({presets: 'es2015-without-strict'}))
    .pipe(rename({extname: '.js'}))
    .pipe(gulp.dest('./compiled/'));
});

gulp.task('pack_js', function (done) {
  return gulp.src('./compiled/app.js')
    .pipe(webpack())
    .pipe(rename({basename: 'app', extname: '.js'}))
    .pipe(gulp.dest('./www/'))
    .pipe(uglify())
    .pipe(rename({extname: '.min.js'}))
    .pipe(gulp.dest('./www/'));
});

 

Now let’s break that down a bit.


gulp.task('compile_js', function (done) {

run('babel', 'pack_js', done);
});

Runs our “babel” and “pack_js” tasks in sequence. This is necessary because “pack_js” would otherwise not get the right file input.


gulp.task('babel', function (done) {
  return gulp.src(paths.es6)
    .pipe(babel({presets: 'es2015-without-strict'}))
    .pipe(rename({extname: '.js'}))
    .pipe(gulp.dest('./compiled/'));
});

This task uses Babel to compile the ES6 code to ES5 so that it is compatible with current browsers.
It will then rename the files, changing the file extension from .es6 to .js and save the compiled files to the “compiled” directory.


gulp.task('pack_js', function (done) {
  return gulp.src('./compiled/app.js')
    .pipe(webpack())
    .pipe(rename({basename: 'app', extname: '.js'}))
    .pipe(gulp.dest('./www/'))
    .pipe(uglify())
    .pipe(rename({extname: '.min.js'}))
    .pipe(gulp.dest('./www/'));
});

This task runs the Babel compiled code through Webpack for packaging. The packaged file is named “app.js” and saved to the “www” directory for production use. This file is then minified and renamed with a “.min.js” extension. Finally the task’s completion function is run.

My gulpfile.js contains other tasks for copying HTML files and Javascript libraries for production and compiling SASS.

 

Here is my entire gulpfile.js so you can see everything in context.


var gulp = require('gulp');
var gutil = require('gulp-util');
var bower = require('bower');
var concat = require('gulp-concat');
var sass = require('gulp-sass');
var minifyCss = require('gulp-minify-css');
var rename = require('gulp-rename');
var sh = require('shelljs');
var uglify = require('gulp-uglify');
var babel = require('gulp-babel');
var webpack = require('webpack-stream');
var run = require('gulp-run-sequence');

var exclude_paths = ['./source/lib/**/*'];

var paths = {
  sass: ['./source/**/*.scss'].concat(exclude_paths),
  es6: ['./source/**/*.es6'].concat(exclude_paths),
  html: ['./source/**/*.html'].concat(exclude_paths),
  lib: ['./source/lib/**/*']
};

gulp.task('default', ['html', 'compile_js', 'sass']);

gulp.task('watch', function () {
  gulp.watch(paths.html, ['html']);
  gulp.watch(paths.sass, ['sass']);
  gulp.watch(paths.es6, ['compile_js']);
});

gulp.task('sass', function (done) {
  gulp.src('./source/app.scss')
    .pipe(sass())
    .on('error', sass.logError)
    .pipe(gulp.dest('./www/'))
    .pipe(minifyCss({
      keepSpecialComments: 0
    }))
    .pipe(rename({extname: '.min.css'}))
    .pipe(gulp.dest('./www/'))
    .on('end', done);
});

gulp.task('compile_js', function (done) {
  run('babel', 'pack_js', done);
});

gulp.task('babel', function (done) {
  return gulp.src(paths.es6)
    .pipe(babel({presets: 'es2015-without-strict'}))
    .pipe(rename({extname: '.js'}))
    .pipe(gulp.dest('./compiled/'));
});

gulp.task('pack_js', function (done) {
  return gulp.src('./compiled/app.js')
    .pipe(webpack())
    .pipe(rename({basename: 'app', extname: '.js'}))
    .pipe(gulp.dest('./www/'))
    .pipe(uglify())
    .pipe(rename({extname: '.min.js'}))
    .pipe(gulp.dest('./www/'));
});

gulp.task('html', function (done) {
  gulp.src(paths.html)
    .pipe(gulp.dest('./www/'))
    .on('end', done);
});

gulp.task('install', ['git-check'], function () {
  return bower.commands.install()
    .on('log', function (data) {
      gutil.log('bower', gutil.colors.cyan(data.id), data.message);
    });
});

gulp.task('git-check', function (done) {
  if (!sh.which('git')) {
    console.log(
      '  ' + gutil.colors.red('Git is not installed.'),
      '\n  Git, the version control system, is required to download Ionic.',
      '\n  Download git here:', gutil.colors.cyan('http://git-scm.com/downloads') + '.',
      '\n  Once git is installed, run \'' + gutil.colors.cyan('gulp install') + '\' again.'
    );
    process.exit(1);
  }
  done();
});

Leave a Reply

Your email address will not be published. Required fields are marked *