Next.js でのエラー Module not found: Can't resolve 'fs' の対処方法
Next.js で次のようなエラーが出たときの対処方法についてです。
Module not found: Can't resolve 'fs'
確認時のバージョン
- Node.js 16.x
- Next.js 12.x / 11.x
問題
Next.js を実行すると(= next dev
や next build
を実行すると)次のメッセージを含むエラーが出て処理が途中で止まってしまいます。
Module not found: Can't resolve 'fs' in ...
前提として、 fs
モジュールは Node.js に同梱されているため、通常 Next.js の実行時に fs
モジュールはシステム内に存在しています。
それにもかかわらず next dev
や next 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 の挙動を確認できるアプリも便利です。