ES7 with express and grunt
written on December 3, 2015I 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, throw
s 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
}));