1

I'm converting old javascript into ES6 using babel and webpack. In multiple files I have something like

var BLOG = BLOG || {};
BLOG.myClass1 = ...

and in another file

var BLOG = BLOG || {};
BLOG.myClass2 = ...

So, I've added export {BLOG} to these files, but how can I import BLOG multiple times? It seems it is not allowed, while I'd like to do something like

import {BLOG} from 'file1.js'
import {BLOG} from 'file2.js'

and have myClass1 and myClass2 into BLOG.

Is there a way to do this?

4
  • 1
    You should export the classes, not the namespace. Commented Dec 28, 2018 at 18:12
  • The problem is that my code uses the classes like new BLOG.myClass1, so do I have to rewrite all the code?? Commented Dec 28, 2018 at 18:13
  • Yes, you do. The point of modules is to not use namespaces at all. Commented Dec 28, 2018 at 18:14
  • @cdarwin - To be fair, changing BLOG.myClass1 to MyClass1 (using standard naming conventions) is a really simple search-and-replace. On any *nix, you could throw sed at it... Commented Dec 28, 2018 at 18:17

2 Answers 2

4

So, I've added export {BLOG} to these files, but how can I import BLOG multiple times?

You'd have to use different import bindings for them:

import {BLOG as BLOG1} from 'file1.js';
import {BLOG as BLOG2} from 'file2.js';

...then use BLOG1 and BLOG2. Or if that bothers you, add

const BLOG = Object.assign({}, BLOG1, BLOG2);

after the imports and keep using BLOG.

If you have cyclic dependencies, it's possible that BLOG1 and BLOG2 may not be fully-populated right away. With true import/export, in that situation, the objects you receive will have their properties, but those properties won't be initialized yet. So with true import/export or a good simulation, you could use accessor properties to handle it:

// In a true ES2015+ module environment, or a simulated one that
// creates the properties up-front like the real one does
const BLOG = (() => {
    const b = {};
    for (const blog of [BLOG1, BLOG2]) {
        for (const key of Object.keys(blog)) {
            Object.defineProperty(b, key, {
                get(name) {
                    return blog[name];
                }
            });
        }
    }
    return b;
})();

(Obviously, you'd wrap that in a function and reuse it.)

In a simulated module environment that doesn't create the properties up-front like the real one would, you could use a proxy (though of course, if you're going to run this in a pre-ES2015 environment, it won't have Proxy):

const BLOGS = [BLOG1, BLOG2];
const BLOG = new Proxy({}, {
  get(target, propName, receiver) {
    const b = BLOGS.find(b => propName in b) || target;
    return Reflect.get(b, propName, receiver);
  }
});

Then, properties added to BLOG1 and BLOG2 after-the-fact still get resolved correctly.

All of which is an awful lot of bother just to avoid the search-and-replace mentioned next.


But: Instead of exporting BLOG, as SLaks says, export the classes, and import those. There's no need for a "namespace object" when you're using proper modules.

export { myClass1 };

and

export { myClass2 };

and then

import { myClass1 } from "file1.js";
import { myClass2 } from "file2.js";

You can even export the class as you define it, either:

export function myClass1() { /* ... */ }

or if using class notation:

export class myClass1 { /* ... */ }

Changing new BLOG.myClass1 to new MyClass1 across multiple files is a really simple search-and-replace. On *nix, you could throw sed at it and do an entire directory tree...


Side note: The overwhelming convention in JavaScript is that constructor functions (often loosely called "classes," e.g., functions you use with new) are written with an initial upper case character. E.g., MyClass1 and MyClass2.

Sign up to request clarification or add additional context in comments.

9 Comments

Do you agree with Slaks when he says that I have to rewrite all my code that uses calls like new BLOG.myClass1?
@cdarwin - Hit refresh. :-) You don't have to, but you may want to...
I'm sorry, but I don't understand. How can I leave my client code unchanged if I import BLOG as BLOG1? It seems to me that I have to replace my code with new BLOG1.myClass1, am I wrong? Even if I export/import the classes without the namespace, I cannot do things like new BLOG.myClass1 but I have to do new myClass1 (rewrite my code again)
@cdarwin - Yes, you'd have to use BLOG1.myClass1 (or do the const BLOG = Object.assign({}, BLOG1, BLOG2); thing I added when you raised the concern in the question comments about having to update your code). But again: Updating that code is really, really simple with any reasonable text editor (or sed or similar tool). You aren't rewriting anything. You're doing a search-and-replace.
const BLOG = Object.assign({}, BLOG1, BLOG2); is a nice suggestion, I think I'll use this. However you're right, this is search and replace, but I have the fear I could make a mess.
|
0

You need to use import in the following manner

{BLOG as variable name} from file

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.