Writing code in a modular way, has a lot of benefits, like: re-useabilty, smaller compile size, faster development time, etc. This is especially true where the ecosystem is thriving with a lot of libraries like JavaScript.

Writing modules in JavaScript itself can be done in multiple ways, which is what this post is trying to cover.

1. ES6 module

ES6 is the standard JavaScript way of doing modular code. There are actually two ways of doing this in ES6

Named export

Default export

Interestingly, both can be used together. Note that by default this ES6 Module is not supported by Node. Which means you need to use a transpiler like babel.

Why Node is not supporting import out of the box? Well that’s a good question. There is a good article here, but basically node needs to retain the backward compatibility.

But anyhow, let’s have a look at ES6 module …

Named export

const add = (a,b) => {

return a + b;

} export {add};

This is called via

import {add} from "./named-export.js";

or you can give an alias.

import {add as adding} from "./named-export.js";

Notice the {} and the relative path because currently it is in a local JavaScript file. If it is a node module then you can use the module name instead

Fun fact, you can actually remove the .js from the relative path

Default export

const substract = (a,b) => {

return a - b;

} export default substract;

This is called via

import substract from "./default-export.js";

Notice that you don’t need {}

If you want to give it an alias there are ways of doing this

you can use {} and aliasing the default syntax instead of the actual function name.

import {default as substracting} from "./default-export.js";

you can just give it an alias straight away.

import substracting from "./default-export.js";

Note that, you can only have one default per module

Mixed export

So what happened when the two got mixed together?

const multiply = (a,b) => {

return a * b;

}

const divide = (a,b) => {

return a / b;

} export default multiply;

export {divide};

and called via

import multiply, {divide} from "./mixed-export.js";

They still works fine.

2. Node modules

So what if you don’t want to use any transpiler? Then you can still do it using commonjs syntax, which Node supports by default.

const multiplyByTwo = (a) => {

return a * 2;

} const divideByTwo = (a) => {

return a / 2;

} module.exports = {

mbt: multiplyByTwo,

dbt: divideByTwo

}

which is then called with

const multiplyingByTwo = require("./commonjs-export.js").mbt;

const dividingByTwo = require("./commonjs-export.js").dbt;

3. Comparison

So what’s the difference between the major two methods?

Import vs Require

require is actually synchronous. where ES6 import is asynchronous. Which means Node by default will evaluate the code one by one in order.

Static analysis vs code valuation

One big win that you can expect from ES6 modules are the compiled size. Do you know that ES6 modules has strict mode on by default?

This enables ES6 modules to be statically analyzed, which means modules can be probed whether it’s a number , function , etc before the code is evaluated. This enables a better treeshaking. Treeshaking is pretty much only importing the code that is needed from a bundle and dropping the rest. This result in much smaller output size.

Sad truth

If you are using babel to transpile your ES6 code, even though you are meant to have the benefits, you actually don’t get it. Because in the of the day, it got boiled down to commonjs syntax.

However that is fine, because

You are future-proofing your code

It’s nicer looking and easier to read. IMHO

JavaScript as a backend language has a strong root in commonjs syntax, with many languages that compiles to JavaScript (e.g. PureScript) actually compiles into commonjs. This makes things a bit complicated.

Alternative bundler

If you don’t mind not being tied to Node environment (i.e. no Babel, no Webpack), you can actually have a look at other bundler, rollup.js

This enables a much better treeshaking result, just look at the bundled result below.

main.js

import {add} from "./named-export.js";

import {default as substracting} from "./default-export.js";

import multiply, {divide} from "./mixed-export.js";

const _mbt = require("./commonjs-export.js").mbt;

const _dbt = require("./commonjs-export.js").dbt; const a = add(1,2); // 3

const b = substracting(5,3); // 2

const c = multiply(2,3); // 6

const d = divide(4,2); // 2

const e = _mbt(4) // 8

const f = _dbt(10) // 5 console.log(a);

console.log(b);

console.log(c);

console.log(d);

console.log(e);

console.log(f);

bundled.js

(function () {

'use strict'; const add = (a,b) => {

return a + b;

}; const substract$1 = (a,b) => {

return a - b;

}; const multiply = (a,b) => {

return a * b;

};

const divide = (a,b) => {

return a / b;

}; const _mbt = require("./commonjs-export.js").mbt;

const _dbt = require("./commonjs-export.js").dbt; const a = add(1,2); // 3

const b = substract$1(5,3); // 2

const c = multiply(2,3); // 6

const d = divide(4,2); // 2

const e = _mbt(4); // 8

const f = _dbt(10); // 5 console.log(a);

console.log(b);

console.log(c);

console.log(d);

console.log(e);

console.log(f); }());

Now the above code won’t actually run, because the code that are require d are not included in the bundle. However if that code is omitted, it will be bundled flawlessly.

4. Summary

So what’s the take away?

You can use ES6 named export and default export at the same time.

and at the same time. You can put aliases, even with default export.

Without a transpiler like babel , you can still write modular code using commonjs syntax. Though really this is being phased out (or at least there’s intention too).

, you can still write modular code using syntax. Though really this is being phased out (or at least there’s intention too). If you write Node code in ES6 style, you are following the latest and greatest of the JavaScript standard. While probably there’s not much gain in doing so, you are future proofing your code (at least in the frontend part).

Webpack is not your only bundler, try out new things!

is not your only bundler, try out new things! If you ever want to see the code I play with while writing this. It’s available in my playground

5. More readings

Below links helped me a lot when writing this post. So give them a visit

Last but not least, special shout out to fizk for lending a pair of eyes :)