バイクとプログラミング

タグ: ES Modules

ExperimentalでもESModulesをNodeで使いたい

TypeScriptで慣れたES ModulesをJavaScriptでも使ってみる

Node.jsをv13.8以上にアップグレードする。

sudo n latest && node -v => v13.8.0

package.jsonに追記する。typeのキー名は変わるかもって話があったようだけど、ほぼこれで確定のよう。

{ "type": "module" }

Rename configuration options to avoid “type” term · Issue #312 · nodejs/modules

使う。拡張子の省略は不可能。TypeScriptではできるので気をつける。

// export.js
export const HELLO_WORLD = 'Hello from module!'

// index.js
import { HELLO_WORLD } from './export.js';
console.log(HELLO_WROLD); // => 'Hello from module!' 

実行時にワーニングが出るが、–no-warningで消すことができる。

ES Modulesではシビアな循環参照

タイトルの通りです。ES Modulesでどハマりしました。

DOMを所定の形式に変換して出力を行う処理を書いていましたが、その中で循環参照が生まれ二進も三進もいかなくなってしまったためメモを残します。

下記のようなファイル群を用意します。Chrome Version 74.0.3729.169で再現。

// script.js
import ModuleA from './ModuleA.js';

new ModuleA().createModuleB();
// ModuleA.js
import ModuleB from './ModuleB.js';

export default class ModuleA {
    createModuleB() {
        return new ModuleB();
    }
}
// ModuleB.js
import ModuleA from './ModuleA.js';

export default class ModuleB extends ModuleA {
}

上記のコードをHTMLから読み込むと下記のようなエラーが出ます。

ReferenceError: can't access lexical declaration `ModuleA' before initialization

まさか循環参照が悪さをしているとは知らず、直感的にはわかりにくいエラーで大変混乱しました。これは普段宣言していない変数を参照しようとすると出るエラーです。

これを解決するには、ModuleA.jsを読み込む前に、あらかじめModuleB.jsを読み込んでおく必要があります。

// script.js
import ModuleB from './ModuleB.js'; //  ここで読み込む
import ModuleA from './ModuleA.js';

new ModuleA().createModuleB();

これで問題なく読み込むことができました。

まだ理解が浅く、なぜこうなるのかを断言できないので詳しくは次回以降にメモできればいいかなと思います。

Powered by WordPress & Theme by Anders Norén