Vitest を導入しただけで tsc がコケるようになった
本スクラップについて
以下のエラーについて追求する。
$ tsc --noEmit
node_modules/vite/dist/node/index.d.ts:6:41 - error TS2307: Cannot find module 'rollup/parseAst' or its corresponding type declarations.
6 export { parseAst, parseAstAsync } from 'rollup/parseAst';
~~~~~~~~~~~~~~~~~
Found 1 error in node_modules/vite/dist/node/index.d.ts:6
error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
結論から言うと、以下で解決した。
{
"compilerOptions": {
// 一部抜粋
"moduleResolution": "bundler",
},
}
のだが、どういう理屈で発生してなぜ治ったのかよくわからなかったので、順に明らかにしていく。
背景
テストフレームワークに Jest を使用しているプロダクトで、Vitest への移行を行った。
その際、vitest の global API を宣言無く呼び出せるようにするため、その型定義を読み込むように tsconfig.json
を追加した。
{
"compilerOptions": {
// 一部抜粋
"moduleResolution": "node",
"types": ["vitest/globals"],
},
}
vitest 移行後のテストは全て通るようにまで一気に修正したが、tsc による型チェックが通らなくなった。
$ tsc --noEmit
node_modules/vite/dist/node/index.d.ts:6:41 - error TS2307: Cannot find module 'rollup/parseAst' or its corresponding type declarations.
6 export { parseAst, parseAstAsync } from 'rollup/parseAst';
~~~~~~~~~~~~~~~~~
Found 1 error in node_modules/vite/dist/node/index.d.ts:6
error Command failed with exit code 2.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
手っ取り早い解決
エラーメッセージで雑にググると、以下の Discussion にて、まったく同じ報告があり、そこですぐに解決されていた。
Vite リポジトリであることや、Rollup でのエラーであることから、vitest でなく vite, それも Vite 5 からであることがうかがえる。
You need to use moduleResolution: 'bundler' (or node16/nodenext) to fix it. Rollup only export those types from the "exports" field which those resolution settings respect.
とのことなので、 moduleResolution
についておさらいすれば良さそう。 import をどのように解決するかのアプローチの設定だった気がするが細かくは理解してない。
moduleResolution
について
この記事が最高に良くまとまってる。というか半年前に読んでブコメを残してた。のでこういう記事があったことは覚えてたんだけど、結局 Node16 や bundler を設定した時にどうなるかは覚えてなかった。
package.json
における、モジュールシステムの宣言
-
type: "module"
の場合は ESM で提供することを宣言できる - `type: "commonjs" の場合は CJS で提供することを宣言できる-
-
main
フィールドにはインポートした際のエントリポイントを指定できる (CJS, ESM 共通) -
exports
フィールドには、インポートするパスごとに、CJS, ESM それぞれのエントリーポイントを指定できる-
main
が定義されていてもこちらが優先される
-
TypeScript 側のモジュール解決
tsconfig.json
の moduleResolution
フィールドで設定する
-
Node
/Node10
- CJS 専用
-
main
フィールドのみ使用される
-
Node16
/NodeNext
-
type
の値によって CJS か ESM か決まる -
exports
フィールドからエントリーポイントを決定する - 拡張子や index の補完を行うの自動補完は行われない
-
-
Bundler
- 拡張子や index の補完を行うの自動補完を行う
-
exports
フィールドによってエントリーポイントが決定する
Rollup について
今回エラーが発生したのは rollup/parseAst
でした。
6 export { parseAst, parseAstAsync } from 'rollup/parseAst';
Vite 5 を使用しているので、Rollup も v4 が使用されます。
$ yarn why vite
=> Found "vite@5.0.6"
$ yarn why rollup
=> Found "rollup@4.6.1"
rollup の package.json から rollup/parseAst
を確認する。
cjs あるくね?
あー違う。現状だと
"moduleResolution": "Node",
が使われてたんだ。だから昔ながらの main
フィールドしか見えてない。
だから require('rollup')
だったら、dist/rollup.js
を見つけられるけど、 require('rollup/parseAst')
だと解決できないんだ。
完全に理解した。完。