できない.dev

Next.js で「Module not found: Can't resolve 'fs'」が解決できない

fs などの Node コアモジュールをクライアントに含まれるコードで import すると出る。
サーバー専用コードへ移すか、Server Component / Route Handler 側でのみ使う。

公開:

要約

Module not found: Can't resolve 'fs' は、fspath などブラウザに存在しない Node コアモジュールを、クライアントバンドルに含まれるコードから import したときに出る。

ファイルに 'use client' を付けると、その import 連鎖はすべてクライアントに含まれる。fs はサーバーにしか無いのでバンドルできず、解決に失敗する。

対策の基本は、サーバー専用の処理を Server Component や Route Handler 側へ寄せること。

よくある原因

  1. クライアント境界の巻き込み: 'use client' のファイル(またはそこから import した先)で fs を参照している。
  2. サーバー専用コードの混入: ファイル読み込みなどサーバー用ユーティリティをクライアントから import している。
  3. 依存ライブラリ経由: ライブラリが内部で Node コアモジュールに依存し、クライアント側に引き込まれている。

解決策

1. サーバー側へ処理を移す(推奨)

// app/page.tsx (Server Component: 'use client' を付けない)
import { readFileSync } from "node:fs";
 
export default function Page() {
  const data = readFileSync("data.json", "utf8");
  return <pre>{data}</pre>;
}

fs を使う読み込みは Server Component 側で行い、結果だけをクライアントへ渡す。

2. server-only でガードする

import "server-only";

このモジュールを import したファイルがクライアントに含まれるとビルドが失敗するため、混入を早期に検知できる。

3. resolve.fallback で空に割り当てる(最終手段)

// next.config.js (webpack 利用時)
module.exports = {
  webpack: (config) => {
    config.resolve.fallback = { fs: false };
    return config;
  },
};

どうしてもリファクタできない場合の逃げ道。
Turbopack を使う場合は turbopack.resolveAlias で同様に空モジュールへ割り当てる。
まずはリファクタで fs をクライアントから外すのが本筋。

この記事は役立ちましたか?