CommonJSのモジュール内でrequire()を使ってESMを読み込むこと、 ESMのモジュール内からimportを使ってCommonJSを読み込むことは可能だけど、 CommonJSの中からimportを使うことはできない。 ESMの中であれば例えば import { require } from 'nodejs' とかやれば可能になる。
- CommonJSのモジュール内で
require()
を使ってESMを読み込むことは可能 - ESMのモジュール内から
import
を使ってCommonJSを読み込むことは可能 - ESMのモジュール内から
require()
を使うことは不可能ではないimport {require} from 'nodejs' みたいなのが必要
- CommonJSのモジュール内では
import
を使えない
import
ステートメントと import()
関数はまったく違うもの。
import
ステートメントは構文解析の段階で処理されるが、 import()
関数は
require()
関数と同じように実行時に呼び出される。
ただし、import()
関数は require()
関数と異なり、常に Promise
を返す。
Promise
なので await import('hoge')
みたいにやれば同期的に読み込むこともできる。
- unambiguous grammar
- package.jsonにメタデータを記述して、ESMであることを明記する
- ESM向けに*.mjsという新しい拡張子を使う
2番と3番は @yosuke-furukawa さんによる解説がある。 ES Modules と Node.js について
1番は多くのエッジケースがあって実装が難しい。
現時点では *.mjs
のアプローチが実現可能性が高い選択肢とのこと。
複数回 require('foo')
を呼んだとき、同じモジュールのインスタンスが返却されるか、という問題。
あるモジュールを読み込んだとき、他のモジュールの機能をモンキーパッチで置き換えたりするテクニックあ
Node.jsのエコシステムではよく使われている。
あるアプリがCommonJSのモジュールAとモジュールBに依存していて、モジュールAはモジュールBを 拡張するためにモジュールBへの依存があった場合、アプリからモジュールAを読み込んでから モジュールBを読み込んで使ったときと、モジュールAでモジュールBを読み込んで使った場合で 異なる結果になってしまう。
ESMにおいてはこのようなモジュール間のモンキーパッチは難しくなっている。 実行前にimportは読み込み対象をリンクしているし、importは冪等性のために必要。 名前付きimportを使っている場合はモンキーパッチが難しくなる。
これらの冪等性のルールはモックとかテストとかで問題お起こす。 でも解決方法はいくつもあるので、インターセプトは可能である。