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 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, template literals, arrow functions, const & let variable declaration, and many more. 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:

  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 with strict mode.

  2. 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.

  3. Update .gitignore to ignore the entire src directory. This is a major simplification from the previous version which had to ignore each bower dependency explicitly.

  4. 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/'
             }]
         }
     }
    
  5. 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'
         }
     }
    
  6. If you are using a CSS pre-processor you may want to repoint it’s grunt task configuration to the _src folder.

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

  8. Add the new babel and copy tasks to the watch task config. Using grunt-newer will make things more efficient.

  9. Add a new clean sub task to clean src/app:
     clean: {
         build: ['dist'],
         deploy: ['deploy'],
         src: ['src/app']
     }
    
  10. 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'
     ]);
    
  11. 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. 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.