📆

Next.jsで`window is not defined` を解決する(依存ライブラリ対応)

2020/12/18に公開1

問題と原因

今回は依存ライブラリ内で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することで、問題の解決ができます。

参考: Dynamic Import | Next.js

ClientDependentComponent.jsx
import React from 'react';
import ClientDependentModule from 'clientdependentmodule';

export default ClientDependentComponent() {
  /* Something write here*/
}

ImportSide.jsx
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

nishinanishina

良記事ありがとうございます!
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/