Next.js でのエラー Module not found: Can't resolve 'fs' の対処方法

JavaScriptSSGNext.js

Next.js で次のようなエラーが出たときの対処方法についてです。

Next.js でのエラー Module not found: Can't resolve 'fs'

Module not found: Can't resolve 'fs'

確認時のバージョン

  • Node.js 16.x
  • Next.js 12.x / 11.x

問題

Next.js を実行すると(= next devnext build を実行すると)次のメッセージを含むエラーが出て処理が途中で止まってしまいます。

Module not found: Can't resolve 'fs' in ...

前提として、 fs モジュールは Node.js に同梱されているため、通常 Next.js の実行時に fs モジュールはシステム内に存在しています。 それにもかかわらず next devnext build を実行すると「 Can't resolve 'fs' 」と言われてしまうというのがこの問題のポイントです。

原因

いろいろな原因がありえますが、 Next.js でよくあるのは クライアントサイド JS のコンテキストで fs モジュールが利用されてしまっていること です。 fs モジュールは Node.js のモジュールであり、クライアントサイド JS には含まれていません。 その fs モジュールをクライアントサイドで利用しまっているために Can't resolve 'fs' のエラーが出ます。

Next.js の場合に少しトリッキーなのは、クライアントサイド JS のコンテキストで明示的に利用していなくても fs モジュールが参照されてしまうことがあることです( Next.js の仕組みをよく理解している人からすれば少しもトリッキーなことはなくこれは当然の挙動かと思いますが……)。

この現象は、次のようなページコンポーネントを作って next dev または next build を実行すると認できます。

pages/example.js:

// エラーの出るコード
import fs from 'fs'

const Example = (props) => {
  return <div><code>fs</code> モジュールでのエラーのサンプル</div>
}

export default Example

ここで Example はページコンポーネントです。 import fs from 'fs'fs モジュールをインポートしていますが、 Example の中で fs は一切利用していません。 にもかからわず、このページコンポーネントで Can't resolve 'fs' のエラーが出ます。

next build

Failed to compile.

./pages/example.js
Module not found: Can't resolve 'fs' in '/path/to/project/root/pages'


> Build failed because of webpack errors

対処方法

対処方法はシンプルで、クライアントサイド JS のコンテキストで fs モジュールが参照されないようにすることです。

ページコンポーネントで fs モジュールを import した場合は、 getStaticProps()getServerSideProps() の中で必ず利用するようにします。

たとえば、上の Example の場合であれば、次のように getStaticProps() (または getServerSideProps() )を書いてその中で fs を利用すれば OK です。

pages/example.js:

// エラーの出ないコード
import fs from 'fs'

const Example = (props) => {
  return <div><code>fs</code> モジュールでのエラーのサンプル</div>
}

export default Example

export async function getStaticProps() {
  // `getStaticProps()` の中で `fs` を少しでも利用すれば OK
  fs
  return {
    props: {}
  }
}

もし fs モジュールを getStaticProps() でも getServerSideProps() でも使っていないのであれば import 自体をやめます。

pages/example.js:

const Example = (props) => {
  return <div><code>fs</code> モジュールでのエラーのサンプル</div>
}

export default Example

import してもページコンポーネント内で参照しなければ一見問題なさそうに思えますが、いまのところはそのような挙動にはなっていません。 少し複雑なところなのでかんたんには改善できなさそうですが、将来的には改善される可能性もありそうです。

以上です。

この問題についてより詳しく知りたい方には Next.js リポジトリのイシュー #7755 が参考になります。

イシュー内で紹介されている、 Next.js の tree shaking の挙動を確認できるアプリも便利です。


アバター
後藤隼人 ( ごとうはやと )

Python や PHP を使ってソフトウェア開発やウェブ制作をしています。詳しくはこちら