Skip to content

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: コードを適切な場所に配置する(推奨)

サーバー専用コードは常に上記のサーバーサイド関数内に配置するようにします:

javascript
// ページコンポーネントファイル (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パッケージをインポートして、誤った使用を防ぎます:

bash
npm install server-only
javascript
// 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の設定を調整します:

javascript
// 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: サーバー/クライアント混在モジュール

サーバー専用コードとクライアントでも使用可能なコードが混在している場合:

javascript
// ❌ 問題のあるコード
import fs from 'fs'

// サーバー専用関数
export function readFileServerSide(path) {
  return fs.readFileSync(path, 'utf8')
}

// クライアントでも使用したい関数
export function formatData(data) {
  return data.toUpperCase()
}

これを以下のように分割します:

javascript
// ✅ サーバー専用モジュール (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のようなサーバー専用ライブラリを使用している場合:

bash
# bcryptの代わりにbcryptjsを使用
npm uninstall bcrypt
npm install bcryptjs
javascript
// bcryptの代わりにbcryptjsを使用
import bcrypt from "bcryptjs"

ケース3: 未使用のインポート

使用していないインポートが残っている場合もこのエラーの原因になります。未使用のインポートは削除しましょう。

App Router(Next.js 13以上)での対応

App Routerを使用する場合、サーバーコンポーネントとクライアントコンポーネントを明確に区別します:

javascript
// 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>
  )
}

クライアントコンポーネントでサーバーからのデータを使用する場合:

javascript
// app/client-component.js
"use client" // クライアントコンポーネントであることを明示

export default function ClientComponent({ serverData }) {
  // サーバーから受け取ったデータをクライアントで使用
  return <div>{serverData}</div>
}

トラブルシューティングのヒント

  1. 使用していないインポートをチェック - 不要なインポートが原因の場合があります
  2. Node.jsのバージョンを確認 - Node.js 14以上の使用を推奨します
  3. キャッシュのクリア - ビルドキャッシュの問題を解決する場合があります
  4. 使用しているライブラリのドキュメントを確認 - 特定のライブラリに必要な設定がある場合があります

まとめ

「Module not found: Can't resolve 'fs'」エラーは、サーバー専用コードがクライアントバンドルに含まれようとした際に発生します。この問題を解決するには:

  1. サーバー専用コードをgetServerSidePropsgetStaticPropsgetStaticPaths内に配置する
  2. サーバー専用モジュールにはserver-onlyパッケージを使用する
  3. サーバー/クライアントのコードを適切に分離する
  4. どうしても必要な場合のみWebpack設定を調整する

これらのベストプラクティスに従うことで、Next.jsアプリケーションのパフォーマンスと保守性を向上させることができます。