Next.jsで「Module not found: Can't resolve 'fs'」エラーが発生する原因と解決方法
Next.jsアプリケーションの開発中に「Module not found: Can't resolve 'fs'」というエラーに遭遇したことはありませんか?このエラーはNode.jsのネイティブモジュールをクライアントサイドコードで使用しようとした際に発生します。この記事では、この問題の根本的な原因と効果的な解決方法を詳しく解説します。
問題の根本原因
fs
モジュールはNode.jsの組み込みモジュールで、ファイルシステム操作を提供します。しかし、ブラウザ環境ではNode.jsのAPIは利用できないため、ブラウザで実行されるクライアントサイドコードでfs
モジュールを使用しようとすると、このエラーが発生します。
Next.jsは以下のサーバーサイド専用関数内でのみNode.jsモジュールの使用を許可しています:
getServerSideProps
getStaticProps
getStaticPaths
これらの関数の外部でfs
モジュールを使用すると、Next.jsのビルドプロセスがクライアントバンドルにサーバー専用コードを含めようとし、エラーが発生します。
主な解決方法
方法1: コードを適切な場所に配置する(推奨)
サーバー専用コードは常に上記のサーバーサイド関数内に配置するようにします:
// ページコンポーネントファイル (pages/my-page.js)
import fs from 'fs'
// サーバーサイドでのみ実行される
export async function getServerSideProps() {
// fsモジュールはここでのみ使用可能
const fileContent = fs.readFileSync('/path/to/file', 'utf8')
return {
props: {
content: fileContent
}
}
}
// クライアントサイドで実行される
export default function MyPage({ content }) {
return <div>{content}</div>
}
方法2: server-onlyパッケージを使用する
サーバー専用のファイルにはserver-only
パッケージをインポートして、誤った使用を防ぎます:
npm install server-only
// utils/server-only-util.js
import "server-only"
import fs from 'fs'
export function readFileData(path) {
return fs.readFileSync(path, 'utf8')
}
方法3: Webpack設定の調整
どうしても必要な場合は、next.config.jsでWebpackの設定を調整します:
// next.config.js
/** @type {import('next').NextConfig} */
module.exports = {
webpack: (config, { isServer }) => {
// クライアントサイドビルド時にfsを無視
if (!isServer) {
config.resolve.fallback = {
...config.resolve.fallback,
fs: false
}
}
return config
}
}
WARNING
この方法は一時的な解決策としてのみ使用し、根本的な原因の解決を目指すべきです。
よくあるシナリオと解決策
ケース1: サーバー/クライアント混在モジュール
サーバー専用コードとクライアントでも使用可能なコードが混在している場合:
// ❌ 問題のあるコード
import fs from 'fs'
// サーバー専用関数
export function readFileServerSide(path) {
return fs.readFileSync(path, 'utf8')
}
// クライアントでも使用したい関数
export function formatData(data) {
return data.toUpperCase()
}
これを以下のように分割します:
// ✅ サーバー専用モジュール (server-utils.js)
import "server-only"
import fs from 'fs'
export function readFileServerSide(path) {
return fs.readFileSync(path, 'utf8')
}
// ✅ クライアントでも使用可能なモジュール (format-utils.js)
export function formatData(data) {
return data.toUpperCase()
}
ケース2: サードパーティライブラリの問題
bcrypt
のようなサーバー専用ライブラリを使用している場合:
# bcryptの代わりにbcryptjsを使用
npm uninstall bcrypt
npm install bcryptjs
// bcryptの代わりにbcryptjsを使用
import bcrypt from "bcryptjs"
ケース3: 未使用のインポート
使用していないインポートが残っている場合もこのエラーの原因になります。未使用のインポートは削除しましょう。
App Router(Next.js 13以上)での対応
App Routerを使用する場合、サーバーコンポーネントとクライアントコンポーネントを明確に区別します:
// app/page.js
// デフォルトでサーバーコンポーネント
import { promises as fs } from 'fs'
async function getData() {
const data = await fs.readFile(process.cwd() + '/data.txt', 'utf8')
return data
}
export default async function Page() {
const data = await getData()
return (
<div>
<h1>ファイルの内容</h1>
<p>{data}</p>
</div>
)
}
クライアントコンポーネントでサーバーからのデータを使用する場合:
// app/client-component.js
"use client" // クライアントコンポーネントであることを明示
export default function ClientComponent({ serverData }) {
// サーバーから受け取ったデータをクライアントで使用
return <div>{serverData}</div>
}
トラブルシューティングのヒント
- 使用していないインポートをチェック - 不要なインポートが原因の場合があります
- Node.jsのバージョンを確認 - Node.js 14以上の使用を推奨します
- キャッシュのクリア - ビルドキャッシュの問題を解決する場合があります
- 使用しているライブラリのドキュメントを確認 - 特定のライブラリに必要な設定がある場合があります
まとめ
「Module not found: Can't resolve 'fs'」エラーは、サーバー専用コードがクライアントバンドルに含まれようとした際に発生します。この問題を解決するには:
- サーバー専用コードを
getServerSideProps
、getStaticProps
、getStaticPaths
内に配置する - サーバー専用モジュールには
server-only
パッケージを使用する - サーバー/クライアントのコードを適切に分離する
- どうしても必要な場合のみWebpack設定を調整する
これらのベストプラクティスに従うことで、Next.jsアプリケーションのパフォーマンスと保守性を向上させることができます。