Moving to ES2016/Webpack/Babel from RequireJS/Grunt

In this post I will be detailing some of the steps I took to convert several of my personal projects code bases from Asynchronous Module Definition (AMD) to the new JavaScript module syntax along with the move to WebPack.

TL;DR;

I have always developed code using some type of modular approach. At one point I developed my own mechanism that used jQuery Deferreds to handle the resolution of dependencies – fun times. When I learned about the existence of RequireJS, I quickly embraced its usage for web applications which allowed for me to keep apps structured as small modules that are loaded on demand and increased re-usability by allowing me to reuse several modules across different projects.  But web development is moving at a fast pace and with it new ways of working are being introduced all the time which warrant an open mind into new approaches.

The most important development with regards to modules was that the language itself (ES2015) has now standardized how to define them. Let’s look at what a module looks like in AMD and with ES2015 (JavaScript v6):

AMD Module


define(["Widget", "less!./myWidget"], function (Widget) {

return class MyWidget extends Widget {...};

});

ES2015 Module


import Widget from "Widget"

import "./myWidget.less"

export class MyWidget extends Widget {...}

As you can see, the syntax is cleaner and more declarative. There is also not much to change in order to convert existing AMD modules to ES2015 modules:

  1. you remove the define() wrapper,
  2. define your imports (dependencies), and
  3. explicitly name your export(s)

In order to target the widest browser support possible, the above code written in ES2015 will need to be transpiled to ES5 (the version of JavaScript supported by all major browsers).  That is where Babel comes in (I’ll touch on loader plugins further below).  It will convert your future proof code to a version that can run on all current browsers by transpiling it to ES5.  You could also use a loader right in the browser – like SystemJS – but I would I not advise it for production use due to the heavy work it would be tasked to doing.

A New Way to Build

Webpack is a module bundler: it looks at your code usage and gathers up all the modules it uses, and generates static resources that are then used to run your app. It’s very similar to RequireJS’s compiler (r.js) were you define the entry point and then it does the rest of the magic.  In addition to doing this, webpack also has a development server with an awesome reloading function (HMR) that makes coding for the web even more enjoyable. This, along with Babel and NPM scripts, has now replaced my use of RequireJS, r.js and Grunt, and simplified my build process.

Note that the use of Grunt or a similar task running library is something that can still be used today to handle non-build related tasks, since Webpack now takes care of that. Personally, I have found that using NPM scripts is sufficient and by doing so, it removes the complexity of having yet another library to learn and debug when things don’t go right.

Migrating to ES2015 modules

So here are the primary steps I took to convert my existing code bases:

Add file extensions to non-javascript file dependencies

Some loader plugins – like the RequireJS Less loader – allow you to define paths to files without having to specify the file extension, ex: ‘less!./myWidget’. Although you could fight with your webpack.config file to make this work, I still found  this caused some issues in using webpack, specially with the “pipe” approach to loader plugins – an awesome feature of Webpack.

My solution: search for all usages  of loader plugins that define file paths with no file extension, and add a file extension to it. This took are of my Less files, Text and HTML files that were loaded with the Text plugins.

Remove Loader Plugins from dependency paths

When converting to webpack, you will need to configure the tool to use the loader plugins that your prior AMD code base was configured for.  In my case, I was mostly using the Less, Text and Handlebars loaders. One other change that will pay off over time is the removal of loader plugins from your code and moving that to your build configuration – webpack.config. It also helps to remove the clutter from our code and ensure that your source remains focused solely on pure code and not tooling.  Before doing this, ensure that the prior tip – on ensuring file extensions are defined for non-JavaScript files – is done, since the triggering of loader plugins are normally done using the file extension.

My solution: setup webpack to loader plugins, and then remove the loader prefix from your AMD modules.

Use a Tool to Help Migrate

The first thing I looked for was a tool that will do this for me, and sure enough I found amdtoes6 NodeJS module. You feed it a directory and it process the files found these and converts them to ES2015 modules – essentially performing the 3 steps I highlighted above.

So now that your RequireJS dependencies were adjusted (removal of loader plugins and adding file extensions to non-JavaScript files), running this tool will convert them all to ES6 modules where each dependency becomes an import whose local variable is the same as the one you had defined in the AMD factory function.

Hope this posts helps you moving your project forward to to take advantage of new tools and technology.

A few links for further reading:

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s