Node.js向けライブラリのpublishの仕方を再勉強
実際Node.jsのesm対応その他についての自分の知識が古いなと思ったのでアップデートを試みる。
まず最新の情報をキャッチアップ。
Node.jsはESMをデフォルトにする可能性がある。
CJS, ESM, UMDそれぞれについての説明。
CJS, ESMに関してはtscのみでビルドできる。UMDはバンドラが必要。
package.jsonについて。
mainフィールドはCJSのエントリポイント。
moduleはESM配布の際のエントリポイント。分かりづらい。
Node.jsでもブラウザ(+バンドラ)でも現状CJSの配布を行うのが普通である。
併せてESMも配布すると対応バンドラではTree Shakingをかけられる。
UMDってそもそも何だっけという話。
Q promiseライブラリ(聞いたことあると思う)で使われていたテクニックをパターン化したものらしい。
やっていることは概ねブラウザではwindowにモジュールをぶら下げる、またはNode.jsの場合はエクスポートするだけ。
概ねUMDはCDN経由でシンプルなライブラリを配布したいなら出力する、くらいの理解で良さそう
今のところまでの理解:
- Node.js向けであればCJSのみ、またはCJS, ESMの両方を出力する
- CJSだけでも、ESM側からはimportで読み込めるので問題ない(し、Tree shakingはNode.jsからのメリットは大きくない)
- ESMだけは今のところNG。CJSを用意しないと利用側もESMに移行しないといけなくなる
- Node.jsとブラウザ両対応では、CJS, ESMの両方を出力する。
- 利用側のコードがESMであるとは限らないが、可能性は高い
- 特にブラウザ側ではTree shakingの需要があるため、両方用意したほうがよい
- Node.jsからも使われることを考えると引き続きCJSも提供したほうが良さそう
- CDN経由でも使えるようにするにはバンドル済みESMとUMD両方を提供する。ブラウザ側でtype="module"の中で使いたいケースと、そうでないケースの両方がありうるため。
実際にradix-uiを見てみる。
CJSとESM両方を提供している。
例外があった。Node.jsでCJSプロジェクトからESM実行できるのか…
Top level await本当に必要だった?みたいな話がようやく理解できた。自分もTop level awaitよりCJSからのESMインポートを優先したほうが良かったんじゃないのと普通に思った
というかFake ESMというのがあるのか。頭痛くなってきた…
Fake ESMはESMの文法を使えるものの、バンドラでCJSにトランスパイルされるのが前提となる。そのためimportでファイル名を省略できたりする(Native ESMのモジュール解決ではない)
なのでFake ESMとNative ESMは明確に区別しなくてはいけない。