ReferenceError: Cannot access 'Player' before initialization

I went to the Node.JS forums and asked what could be the issue. Not a babel issue at all, just circular dependencies. For example:

// A.js
import B from './B.js'
export default class A{}
// B.js
import A from './A.js'
export default class B extends A{}

Sorry there wasn't nearly enough information to be able to figure this one out. I got a lot of help on the node.js github and someone looked through my project on github and ended up finding an instance where two modules pointed at each other.


The dependencies in your imports were probably too difficult to resolve, so it gave up, leaving you with Player uninitialized at the point where it is needed to define GamePlayer.

As I mentioned in a comment for another answer, import can be used in a "circular" way, but Node.js can't always untangle the dependencies.

In my case it had no problem with a class in one file and a subclass of that in another file, where both of them import each other, and it's hard to say exactly where it got too complicated, but this is a simplified version of what I had that broke it:

// server.js
import Acorn from './acorn.js';
import Branch from './branch.js';
class Server {
    ...
}

// universe.js
import Acorn from './acorn.js';
import Branch from './branch.js';
import Thing from './thing.js';
export default class Universe {
    things(type) {
       if (Thing.klass[type]) {
           ...
       }
    }
    ...
}

// acorn.js
import Thing from './thing.js';
export default class Acorn extends Thing {
    ...
}

// branch.js
import Thing from './thing.js';
export default class Branch extends Thing {
    ...
}

// thing.js
import Acorn from './acorn.js';
import Branch from './branch.js';
export default class Thing {
    static klass(type) {
        const klass = {acorn: Acorn, branch: Branch};
        ...
        return klass;
    }

    constructor(...) {
        this.type = this.constructor.name.toLowerCase();
        ...
    }
    
    ...
}

I'm using the same code for browsers and server-side Node.js, so I was also transpiling it with Babel, which handled everything fine. But Node may have other constraints that make it more difficult, because, at least as far as importing is concerned, it was on a different track from browsers (and others), and is now trying to bridge the gap. And also the knot may be more tangled than it appears to the naked eye.

In the end I ditched the most circular part of my pattern, which was the part where I refer to the Thing subclasses within Thing itself. I extracted that into a "factory-like" pattern, where the factory knows about the Thing subclasses, but the Thing and its subclasses don't need the factory.