package.json の exports の順番には決まりがある
Summary
exports を書く場合, types は一番最初に, default は最後に書かなければならない (should)
これをしないと挙動がおかしくなる場合がある
Environments
Node.js: v20.11.1
TypeScript: v5.4.3
eslint: v8.57.0
eslint-plugin-import: v2.29.1
eslint-import-resolver-typescript: v3.6.1
Introduction
前提:
monorepo でプロジェクトを管理していた
eslint で eslint-plugin-import を使いたいという動機が存在
しかし, eslint-plugin-import では, eslint-import-resolver-typescript とそのほかの設定がないと import/no-unresolved で依存関係が解決できない
ref: https://github.com/import-js/eslint-import-resolver-typescript
とりあえず, 導入して設定したが, 一部パッケージで import/no-unresolved の解決ができていなかったため eslint 実行中にエラーを吐いた
しかも, エラーを吐いた場所が全て自分のパッケージであるので困った
理由は後で書くが package.json で以下のように exports を書いていた:
code:package.json
"exports": {
".": {
"default": "./dist/index.js",
"types": "./dist/index.d.ts"
}
},
正しくはこう:
code:package.json
"exports": {
".": {
"types": "./dist/index.d.ts", // <- 先に types を書く
"default": "./dist/index.js" // <- default はあと
}
},
何故こうしなければならないのかは Node.js の Docs からの引用する:
"default" - the generic fallback that always matches. Can be a CommonJS or ES module file. This condition should always come last.
"types" - can be used by typing systems to resolve the typing file for the given export. This condition should always be included first.
ここの原因は詳しく調べてないが, おそらく eslint-plugin-import が package.json を精査するときに先に default を参照してしまうことが原因 (だと考えている)
Docs にも "the generic fallback that always matches. Can be a CommonJS or ES module file." と書かれているし
ちなみに exports の仕様は, Node.js が ESM に対応するときに CommonJS との互換性の観点を持たせている
それにより, eslint-plugin-import に問題が発生した (調べている最中 GitHub Issue に上がっていた)
ref: https://github.com/import-js/eslint-plugin-import/issues/1810
ちなみにそのための解決法として実は eslint-import-resolver-typescript が存在する
なんやいね
そのため, types を参照する前に default を参照してしまい依存関係が解決しなかったと考えるのが適切な気がする
おそらく要検証だが…
References
https://nodejs.org/api/packages.html#conditional-exports
https://nodejs.org/api/packages.html#community-conditions-definitions
https://github.com/Hytusium/eslint-config
eslint の Shareable Config をユースケースごとに持ちたかったので monorepo にするの意味あるのか…?と思った
いくら FlatConfig 対応のためと言っても monorepo にする必要性はちょっと微妙なので素直に @scope/package/hoge, @scope/package/fuga で分けれるように exports にした方がもしかしたらいい
依存パッケージを一元管理できるので
でも, monorepo でもパッケージを一元管理にしてあるし問題ないか!
ほんまか?
まあ monorepo やったことないからやってみたかったというのもあるけど…
#article #tech