Blog

ES7 with express and grunt

I have been recently in process of getting used to fast prototyping using Node.js and Express. One major thing that gets really frustrating when dealing with async calls is the call back hell:

db.get(function (err, info) {
        if (err) {
            // handle err

        } else {
            // do sth with info
        }
    });

a better version is promise style (node > 4.x):

db.get()
    .then(info => {
        // do sth with info
    }, err => {
        // handle err
    });

not a bad improvement but still can get messy to handle each error callback.

The ES7 has the best solution:

try{
    let info = await db.get();

} catch (err) {

}

Where you can have one single catch block for a lot of async calls. Its getting sexy but the biggest problem is that this can not be used even with latest node (currently v5.1.0).

Using a shim

Babel can help you here. I’m not going to introduce Babel here, nor I’m going through all the setup needed for express and co. Following steps show you how you can use ES7 in a project created by express generator and served using grunt-express-server.

following has been tested with node 5.1.0 and express 4.13.1.

First installing dependencies:

$ npm i --save babel-cli
$ npm i --save babel-preset-es2015
$ npm i --save babel-preset-stage-0
$ npm i --save babel-register

then creating a shim bin/es7-shim script which sets up the necessary babel translator and then calls express 4’s bin/www script created by express generator:

#!/usr/bin/env node

require("babel-polyfill");
require("babel-register")({
    presets: [
        "es2015",
        "stage-0"
    ]
});
require('./www');

Note not adding require("babel-polyfill"); line, results in some ugly error.

and finally changing express-server grunt config to use our shim:

        express: {
            options: {
            },
            dev: {
                options: {
                    script: 'bin/es7-shim',
                    debug: true
                }
            }
        },

and thats it!

Appendix

If your whole goal was to run ES7 ahead of time, then you did it ;) now go and sleep well. However if you are going to use await in some express routes and all of a sudden you forget to write a try/catch block (because to be honest, throws still does not really belong to JavaScript world) then you will end up with unanswered requests.

To prevent this I found an interesting way to improve your routes here. basically we wrap the router function in a generic handler.

To do it first define the wrapper:

let wrap = fn => (...args) => fn(...args).catch(args[2]);

then you have to change your routes from this:

router.get('/', function (req, res, next) {
   // async calls and all ES7 cool stuff with unhandled exceptions here
});

to this:

router.get('/', wrap(async function (req, res) {
   // async calls and all ES7 cool stuff here
}));
comments powered by Disqus