Firebase Hosting で Vue SPA + ランディングページを共存させる構成

Firebase

Firebase Hosting で Vue SPA + ランディングページを共存させる構成

導入:SPAとランディングの共存が必要な理由

Firebase Hosting 上で、Vue製SPAとAdSense審査用のランディングページを共存させたい場面って多いよね。SPAがログイン必須だったりすると、ルート直下にそのまま置くと審査が通らない問題もある。

読者
読者

最初ってどのファイルに広告タグ入れたらいいの?

その場合、SPAを /app/ に配置して、ルート / には誰でも見られるランディングHTMLを置く構成にすればOK。Firebase Hosting の rewrite 機能を活用するのがポイント。

ごりら
ごりら

Firebase の rewrite と Vite のビルド出力をうまく合わせるのがコツだぞ。

ディレクトリ構成とビルド戦略

Vite の出力を dist/app に固定。ルート配信用のHTML(landing.html、privacy.htmlなど)は public/ に置いて、ビルド後に dist/ にコピーする。package.json の postbuild スクリプトでそれを自動化する。

読者
読者

ビルドごとに手でコピーするの面倒だった!

この構成なら npm run build 一発で、

  • dist/app/ に SPA
  • dist/ にランディングや静的HTML

が自動でそろう。

ごりら
ごりら

コピー処理は Nodeスクリプトでやってる。import/export形式(type: module)ならESMで書こう。

firebase.json の設定(rewrite)

以下が最小で鉄壁な設定:

{
  "hosting": {
    "public": "frontend/dist",
    "rewrites": [
      { "source": "/", "destination": "/landing.html" },
      { "source": "/about", "destination": "/about.html" },
      { "source": "/privacy", "destination": "/privacy.html" },
      { "source": "/terms", "destination": "/terms.html" },
      { "source": "/contact", "destination": "/contact.html" },
      { "source": "/app", "destination": "/app/index.html" },
      { "source": "/app/**", "destination": "/app/index.html" },
      { "source": "**", "destination": "/landing.html" }
    ]
  }
}
読者
読者

/app にアクセスしたら404になるのってこのルールで直るの?

そう。"/app""/app/**" の両方をカバーしておくのが重要。リダイレクトではなくリライトでSPAのエントリに飛ばす。

ごりら
ごりら

忘れずにRouterの createWebHistory(‘/app/’) にスラを付けよう。

よくあるトラブルと対処

症状:/ で勝手に /app に遷移

→ それ、landing.html でSPA資産を読み込んでるか、古いService Workerが働いてる。

読者
読者

scriptやlinkで/app/assets読んでたらアウトってこと?

そう。ランディングHTMLは完全に独立した静的HTMLにして、<script type="module" src="/app/assets/..."> みたいな行は絶対に入れない。

ごりら
ごりら

キャッシュ残ってる時は DevTools → Application → Service Workers → Unregister で一度切るといい。

ビルドスクリプトの設定(frontend/package.json)

postbuild で public/dist/ コピー:

{
  "scripts": {
    "build": "vue-tsc -b && vite build",
    "postbuild": "node ./scripts/copy-public-to-dist.js"
  },
  "type": "module"
}
読者
読者

ViteのpublicDirはfalseにするんだよね?

正解!publicDir: false にしないと、Viteが dist/app にコピーしちゃってズレる。

ごりら
ごりら

構成が安定すれば、あとは deploy 前に dist の中身を確認するだけ。

まとめ

Firebase Hosting で SPA + ランディング構成を安全に共存させるには:

  • Vite: base=/app/, outDir=dist/app, publicDir=false
  • ルート用HTMLは public に置き、postbuild で dist にコピー
  • firebase.json は /app/** → /app/index.html でSPAフォールバック
  • Router: createWebHistory(‘/app/’)(末尾スラ付き)
  • landing.html ではSPA資産を読み込まない!

これで AdSense の審査も通るし、PWAとしても快適に使える構成になるぞ!

ごりら
ごりら

この構成、もうゴリ押しで鉄板だ。未来の自分にもこのまま残せ!

コメント

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