package.jsonのmainとexports
エントリーポイントを表すmain
とexports
パッケージのエントリーポイント指定には今までmain
フィールドを使用してきた。
{ "main": "./dist/index.js" }
これは今でも有効な指定であるが、単一のエントリーポイントしか指定できないため、利用者側の形式(CommonJS形式とESModule形式)で分岐できない。
現代ではブラウザ環境およびNode環境でもESModuleが普通に使えるので、ESModule形式だけでも大分問題なくなってきたが、とはいえライブラリとして配布する時はCommonJS形式のサポートが必要なことが多い。
exports
はNode.js 12から追加された機能で、条件によってエントリーポイントを分岐することが出来る。
{ "main": "./dist/index.js", "exports": { // 利用する側がESModule環境のとき "import": "./dist/index.js", // 利用する側がCommonJS環境のとき "require": "./dist/index.cjs" } }
exports
とmain
がどちらも指定されている場合はexports
が優先される。
基本的にexports
はmain
の上位互換的な機能なので通常はexports
だけで良いが、古いNode.js環境用にmain
も指定しておくのが良さそう。
exports
のメリット
exports
は定義したパスのみ公開できる。
これにより、定義していないパスでのインポートをエラーにすることが出来る。
{ "name": "my-package", "main": "./dist/index.js", "exports": { ".": "./dist/index.js", "./client": "./dist/client/index.js" } }
// ok import { xxx } from 'my-package'; // ok import { yyy } from 'my-package/client'; // error (ERR_PACKAGE_PATH_NOT_EXPORTED) import { yyy } from 'my-package/server';