🐏

フロントエンドライブラリ開発におけるpackage.jsonのエントリーポイント設定

2024/08/31に公開

フロントエンドライブラリ開発において、package.jsonに設定するエントリーポイントについて、理解しきれずに設定していた状態だったため、公式ドキュメント等を通じて理解を深めました。その内容をまとめた記事です。

前提

フロントエンドライブラリのエントリーポイントは、通常package.jsonに設定します。この設定の基本はNode.jsのドキュメントに記載されています。

プロジェクトがライブラリを使用する際、そのプロジェクトのバンドラー(webpack, viteなど)はライブラリによって定義されたpackage.jsonのエントリーポイントを参照しますが、その参照方法は個別のバンドラーに依存しており、Node.jsの仕様と異なる場合があります。
そのため、フロントエンドライブラリを開発する際には、エントリーポイントの設定に注意が必要です。

それを踏まえて、主要なエントリーポイントの設定について、Node.jsのドキュメントと主要なバンドラーであるwebpackとViteのドキュメントを読みつつ、その仕様について理解した内容をまとめました。

※なお、バンドラーごとに仕様が異なるため、ここで説明した内容が全てのバンドラーで正しく機能するわけではありません。

exportsフィールド

https://nodejs.org/api/packages.html#package-entry-points

exports フィールドは、Node.jsで推奨されるエントリーポイントの設定方法です。(Node.js 12以降でサポートされます)
このフィールドを使用することで、パッケージのエントリーポイントを明確に指定することができ、import(ESModules)とrequire(CommonJS)で異なるファイルを提供することができます。
なお、この設定は後述のフォールバックの設定(mainフィールド, moduleフィールド)より優先して適用されます。

基本的な構造

{
  "exports": {
    ".": {
      "import": "./dist/index.mjs", // ESMのエントリーポイント
      "require": "./dist/index.cjs" // CJSのエントリーポイント
    }
  }
}

バンドラーの対応状況

webpack と Vite の対応状況は以下の通りです。

フォールバック用のフィールド設定

プロジェクトがexportsが未対応な場合に備えて、フォールバック用のフィールドを設定をすることができます。
ここでは基本的に設定する、主要な2つのエントリーポイント設定のためのフィールドについて説明をします。

mainフィールド

https://nodejs.org/api/packages.html#main

Node.jsの標準仕様として定義されたエントリーポイント設定用のプロパティです。
CJSのエンドポイントをエンドポイントとして設定すること一般的ですが、ESMのエンドポイントも設定可能です。
設定したエンドポイントがCJS, ESMであるかの判定はファイル拡張子とtypeフィールドの設定値に基づき行われます。

typeフィールドについて

https://nodejs.org/api/packages.html#introduction_1

package.jsonのtypeフィールドは、パッケージ内のJavaScriptファイルをどのモジュールシステムとして扱うかを指定します。

  • "type": "module": パッケージ内のJavaScriptファイルをデフォルトでESMとして扱います

  • "type": "commonjs": パッケージ内のJavaScriptファイルをデフォルトでCJSとして扱います

  • typeフィールドが未指定: デフォルトで"commonjs"として扱われます

  • typeフィールドの設定に関わらず、以下の拡張子は常に特定のモジュールシステムとして扱われます:

    • .mjs: 常にESMとして扱われます
    • .cjs: 常にCJSとして扱われます

設定例

{
  "type": "module",
  "main": "./dist/index.cjs"
}

この例では、mainフィールドで指定されたファイルは.cjs拡張子を持つため、CJSとして扱われます。
一方、typeフィールドが"module"に設定されているため、拡張子が.jsのファイルはデフォルトでESMとして扱われます。

moduleフィールド

ESMのエントリーポイントを設定するフィールドです。
これはNode.jsの標準仕様としては定義されていませんが、多くのバンドラーではこれを参照し、ESMのエントリーポイントとして扱います。
一般的にこのフィールドはmainより優先して適用されます(参考: webpackドキュメント, @rollup/plugin-node-resolve)

Node.jsの標準仕様ではないmoduleフィールドですが、webpackやviteでも設定が推奨されていることが確認できます。

設定例

{
  "main": "./dist/index.mjs"
}

まとめ

  • exportsフィールド
    • 最新のNode.js推奨設定
    • ESMとCJSのエントリーポイントを明確に指定可能
    • 多くの最新バンドラーでサポート
  • フォールバック設定
    • mainフィールド: CJS(または場合によってはESM)のエントリーポイントを指定
    • moduleフィールド: ESMのエントリーポイントを指定(非標準だが広くサポート)
  • typeフィールド
    • パッケージ全体のデフォルトモジュールシステムを指定
    • ファイル拡張子(.mjs, .cjs)で個別に上書き可能

以下の設定を適切に行うことで、より多くの環境で正しく動作し、開発者が利用しやすいフロントエンドライブラリを提供することができそうだと思いました。

  • exportsフィールドを使用し、明確なエントリーポイントを提供する
  • 互換性のためにmainフィールドとmoduleフィールドも設定する
  • エントリーポイントには、必要に応じて適切なファイル拡張子を設定する(.mjs, .cjs
  • 使用するバンドラーの仕様を確認し、必要に応じて設定を調整する

Discussion