20

In the past I've used the revealing module pattern.

function myModule() {
  function foo() ...
  function bar() ...

  return { 
    foo: foo, 
    bar: bar
  };
}

With ES6, this was improved with object shorthand.

function myModule() {
  function foo() ...
  function bar() ...

  return { foo, bar };
}

Now with built-in module syntax, I'm struggling to find the preferred pattern that is most similar to the above.

Option #1 named exports

// export file
function foo() ...
function bar() ...

export { foo, bar };

// import file
import { foo, bar } from './export-file';

foo();
bar();

Option #2 default export/import with destructuring

// export file
function foo() ...
function bar() ...

export default { foo, bar };

// import file
import baz from './export-file';

const { foo, bar } = baz;

foo();
bar();

Option #3 default export/import with name spacing

// export file
function foo() ...
function bar() ...

export default { foo, bar };

//import file
import baz from './export-file';

baz.foo();
baz.bar();

I like Option #1 with the named exports for the simplicity it offers in the "destructuring" import syntax.

import { foo, bar } from './export-file';

I also want to continue to make the module's exported API explicitly defined at the bottom of the exporting file in the export object.

export { foo, bar };
// OR
export default { foo, bar };

I read all the time that default exports are preferred, and so I've been trying to find a preferred pattern that includes default exports, but I'm reluctant to adopt as it just seems more verbose with few advantages (other than the need for name-spacing, or the inclusion of both named and default exports in some cases).

Is there an idiomatic pattern for the revealing module pattern with ES6 module syntax?

sfletche
  • 47,248
  • 30
  • 103
  • 119
  • I personally prefer option #2, as it feels like it closely matches RMP. – evolutionxbox May 16 '17 at 16:13
  • 1
    You could also just directly export the function definitions: `export function foo() { ...`. This question is somewhat opinion based, and here's mine: don't default export "namespace objects", since one can do `import * as baz from './export-file'` for that effect anyway. – Ilja Everilä May 16 '17 at 17:41
  • I'm sorry I missed the "I also want to continue to make the module's exported API explicitly defined at the bottom", but still In my opinion the default should provide something fundamental such as `TheOneClassToRuleThemAll` and possible utilities etc. belong as plain exports, so a user of the module can easily either destructure in the import statement, or do the star import. – Ilja Everilä May 16 '17 at 17:50
  • thanks @IljaEverilä. i'm starting to see that expressed elsewhere as well. "Default exports only are favoured when there is only a single major value to export (e.g. a class)". This sentiment expressed by you and others, has me leaning toward option #1 for now. – sfletche May 16 '17 at 19:04
  • "*I read all the time*" - where? That claim needs to be debunked. Everywhere. – Bergi Jun 05 '17 at 16:54

1 Answers1

14

I read all the time that default exports are preferred

No, they are not. They are simpler and have shorter syntax, and might be used more often (since there are more small, single-export modules), but they are not generally preferred.

Use the right tool for the job. You already know the advantages you want.

Is there an idiomatic pattern for the revealing module pattern with ES6 module syntax?

Yes, Option #1. When you have multiple things to export, always use named exports.

You get both explicit aliasing and tree shaking from the picky syntax

import { foo, bar } from './export-file';

as well as namespaces

import * as baz from './export-file';
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • That's what I needed to hear. Thanks @Bergi! – sfletche Jun 06 '17 at 17:30
  • This is weird. I tried option 1, `function login();` and `export { login };`. When I run it in CLI, I get `export { login }; SyntaxError: Unexpected token export` What? I'm running this through `cucumberJS`. Don't know if my problem relates to the export or the JS package. – Mike S. Apr 02 '18 at 13:28
  • Ok. `cucumberJS` was the problem. I had to require a config hook to support ES6/7 `import/export`. All better. ;-) – Mike S. Apr 02 '18 at 14:32