poyopoyo0のブログ

poyopoyoのブログ

Web 関連のメモ書きブログです。

【Vue.js / Nuxt.js / Firebase】 NuxtでgenerateしたSPAをFirebase上でリダイレクト処理させるには

※middlewareについての記述が間違っていたので、訂正しました。

NuxtでgenerateしたSPAをFirebase上でリダイレクト処理させるのに、えらいこと手こずってしまったので、覚え書き。 以下は、ロケーションバーに直打ちして https://(app_url)/hoge にアクセスしたとき https://(app_url)/login にリダイレクトさせたいときの実装方法。

最初は、 pages/hoge.vue<script> タグの中にbeforeCreateを書いて、その中で条件分岐して this.$router.push(/login) させてみる、という方法を試みた。だけど、この方法だと、リダイレクトする直前に pages/hoge.vue が一瞬だけ表示されてしまい、印象が良くない。 なので、以下の2つの方法を試してみた。

middlewareを用いる方法

middlewareへの記述は、こちらの記事 su-kun1899.hatenablog.com が参考になった。 この方法で、ローカルの開発環境では問題無くリダイレクトできるようになった。

ところが、その後、generateしてからFirebaseにデプロイしたところ、Firebase上ではリダイレクトしてくれないという状況が発生。 Nuxtの GitHub Issue github.com でも報告されているのだけど、どうやら、generateしたSPAファイルにはmiddlewareの処理が反映されない、という仕様になっているみたい。 つまり、Firebase / Netlify / GitHub Pages / GitLab Pages などにデプロイしたアプリでリダイレクト処理をさせるには、別の方法が必要らしい。 (※こちらは古い情報でした)

【追記】 generateしたSPAファイルにはmiddlewareの処理が反映されないというのがNuxtの仕様、と思い込んでいたのだけど、 @nishiokaex さんから

こんにちは。ブログ楽しく拝見させて頂いたのですが、SPAモードでビルドするとミドルウェア使えないでしょうか。私の環境(nuxt.js v2)では、nuxt.config.jsに「mode: 'spa'」と書いて、「nuxt build」すると、ミドルウェアが動作しているように見えます。

というご指摘を受けたので、middlewareに書いた処理が別の理由で動かなくなっているのではないかと思い、もう一度見直してみた。

当初、middlewareには

export default function ({ route, redirect }) {
  if (!route.params.hoge && route.path == '/hoge') {
    return redirect('/login')
  }
}

という風にリダイレクト処理を書いていたのだけど、Firebase上でmiddlewareが動かないように見えていたのはこの記述が悪かったようで、これを

export default function ({ route, redirect }) {
  if (!route.params.hoge && (route.path == '/hoge' || route.path == '/hoge/')) {
    return redirect('/login')
  }
}

のように書き換えることで、Firebase上でもmiddlewareでリダイレクト処理できるようになった。以前のNuxtではgenerateしたSPAでmiddlewareが動かなかったようだが、今は動くように実装されているみたい。 ( @nishiokaex さん、ご指摘ありがとうございました!)

コンポーネントを切り替える方法

次に試みた方法は、読み込むコンポーネントを条件分岐で切り替えることで、疑似的なリダイレクトを実装する、という方法。

pages/hoge.vue

<template>
  <section>
    <div v-if="$route.params.hoge">
      <hoge/>
    </div>
  </section>
</template>

<script>
import hoge from '@/components/hoge.vue'

export default {
  components: {
    hoge
  },
  beforeCreate() {
    if (!this.$route.params.hoge && this.$route.path == '/hoge') {
      this.$router.push('/login')
    }
  }
}
</script>

のように記述したところ、ローカルの開発環境では狙い通りにリダイレクトするようになった。

ところが、generateしたファイルをFirebaseにデプロイさせたところ、リダイレクトしてくれない。 前回の記事 で書いた方法を使って、デプロイ先のページの this.$nuxt.$route.path をコンソールで表示させてみたところ、画面遷移して https://(app_url)/hoge にアクセスしたときは /hoge と表示されるのに、ロケーションバーに直打ちして https://(app_url)/hoge にアクセスすると、 /hoge/ のように、末尾にスラッシュが入ってしまっている。

仕方が無いので、beforeCreateの記述を

  beforeCreate() {
    if (!this.$route.params.hoge && this.$route.path == '/hoge/') {
      this.$router.push('/login')
    }
  }

のように書き換えたところ、デプロイ先のページでは問題無くリダイレクトするようになったが、今度はローカルの開発環境でリダイレクトしてくれなくなってしまった。 デプロイ先のページで動いているのなら問題無い気もするが、ローカルの開発環境できちんと動いてくれないのは気持ちが悪いので、最終的にbeforeCreateの記述を

  beforeCreate() {
    if (
      !this.$route.params.hoge &&
      (this.$route.path == '/hoge' || this.$route.path == '/hoge/')
    ) {
      this.$router.push('/login/')
    }
  }

と記述することで、ローカルでもデプロイ先でも、問題無くリダイレクトしてくれるようになった。

ちなみに、URLを直打ちしたとき、URLの末尾に自動でスラッシュ / が入ってしまうのはWebの仕様がそうなっているみたいで、Firebaseが悪いわけではなさそう。

今回手間取ったのは、ローカルの開発環境と、generateさせたSPA、および、デプロイ先で、微妙に挙動が違うことが原因だったのだけど、 前回見つけたやり方 は、デバッグに多大なる力を発揮してくれた。

補足

今回レベルの単純なリダイレクトであれば、Firebaseの公式ドキュメント Configure hosting behavior  |  Firebase にある通り、 firebase.json ファイルに

    "redirects": [
      {
        "source": "/hoge",
        "destination": "/login",
        "type": 301
      }
    ],

と記述してやれば、すぐ実装できるのだけど、CookieやLocalStorageなどで条件分岐してリダイレクトさせたいときには使えなさそう。なので、generateしたSPAでリダイレクト処理を書くときは、基本的にはコンポーネントの切り替えで対処するしかないかな…。

【追記】 上の追記でも触れていますが、現在のNuxtでは、generateしたSPAでもmiddlewareが動くので、middlewareでリダイレクト処理させる方が望ましいようです。