namespace with ES6 modules
Asked Answered
V

2

8

How do I assign a namespace using ES6 modules? I'd like to do with for example jQuery does, where the namespace is $ but doing it the intended ES6 way. All my modules are structured in separate files which export the classes/functions/whatever as default (e.g. export default class Pikachu). How do I import it into another (main) file so that a user can access this class using e.g. Namespace.Pikachu?

I have come to understand that it might have to do with named exports but I'm not quite totally sure how. Any help please?

Vigilance answered 8/2, 2016 at 2:4 Comment(3)
See second example.Oarlock
You just export an object with a Pikachu property, as always. But why would you do that, instead of letting the user import … from '…/pikachu' whatever and in whichever way he chooses?Cripps
@usandfriends thanks! i must have accidentally skipped it over when reading that article!Vigilance
E
5

If you use modules, you don't need namespaces.

The point of namespaces is to prevent conflicts between different files that define the same names.

Modules eliminate this problem entirely by letting the callsite choose a name to give each module it needs.

You just export a simple object with the things you want, and other files can import that to any name they choose.

Edwardoedwards answered 8/2, 2016 at 2:12 Comment(2)
Well I wouldn't say modules eliminate the problem entirely, they just move it from the (global) scope level to the naming (conventions) and hierarchy of module identifiers.Cripps
I suppose I was just somewhat confused in between learning all this -- I should have known! Thanks!Vigilance
U
1

It's an old question with an accepted answer, but I feel that one should mention that module namespaces are nevertheless supported to some extent. As was already noted by the comment of @rgajrawala , an import of all exported variables from a module via "*" always creates such a namespace. (see here on MDN)

import * as Namespace from "./myModule.js";
console.log(Namespace.default); // in the OP, Pikachu is exported as default
//console.log(Namespace.Pikachu); // if Pikachu wasn't exported as default

Similarly, dynamic imports always return a Promise for a module-namespace:

const Namespace = await import("./myModule.js");
console.log(Namespace.default);
//console.log(Namespace.Pikachu);

For more details on what kind of object such a namespace is, see this SO answer

A third alternative (in general not preferable, see comments to this answer) is to create a namespace already in the module and make it the default export:

// within "./myModule.js"
export default {Pikachu, otherVariable, ...};
// within the other module
import Namespace from "./myModule.js";
console.log(Namespace.Pikachu);
Ultann answered 8/2 at 11:4 Comment(5)
"create a namespace already in the module and make it the default export" - please don't. That prevents named imports, messes with tree shaking, and is unnecessary verbose.Cripps
@Cripps it doesn't prevent named imports. All these variables can still be exported separately in addition, if one wants. I'm not saying, it's a good thing to do, but I could imagine use cases, were it might be useful to bundle a subset of all exports as a default export. But what do you mean with "tree shaking"?Ultann
Ah but if they're separately exported as named (and they should!), that's unnecessary duplication and ambiguity. Sure I can imagine use cases where it's useful to bundle a subset of the exports into an object, but these are rather exotic not the standard - and I would argue it would be cleaner to create that object only in separate module.Cripps
"Tree shaking" refers to an optimisation in bundlers that omit dead code when they know it's not imported anywhere.Cripps
yes, I agree with the verboseness. In any case, this last alternative was mostly for completeness. Thanks for your remarks!Ultann

© 2022 - 2024 — McMap. All rights reserved.