Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?

Minimum Viable Async with Node 6

With the release of Node 6.0.0, the surface of code that needs transpilation to use ES6 features has been reduced very dramatically.

This is what my current workflow looks like to set up a minimalistic and fast microservice using micro and async + await.

The promise

To write a service that displays the current Bitcoin price we should be able to write an lib/index.js like so:

import request from 'request-promise';
const URL = 'https://api.bitcoinaverage.com/ticker/global/USD';
export default async () => {
  const price = await request(URL, { json: true });
  return `The price is ${price.last} as of ${price.timestamp}`;
}

and to run it with node run.js:

import serve from 'micro-core';
import api from './lib';
serve(api).listen(8080, (err) => {
  if (err) throw err;
  console.log('Listening on *:8080'); 
});

Minimum viable Babel

The only notable feature that’s missing in V8 as far as ES6 support is import and export (i.e: the module syntax).

async and await is coming to V8 but it’s not ready yet. This means that our babel configuration in package.json is simply down to two modules.

{
  "babel": {
    "plugins": [
      "transform-es2015-modules-commonjs",
      "transform-async-to-generator"
    ]
  }
}

Since we can compile to generators instead of regenerator and Promise is built-in, Babel can do exclusively the job it was designed to do: transform code. No babel-runtime!

babel-node is back

If you’ve used babel-node in the past you probably noticed it could be slow and resorted to more complicated pipelines with gulp or make.

Since the amount of work babel has to do has now been decreased to a minimum, it’s now feasible to run your programs with it again!

During development you could then execute.

$ babel-node run.js

When you make a change, you just re-run your code without an explicit build step and with great support for source maps.

Production optimizations

To optimize startup time to the fullest, you probably still want to pre-compile before you ship. For that, you can define a task like this:

"scripts": {
  "build": "babel lib --out-dir dist"
}

If you plan to publish, make sure that you only publish that directory:

"files": ["dist"],
"scripts": {
  "prepublish": "npm run build" 
}

Finally, micro-core gives you a little binary to launch the exported microservice easily:

"scripts": {  
  //
  "start": "micro-serve -p 3000 dist/"
}
// NOTE: this file belongs in `lib/`! [gist limitation]
import request from 'request-promise';
const URL = 'https://api.bitcoinaverage.com/ticker/global/USD';
export default async function (req, res) {
const price = await request(URL, { json: true });
return `The price is ${price.last} as of ${price.timestamp}`;
}
{
"name": "mva",
"version": "0.0.1",
"description": "a simple example showing off micro + minimum babel settings",
"dependencies": {
"micro-core": "0.3.0",
"request-promise": "3.0.0"
},
"files": [
"dist"
],
"babel": {
"plugins": [
"transform-es2015-modules-commonjs",
"transform-async-to-generator"
]
},
"scripts": {
"start": "micro-serve -p 8080 dist/",
"build": "babel lib --out-dir dist",
"prepublish": "npm run build"
},
"devDependencies": {
"babel-plugin-transform-es2015-modules-commonjs": "6.8.0",
"babel-plugin-transform-async-to-generator": "6.8.0",
"babel-cli": "6.8.0"
}
}
import serve from 'micro-core';
import api from './lib';
serve(api).listen(8080, (err) => {
if (err) throw err;
console.log('Listening on *:8080');
});

taoeffect commented May 18, 2016 edited

What about this "syntax-async-functions" plugin? That's not mentioned in the document?

EDIT: apparently it's not necessary.

What do you think about having sourcemaps in production?

babel-runtime isn't actually the problem, it just reduces a bunch of code duplication. Are you thinking of babel-runtime/regenerator?

leo commented Jul 28, 2016

@taoeffect Fixed!

This example keep asking me for dist file, not sure what kind error is, can some show me how to runt the little program?

Listening on http://localhost:8080
TypeError: fn is not a function

@joshvoll if you run npm run build it will generate the necessary file in the dist folder, and then you just need to write npm run start and you're good to go.

obiwarn commented Jul 20, 2017

Fantastic read. Could this be updated to Node v8?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment