J'ai donc utilisé la syntaxe de style ES6 avec import/export sur Nodejs avec le chargeur de module ESM. Tout va bien jusqu'à ce que je commence à recevoir une erreur concernant les importations.
Voici les messages d'erreur:
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...
Voici les fichiers Player (classe de base):
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,
}
}
Et GamePlayer (classe enfant):
import Player from '../players/player.mjs';
export default class GamePlayer extends Player
{
constructor(player, token)
{
super(player);
this.token = token;
}
}
Et l'héritière du projet:
src/
-- games/
-- -- game-player.mjs
-- -- ...
players/
-- -- player.mjs
-- -- ...
-- ...
Comment puis-je résoudre ce problème d'importation, sauf s'il s'agit d'autre chose?
Edit: Je n'utilise pas Babel pour autant que je sache, j'utilise --external-modules fournis par Node. Je ne sais pas comment cela fonctionne.
Supprimez es2015 de votre configuration Babel. la classe étend la classe ES6 native et les transpiles Babel à ES, ce qui cause probablement le problème
Les dépendances dans vos import
étaient probablement trop difficiles à résoudre, donc il a abandonné, vous laissant avec Player
non initialisé au point où il est nécessaire de définir GamePlayer
.
Comme je l'ai mentionné dans un commentaire pour une autre réponse, import
peut être utilisé de manière "circulaire", mais Node.js ne peut pas toujours démêler les dépendances.
Dans mon cas, cela n'a eu aucun problème avec une classe dans un fichier et une sous-classe de celle-ci dans un autre fichier, où les deux import
l'un de l'autre, et il est difficile de dire exactement où cela est devenu trop compliqué, mais c'est une version simplifiée de ce que j'avais qui l'a cassé:
// 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();
...
}
...
}
J'utilise le même code pour les navigateurs et Node.js côté serveur, donc je l'ai également transpilé avec Babel, qui a tout géré correctement. Mais Node peut avoir d'autres contraintes qui le rendent plus difficile, car, au moins en ce qui concerne l'importation, il était sur une piste différente de celle des navigateurs (et d'autres), et essaie maintenant de et le nœud peut être plus emmêlé qu'il n'y paraît à l'œil nu.
À la fin, j'ai abandonné la partie la plus circulaire de mon modèle, qui était la partie où je me réfère aux sous-classes Thing dans Thing lui-même. J'ai extrait cela dans un modèle "semblable à une usine", où l'usine connaît les sous-classes Thing, mais la Thing et ses sous-classes n'ont pas besoin de l'usine.