自分的ESM(ES Modules)対応方法

投稿日: 更新日:

はじめに

ゴシップサイトブロッカー他ES Modules(ESM)に対応するのをいろいろやってきたり、最近Node.js関連の開発が多くていろいろ試行錯誤した結果、こうしたらいいのかなぁというのを自分なりにまとめてみます。あくまで利用者視点なので、ライブラリの作成者には役立ちません。あとNode.jsを前提にしています。

原則

ES Modules対応するときにはまず「CommonJSでは書かない」というのを原則としています。 当たり前と言えば当たり前なんですが、とにかく「CommonJSでは書かない」というのは大前提です。 なので以下の話は全て「CommonJSでは書かない」という話です。

CommonJS前提のライブラリやツールを選ばない

一番重要なのはライブラリやツールの選定です。 CommonJSでしか使えないライブラリやツールを最初から選ばないことです。

といってもライブラリは基本的にCommonJSで例が書かれていても、ESMで書けます。 require記法をimport記法に変えればそのまま動くものがほとんど(全部?)です。

あとloadshはlodash-esがあるのでこちらを使いましょう。適切に使えばTree Shakingが効いてサイズも小さくなります(lodash自体をやめる話もあるがそれは別の話)。

しかし最終的にこの2つのツールは乗り換えました。

  • Jest → Vitest
  • ts-node → tsx

特にJestはIssueにありますが、mockが使えないのが致命的です。 頑張るよりVitestに乗り換えたほうが絶対いいです。

ts-nodeもtsxに乗り換えたほうが幸せになれると思います。watchモードがあるのもいいです。

一部の定数は回避策を適用

__dirname, __filename が使えない問題は回避策があります。

設定ファイルのみは例外で .cjs にする

そもそもCommonJS前提のライブラリやツールを選ばないのですが、例外は一部のツールの設定ファイルです。 具体的にはESLintdependency cruiserが該当します。

これらの設定ファイルはCommonJSの module.exports を使っていますが、拡張子を .cjs にすることで回避しています。 設定ファイルは独立しているのと、対応できないものも多いので。

それでも次のエラーが出ますが、これは // eslint-disable-next-line no-undef として無視させています。

path/to/.eslintrc.cjs
  1:1  error  'module' is not defined  no-undef

なお、ESLint v9からの新しい設定ファイルは、ESM形式でも書けるようになっています。

package.json は type: module にする

これでデフォルトがESMになります。

おわりに

これくらいしか書くことがないです。逆に言えば、もう悩むことがほとんどなくなったかなと思います。