したがって、ESMモジュールローダーを使用してNodejsでインポート/エクスポートするES6スタイルの構文を使用しています。インポートに関するエラーが出始めるまで、すべて順調です。
エラーメッセージは次のとおりです。
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...
プレイヤー(基本クラス)のファイルを次に示します。
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,
}
}
そしてGamePlayer(子供クラス):
import Player from '../players/player.mjs';
export default class GamePlayer extends Player
{
constructor(player, token)
{
super(player);
this.token = token;
}
}
そしてプロジェクトの階層構造:
src/
-- games/
-- -- game-player.mjs
-- -- ...
players/
-- -- player.mjs
-- -- ...
-- ...
これが他のものでない限り、どうすればこのインポートの問題を修正できますか?
編集:私が知る限り、Babelを使用していません。Nodeから提供されている--external-modulesを使用しています。それがどのように機能するかは不明です。
Es2015をBabel構成から削除します。クラスはネイティブES6クラスを拡張し、BabelはESにトランスパイリングします
import
sの依存関係はおそらく解決が難しかったため、あきらめ、Player
を定義する必要がある時点でGamePlayer
を初期化せずに残しました。
別の回答のコメントで述べたように、import
は「循環的」な方法で使用できますが、Node.jsは常に依存関係を解くことができません。
私の場合、あるファイルのクラスと別のファイルのそのサブクラスには問題がありませんでした。両方がお互いにimport
であり、複雑になりすぎた場所を正確に言うことは困難ですが、これは私が持っていたものの簡単なバージョンはそれを壊しました:
// 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();
...
}
...
}
私はブラウザーとサーバー側のNode.jsに同じコードを使用しているため、すべてを適切に処理するBabelでコードを変換していました。ただし、Nodeには他の制約がある可能性があります。少なくともインポートに関しては、ブラウザ(およびその他)とは別の経路にあり、現在はまた、結び目が肉眼で見えるよりも絡まっている可能性があります。
最後に、パターンの最も円形の部分を捨てました。これは、Thing自体の中でThingサブクラスを参照する部分です。これを「ファクトリーのような」パターンに抽出しました。ファクトリはThingサブクラスについて知っていますが、Thingとそのサブクラスにはファクトリは必要ありません。