Write your JS library in ES6

Finally the ECMAScript 6 (or ES6, or ES2015) specification came to an end and even without having native support for it we’re all excited about using it in current browsers with transpilers! It’s not just a matter of using the latest, but the best.

So you might be wondering if you should use ES6 for your new library or for the next version of it. Of course! There’s no doubt, this is where the future is going. But then, How do you keep using it in existing scripts and while not having to maintain two versions? The aim of this short post is to show one way to do it as an example. Check it out!.

Working with ES6 in ES5 browsers

As you might already know, you can use Babel with Browserify, Webpack or other tools to automate the transpilation. Please google “babel browserify” (or the tool of your preference) and read some in depth tutorials. I found this browserify tutorial very useful. As this is already documented in many other sources and the aim of this post is not to duplicate that content, you should read the topic before this post.

Classes and functions

One of the main advantages I see in ES6 is the easier way of working with and thinking in classes, as in any other OOP language. And for all of us that have some static functions that make our life easier, let’s continue counting on them in the private scope of ES6 and the public scope of ES5 when needed.

Example: A mouth with its jaws and their teeth

This is taken from a real world project I’ve just developed for a German client. It is about a 3D (WebGL/ Three.js) mouth with its jaws and teeth.

We defined many classes, among them:

  • Scene
  • Jaw
  • Tooth

An instance of a Scene has 2 instances of a Jaw (upper and lower) and each have 16 instances of Teeth. Each class is in a single file. For instance, the “jaw3d-scene.js” file contains the main Scene class, requires 2 more classes (Jaw and Tooth) and some static functions:

var __s__ = require('./support-functions.js');
var Jaw3DJaw = require('./jaw3d-jaw.js');
var Jaw3DTooth= require('./jaw3d-tooth.js');
export class Scene {
constructor () {
this.upperJaw = new Jaw3DJaw.Jaw(1);
this.lowerJaw = new Jaw3DJaw.Jaw(0);
        ...
__s__.addEventLnr(this.node, "click", onClickFn);
    }
    getTooth (nameUNS) {
...
    }
}

The Jaw and Tooth classes look similar, except that they have less dependencies at the top.

The “support-functions.js” file that contains the static functions looks like the following code:

//Cross browser addEventListener
export let addEventLnr = (obj, type, fn) => {
if (window.attachEvent) {
obj["e" + type + fn] = fn;
obj[type + fn] = function () { obj["e" + type + fn](window.event); };
obj.attachEvent("on" + type, obj[type + fn]);
} else {
obj.addEventListener(type, fn, false);
}
};
//function to make numeric sorts / Array.sort(sortNumber)
export let sortNumber = (a, b) => { return a - b; }
...

To use this code in the current ES6-unsupportive browsers, you should use Grunt (or Gulp) to transpile everything to ES5. But before, to use it in ES6 you might need an “app-demo.js” script that makes use of this new library. This is how you can create it:

var __s__ = require('./support-functions.js');
var Jaw3DScene = require('./jaw3d-scene.js');
jaw3DScene = new Jaw3DScene.Scene();
...
var t16 = jaw3DScene.getTooth("16");
...

Your library is now working in a ES6 project! But what about using it on old ES5 scripts? Ok, following the old approach of exposing a window global object (or function), like Modernizr, Sizzle, THREE, TweenLite, etc. we’re going to do the same. You need to create another JS script (let’s call it my-library.js) that does exactly this, expose the code to window global objects:

var __s__ = require('./support-functions.js');
var Jaw3DScene = require('./jaw3d-scene.js');
var Jaw3DJaw = require('./jaw3d-jaw.js');
var Jaw3DTooth= require('./jaw3d-tooth.js');
//INIT 
window.Jaw3D = {
Scene: Jaw3DScene.Scene,
Tooth: Jaw3DTooth.Tooth,
Jaw: Jaw3DJaw.Jaw
};
window.MySupportFunctions = {
addEventLnr: __s__.addEventLnr,
...
};

Add this transpiled script to your “.js” dependencies in your HTML as you would do with Modernizr, Sizzle, etc. or to your bundle, and you’re ready to go!

Finally, not to have two Grunt builders to create your demo-app and the window-exposer version, just tell Grunt to make an extra build at the same time (in Gruntfile.js):

files: {
"./build/app-demo.js": ["./src/app-demo.js"],
"./build/my-library.js": ["./src/my-library.js"]
}

So why not build your next javascript library or version in ES6!