Vitest で「Cannot find module」とパスエイリアス(@/)が解決できない
tsconfig の paths は型解決用で、Vitest(Vite)の実行時には効かない。
テストで @/ が Cannot find module になるのは resolve.alias 未設定が主因。
alias を定義するか vite-tsconfig-paths を入れる。
#vitest#alias#vite#tsconfig-paths#resolve
公開:
要約
テストで Error: Cannot find module '@/foo' のように出るのは、@/ のようなパスエイリアスが Vitest の実行時に解決できていないため。tsconfig.json の paths はあくまで TypeScript の型解決・エディタ補完用で、実際にモジュールを束ねる Vite/Vitest は resolve.alias を見る(alias | Vitest)。
二つは別物なので、tsconfig だけ書いても実行時には効かない。
alias を Vite 側にも定義するか、tsconfig の paths を同期するプラグインを入れる。
よくある原因
- 設定の二重管理漏れ: tsconfig の
pathsは書いたが、resolve.aliasを書いていない。 - 相対パス: alias の値を相対パスで書いており、基準ディレクトリがずれて解決できない。
- 設定ファイル分離:
vite.configとvitest.configが別で、テスト側に alias が渡っていない。 - require には効かない: alias は
import文のみ対象で、require()は解決しない。
解決策
1. resolve.alias を絶対パスで定義する
vitest.config.ts(または vite.config.ts)のトップレベルに置く(Shared Options | Vite)。
import { defineConfig } from "vitest/config";
import { fileURLToPath } from "node:url";
export default defineConfig({
resolve: {
alias: { "@": fileURLToPath(new URL("./src", import.meta.url)) },
},
});2. tsconfig の paths を同期する
エイリアスを tsconfig 一本で管理したいなら、プラグインで Vite 側へ反映する。
import tsconfigPaths from "vite-tsconfig-paths";
export default defineConfig({ plugins: [tsconfigPaths()] });3. include を確認する
tsconfig.json の include にテストフォルダが含まれているかも確認する。
含まれないと型解決とテスト解決の食い違いが起きやすい。