2

I'm just getting into using es 6 modules for front end development (we don't use Node at all), and am wondering if this pattern we've come up has any pitfalls or if you have any improvement suggestions. I guess it uses some of the rationale behind the revealing module pattern, in es6 modules. I ask this question because most es6 module "how to guides" I've seen do something different, which I'll note at the very bottom of the question.

Some things to note:

  • We (are pretty sure we) want each module to only export one thing. This is listed as a best practice in the Airbnb style guide, and we've just found it nice overall when consuming npm packages
  • We really like naming methods with "public" and "private" (guess we should be using _ for private methods as that's newer best-practice), it makes it easy to see what is available outside of the module

module.js:

// publicly available method
function publicHello() {
    return 'Hello';
};

// publicly available method
function publicHelloWorld(){
    const a = publicHello();
    const b = privateProcessWorld(a);
    return b;
};

// private method
function privateProcessWorld(x) {
    return x + ' world';
};


// create an object to export, containing only the public methods
// note that we rename them here as well, making them easier to consume
const exp = {
    h: publicHello,
    hw: publicHelloWorld,
};

// export the object as default so it can be used in an unnamed import
export default exp;

to consume the module:

import whatever from "module.js";

whatever.h();   // "Hello"
whatever.hw();  // "Hello world"

What I have seen in most "es6 module how to" guides is this:

var utils = {
  generateRandom: function() {
    return Math.random();    
  },
  sum: function(a, b) {
    return a + b;
  }
};

export default utils;
KayakinKoder
  • 3,243
  • 3
  • 23
  • 37
  • The second one is shorter and enshures a good structure. However there are many good usecases for the first pattern too. And instead of `public / private` its a common pattern to annotate peivate ones with a `_` or `#` before – Jonas Wilms Dec 07 '17 at 21:19
  • @JonasW. could you expand on what you mean by "ensures a good structure" ? I guess my first question in that regard would be where do private methods/vars go, above or below var utils? Also yes we should say _ is best practice; when we started using public/private long ago I guess we just never changed our ways. – KayakinKoder Dec 07 '17 at 21:26
  • 1
    "*We want each module to only export one thing. This is listed as a best practice in the Airbnb style guide*" - no, airbnb misunderstood how modules work. [Please don't do this](https://stackoverflow.com/a/44373830/1048572). – Bergi Dec 07 '17 at 21:35

1 Answers1

3

We (are pretty sure we) want each module to only export one thing.

No. Don't do this. If your module provides multiple functionalities, like a bunch of helper functions, and does not provide a single function or single class or something, you should also export multiple things.

Just change your default export to

export {
  publicHello as h,
  publicHelloWorld as hw,
}

and your import to

import * as whatever from "module.js";
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Awhile back during my research I read the stack answer you linked to in your comment, and have read a few other answers similar to yours here, but I've never seen explicit reasons *why* we should export multiple things. What's the reasoning, just that "they do different things so they should be named differently"? (also, npm packages from "big companies" that we use [filestack, opentok ...] all seem to export one thing I think, so I've just assumed. I could look at filestack's api and says it does "one thing" -- lets us use their api -- or multiple things: upload, edit image, etc) – KayakinKoder Dec 07 '17 at 21:43
  • a) It's shorter b) it allows you to use individual named imports (`import {h, hw} from "module.js";`) if you want to do that c) it helps tree shaking (at the build stage) and similar optimisations (also in the engine) d) this is exactly the use case that named exports were designed for – Bergi Dec 07 '17 at 21:46
  • Thanks, much appreciated. The only benefit I would really care about of those three would be c), and https://rollupjs.org/ handles tree shaking without named imports. So I guess I'm still not convinced :/ Edit -- maybe one argument would be that when we can eventually use modules in browser, they may need (or may process faster) named exports to handle tree shaking. And you added d), so if the spec says so, that's generally a good reason. – KayakinKoder Dec 07 '17 at 21:48
  • @KayakinKoder It doesn't seem so: "*[Exporting functions individually is the way to make them tree-shakeable.](https://github.com/rollup/rollup/issues/645#issuecomment-271105045)*" (you don't need to *import* them individually as well, namespace imports like the one shown in my answer are optimisable just as well). Of course d) on it's own is a weak argument, but it does imply the other ones :-) – Bergi Dec 07 '17 at 21:57
  • I stand corrected, thought I had tested that with rollup. Thanks much – KayakinKoder Dec 07 '17 at 22:13