qqq blog

web開発のメモ

package.jsonのmainとexports

エントリーポイントを表すmainexports

パッケージのエントリーポイント指定には今まで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"
  }
}

exportsmainがどちらも指定されている場合はexportsが優先される。 基本的にexportsmainの上位互換的な機能なので通常は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';

参考