Empower your node.js module with backward compatibility for node < 8

Lost in Space
@tomchentw/software
2 min readNov 1, 2017

It’s really good to see node 8 is now entering LTS. The node contributors have been doing great job bringing latest ES features into node, empowering developers and boosting their productivity. This makes me thinking:

What if we can write code with latest ES features but still have backward compatibility for older node?

The babel team has already done lots of work for us. We can of course compile our code into the most compatible form: ES3. But why wasting time on the trans-piled code when we’re on the platform which supports generator, async functions……and more? This leads us to the experimental babel-preset-env. It allows us to specify the platform we’d like to support, and configure babeloptions so that we get the least transpilation of your code.

These all sounds great for us. But can we do better? Let’s say you’re writing an async function, which gets stable after node ≥ 7.6.0. But we’ve already got generators for node ≥ 4.8.5. What if we want to support all versions for node ≥ 0.12? We’ll have three cases:

  1. node ≥ 7.6.0: don’t transpile, use native
  2. node ≥ 4.8.5 but node < 7.6.0: transpile to generators with regenerator-runtime
  3. node < 4.8.5: transpile to functions emulating generators with switch cases, and run with regenerator-runtime

This means, given one source file, we’ll need to generate three files for different versions. This is not possible given the current babel CLI is one-to-one mapping. So I create a CLI tool:

babel-multi-env

It will generates a set of files based on the desired supported node.js versions. Each source file will become a series of switch cases in the output:

var gte = require("semver").gte;
var version = process.version;

if (gte(version, "8.0.0")) {
module.exports = require("./index__8.0.0__.js");
} else if (gte(version, "6.0.0")) {
module.exports = require("./index__6.0.0__.js");
} else if (gte(version, "4.0.0")) {
module.exports = require("./index__4.0.0__.js");
} else if (gte(version, "0.12.0")) {
module.exports = require("./index__0.12.0__.js");
} else {
module.exports = require("./index__0.10.0__.js");
}

By doing so, we now have the transpiled files running on their latest feature sets. Giving us:

  1. Better performance: less transpilation overhead
  2. Better debugging experience: native async functions are like a breeze

Wanna try it immediately? Go to the GitHub page and see more:

Love to hear your thoughts/feedback!

--

--

Lost in Space
@tomchentw/software

<Tom Chen> Aspie. Introvert. Remoter. Blogger. 「從程式碼的26個英文字母到文章的26個英文字母,開始發現寫作的魅力。」