パッケージとはディレクトリツリーのことだが、次の条件/制約がある。
- トップレベルに package.json を持つ。
- サブディレクトリで、package.json を持つものがあれば、それは別なパッケージなので除外する(サブツリーを切り落とす)。
- すぐ下のサブディレクトリ node_modules/ は除外する(サブツリーを切り落とす)。
ひとつのファイルシステム内にたくさんのパッケージを持てる。ZIPに固めたりしないところが昔とは違う。ディスク容量が増えて、gitのプロトコルでファイルツリーがそのまま転送されるようになって、アーカイブする動機がなくなったと思う。ディレクトリツリーは、そのまま転送する(コピーする)感覚になった。
CJS方式だと、ディレクトリをモジュールとみなすこと(folders as modules)ができる。Webサーバーと同じ index.* をフォルダーとみなす。これはあまり良くないと思う。ディレクトリ名と同名で、型を表す拡張子のファイルが好み;./foo/foo.md とか。これはこれでほんとに ./foo/foo.md が欲しいときに困るが。
パッケージのエントリーポイントと公開名〈公開ラベル〉は同じもの。package.json の exports プロパティはエクスポートテーブルを与える。エクスポートテーブルは、名前の変換表になる。main も名前の変換をするが、パッケージ名をファイル名にマップする。
パッケージの置かれているローカルディレクトリを仮にパッケージコンテナと呼ぶと、モジュール検索は、幾つかのパッケージコンテナ内を順番に検索となる。
- パッケージコンテナ(例えば ./node_modules/)内にパッケージ名と同名のディレクトリがあれば、それがパッケージ。
- パッケージ内の package.json を見て、モジュール名をファイル名にどうマップするかを決める。このとき見る package.json のプロパティは exports 、なければ main 。exports があれば main は見ない。
- exports は「モジュール名 → 実体であるファイル名」マッピングの記述。
- ./package.json#property(exports) は、パッケージ内の実体に対する公開/非公開の制御と名前の設定を行う。
- これは、ツリー構造の部分的な貼り合わせの技法。なかなか優れている。
- 名前に対して最終的にはプログラム・エンティティをロードするが; (1)パッケージ名からパッケージ実体(ディレクトリツリー)を探す、(2)モジュール名からファイルモジュール=モジュールファイルを探す (3)エンティティ名からエンティティ〈実体〉を探す、(4)現在の名前グラフに追加する。
- 名前からエンティティの検索と、見つかったエンティティの内部登録の際に、“名前→名前マッピング”と“名前→実体”マッピングが繰り返し使われる。
- TypeScriptだと、export {foo as pubName} とか import {pubName as myName} とかできる。ES2015+ ならどうかは知らん。
- TypeScriptのモジュールのエクスポートテーブルには、やはり値名空間、型名空間、名前空間名空間がある。
- mainがエントリーポイントという発想はどうも古すぎる。エクスポートテーブル、あるいはエクスポートリストだろうな。テーブルエントリ、リストアイテムに名前〈ラベル〉だけでなく型〈プロファイル〉が付いているとさらに新しい。指標とセオリーが使える。
- mainエントリーポイント → デフォルト・エクスポート・エントリ。同じ「エントリー」が使われているが、「入り口」と「項目」で違う意味。
- 名前構造をツリーだと思うのもダメで、名前グラフで考えないと。