Search code examples
javascriptnode.jses6-modules

ReferenceError: Cannot access 'Player' before initialization


So I've been using ES6 style syntax with import/export on Nodejs with the ESM module loader. Everything has been fine until I started getting an error pertaining to imports.

Here's the error messages:

joseph@InsaneMachine:~/placeholder2/main-server$ npm start

> [email protected] start /home/joseph/placeholder2/main-server
> nodemon --experimental-modules src/index.mjs

[nodemon] 1.19.4
[nodemon] to restart at any time, enter `rs`
[nodemon] watching dir(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node --experimental-modules src/index.mjs`
(node:16942) ExperimentalWarning: The ESM module loader is experimental.
file:///home/joseph/placeholder2/main-server/src/games/game-player.mjs:3
export default class GamePlayer extends Player
                                        ^

ReferenceError: Cannot access 'Player' before initialization
    at file:///home/joseph/placeholder2/main-server/src/games/game-player.mjs:3:41
    at ModuleJob.run (internal/modules/esm/module_job.js:109:37)
    at async Loader.import (internal/modules/esm/loader.js:132:24)
[nodemon] app crashed - waiting for file changes before starting...

Here are the files Player (Base class):

import PasswordHash from 'password-hash';

import GamesService from '../games/games.service.mjs';

import PlayersService from './players.service.mjs';

import QueueingService from '../queueing/queueing.service.mjs';

export default class Player
{
    constructor(object)
    {
        Object.assign(this, JSON.parse(JSON.stringify(object)));
    }

    get id()
    {
        return this._id.toString();
    }

    equals(other)
    {
        if(other.id != null)
            return other.id == this.id;
        return false;
    }

    checkPassword(password)
    {
        return PasswordHash.verify(password, this.password);
    }

    online()
    {
        return PlayersService.consumer.isPlayerOnline(this);
    }

    inQueue()
    {
        return QueueingService.queued(this);
    }

    inGame()
    {
        return GamesService.getActiveGameByPlayer(this) != null;
    }

    reduce()
    {
        return {
            id: this.id,
            username: this.username,
            email: this.email,
            admin: this.admin,
            online: this.online(),
            in_queue: this.inQueue(),
            in_game: this.inGame(),
        };
    }

    static hashPassword(password)
    {
        return PasswordHash.generate(password);
    }

    static schema = {
        username: String,
        password: String,
        email: String,
        email_confirmed: Boolean,
        admin: Boolean,
    }
}

And GamePlayer (Child Class):

import Player from '../players/player.mjs';

export default class GamePlayer extends Player
{
    constructor(player, token)
    {
        super(player);
        this.token = token;
    }
}

And the heirarchy of the project:

src/
 -- games/
 --  -- game-player.mjs
 --  -- ...
    players/
 --  -- player.mjs
 --  -- ...
 -- ...

How can I fix this import issue, unless this is something else?

Edit: I am not using Babel as far as I know, I am using --external-modules provided by Node. Not sure how that works.


Solution

  • 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.