Next.jsで`window is not defined` を解決する(依存ライブラリ対応)
問題と原因
今回は依存ライブラリ内でpepjs
が使われていたため、window is not defined
が出ました。
つまり、pepjs
内でwindow
を使おうとしてるのが問題です。
原因はwindow
がクライアント処理でしか使えないため、Nextjsのサーバサイド処理ではエラーになります。
Reactコンポーネント内で使う場合であれば下の記事の方法で、処理をクライアントサイドに限定することで解決できます。
Next.jsで"document is not defined." "window is not defined."のエラーが出たときの対処法
すなおにNextjsを使わない形でReactを使う手もありますが、Next(というかVercel)はその辺の対応をすでにしています。
また、Nuxt.jsではこれに関する記事が多くありますが、Nextjsではなぜかなかったので、記事として残しました。
解決法: Dynamic Importを使う
Dynamic ImportはES2020で導入された機能で、動的にモジュールを読み込むことができます。
Nextjsではこれを利用したdynamic
というモジュールで、コンポーネント等を動的にインポートできます。
さらに、ここではサーバサイドレンダリング(SSR)を使わない設定を行うことができます。
これらをかけ合わせ、クライアントへの依存性のあるコンポーネントをSSRなしで、Dynamic Importすることで、問題の解決ができます。
import React from 'react';
import ClientDependentModule from 'clientdependentmodule';
export default ClientDependentComponent() {
/* Something write here*/
}
import React from 'react';
import dynamic from 'next/dynamic';
const ClientDependentComponent = dynamic(() => {
import('./ClientDependentComponent'), { ssr: false}
});
export default ImportSide() {
return (
<>
<ClientDependentComponent />
</>
);
}
この方法はライブラリ依存による問題のほか、Nextjsでクライアント側で処理を行いたい、ブラウザの提供するAPIを使いたい場合などでも対処することができると思います。
ReactではできたのにNextjsに変えた途端エラー吐くとかもこれで直ると思います。(抜本的な解決ではありません)
Discussion
良記事ありがとうございます!
Next.jsはPre-renderingなので気を抜くと
window is not defined
が発生してしまいますよね。。。SSR回避の方法ですが、今回紹介していただいた『
ssr: false
オプションを追加したdynamic import』の他に、『副作用で読み込む』『process.browser
で実行環境を確認する』『typeof window
でwindowを参照できるか判定する』などもあるかなと思いました。参考: https://nishinatoshiharu.com/next-exec-only-client/