Search our website

From the blog

Implementing Babel via Grunt

Author · Scott Davis
Published · May 18, 2018
Last modified · Mar 20, 2024
Category · Developer
Read time · 3 min

Have you ever felt your excitement build after seeing some cool, new JavaScript feature only to find out that it isn’t supported in all of the browsers that your app supports? Bummer! If you’ve ridden this rollercoaster of emotions before, Babel, opens in a new tab might just be your favorite new tool.

Babel allows you to write your code with all of the features that the cool-kids are using such as async/await, opens in a new tab, template literals, opens in a new tab, arrow functions, opens in a new tab, const, opens in a new tab & let, opens in a new tab variable declaration, and many more, opens in a new tab. It does this by compiling your modern code to backwards-compatible code that is supported in all major browsers.

It does take a bit of setup but it’s well worth the investment of time. Once you start using some of these newer language features you’ll wonder how you ever got by without them. Here are the steps that we take when “babelifying” our grunt-based projects, opens in a new tab:

  1. Install node dependencies:
npm i grunt-babel babel-preset-latest babel-plugin-transform-remove-strict-mode --save-dev

We use the last plugin to remove the "use strict" that Babel writes to all output files. This is because dojo 1 has issues, opens in a new tab with strict mode, opens in a new tab.

  1. Move the src/app folder to _src/app as well as any other files in src that are committed to source control such as index.html. This is because we are going to git ignore the src folder entirely since it will only hold Babel output as well as other dependencies.

  2. Update .gitignore to ignore the entire src directory. This is a major simplification, opens in a new tab from the previous version which had to ignore each bower dependency explicitly.

  3. Add babel grunt task configuration:

    babel: {
        options: {
            sourceMap: true,
            presets: ['latest'],
            plugins: ['transform-remove-strict-mode']
        },
        src: {
            files: [{
                expand: true,
                cwd: '_src/app/',
                src: ['**/*.js'],
                dest: 'src/app/'
            }]
        }
    }
  1. Add a copy task config for copying all of the non-js files from _src to src:
    copy: {
        dist: {
            files: [{expand: true, cwd: 'src/', src: ['*.html'], dest: 'dist/'}]
        },
        src: {
            expand: true,
            cwd: '_src',
            src: ['**/*.html', '**/*.css', '**/*.png', '**/*.jpg', 'secrets.json', 'app/package.json'],
            dest: 'src'
        }
    }
  1. If you are using a CSS pre-processor you may want to repoint it’s grunt task configuration to the _src folder.

  2. You’ll also want to repoint the linter, watch, and bump tasks to the _src folder.

  3. Add the new babel and copy tasks to the watch task config. Using grunt-newer, opens in a new tab will make things more efficient.

  4. Add a new clean sub task to clean src/app:

    clean: {
        build: ['dist'],
        deploy: ['deploy'],
        src: ['src/app']
    }
  1. Add babel, clean and copy tasks to the build and default tasks:
grunt.registerTask('default', [
  'eslint',
  'clean:src',
  'babel',
  'stylus:src',
  'copy:src',
  'connect',
  'jasmine:main:build',
  'watch',
]);
grunt.registerTask('build-prod', [
  'clean:src',
  'babel',
  'stylus:src',
  'copy:src',
  'newer:imagemin:main',
  'dojo:prod',
  'uglify:prod',
  'copy:dist',
  'processhtml:main',
]);
  1. You may also need to update your .eslintrc file to be at the correct Ecma version that you’ll be writing your code in
parserOptions: {
  ecmaVersion: 8;
}

Here’s a commit that contains most of these steps, opens in a new tab. It seems like I always forget a few things. :)

Writing modern JavaScript is fun and it encourages better programming patterns. I hope that you’ll give Babel a try.