【Nuxt.js/Vue.js】SSR環境で「window is not defined」エラーを解決!クライアントサイドコードの安全な実行方法

Nuxt.jsでSSR開発中に「window is not defined」というエラーでハマったので備忘録として残します。

この記事でわかること:

  • 「window is not defined」エラーが発生する根本原因
  • SSR(サーバーサイドレンダリング)環境でのブラウザAPIの扱い方
  • process.clientを使用した具体的な解決コード

[現象] ブラウザのAPIを叩くと発生する参照エラー

Nuxt.jsやVue.jsのSSR(サーバーサイドレンダリング)モード、あるいはSSG(静的サイト生成)モードを使用している際、実行時に以下のエラーが発生し、動作が停止することがあります。

ReferenceError: window is not defined

[環境] 使用技術

フレームワークNuxt.js / Vue.js
レンダリングSSR(サーバーサイドレンダリング)/ SSG(静的サイト生成)
エラー発生箇所mounted / created ライフサイクルフックやプラグイン内

[原因] サーバーサイドにはwindowオブジェクトが存在しない

Nuxt.jsのSSR/SSGモードでは、ページがブラウザに表示される前に、サーバー(Node.js環境)で一度JavaScriptが実行され、HTMLが生成されます。

サーバーサイド環境(Node.js)には、ブラウザ固有のオブジェクトである windowdocument が存在しません。 そのため、コンポーネントの初期化時にこれらにアクセスしようとすると、サーバーサイドでのレンダリング中にエラーが投げられてしまうのです。特に、mounted 内であってもサーバーサイドレンダリングの一環として評価されるタイミングがある場合に注意が必要です。

[解決策] process.clientによる実行制御

この問題を解決するには、該当のコードが「クライアントサイド(ブラウザ)」でのみ実行されるように、条件分岐を追加します。

修正前のコード(エラーが発生する例):

export default {
  mounted() {
    // サーバーサイドでも実行されるため、windowが見つからずエラーになる
    window.addEventListener('resize', this.handleResize);
  },
  methods: {
    handleResize() {
      console.log('Window resized!');
    }
  }
}

修正後のコード:

export default {
  mounted() {
    // クライアントサイドでのみ実行されるように制御
    if (process.client) {
      window.addEventListener('resize', this.handleResize);
    }
  },
  methods: {
    handleResize() {
      console.log('Window resized!');
    }
  }
}

解説:

Nuxt.jsでは、実行環境を判定するための process.client 変数が用意されています(Nuxt 2では process.browser も利用可能)。この条件分岐を加えることで、サーバーサイドでのレンダリング時は window へのアクセスをスキップし、ブラウザに読み込まれた後だけ安全にイベントリスナーを登録できます。

[まとめ]

  • エラー原因: SSR環境のサーバー側(Node.js)には window オブジェクトがないため。
  • 対策: process.client を使って、ブラウザ環境のみで動くように制御する。
  • コツ: 外部のJSライブラリを使用する場合も、ssr: false 設定や同様の条件分岐を検討しましょう。

これでSSR/SSG特有の参照エラーを回避できるようになります!

タイトルとURLをコピーしました