VercelでNuxtをホスティングする (SPA/SSR)

最近のフロントのホスティングの流行りと言ったら、Vercel

旧サービス名はnowらしい。いまだに、古い情報はnowのサービス名だったりするから、調べるときは頭の中で置換するー

Next.js × Vercel は同じ会社が出していることから最強の組み合わせでしょう。

もちろん、Vue.js / Nuxt.js でも十分活躍できます!

U-labでは、みやメシ.comのフロントもVercelでホスティングしています。

TypeScript×Nuxt×Firebase×Vercelの構成はみやメシで作ったので、GitHub参照を推奨します。

参考 みやメシ.com TypeScript×Nuxt×Firebase×Vercelの構成GitHub

まず初めに

Vercelにホスティングするとき、どのパターンを試すにしても、nuxt/pwa を入れるのをおすすめします。

入れて損しない。設定も軽い。詳しくは公式ドキュメントのsetupを見てほしい。

$ npm i --save-dev @nuxtjs/pwa
# or
$ yarn add --dev @nuxtjs/pwa

nuxt.config.jsに以下を追加。

{
  buildModules: [
    '@nuxtjs/pwa',
  ]
}
参考 nuxt/pwanuxt/pwa 公式ドキュメント

SPA

基本的に、画面ポチポチーー。

まあ、SPAならVercelではなく、Netlifyでもいいような気がするー。

さて、Nuxt/SPA×Vercel に戻ります。

まずは、ディレクトリ構成ですが、一般的なこれです。特に、何かvercelのためにファイルを追加する必要はなし。

--
 |- assets
 |- components
 |- layouts
 |- middleware
 |- pages
 |- plugins
 |- static
 |- nuxt.config.js
 |- package.json
 |- README.md

Build & Development Settings はすべてデフォルトで十分。

SSR

最初やったときは難しかったけど、今では、数か月前より簡単になった印象がある。基本的には、デフォルトでよい!と思います。

まずは、ディレクトリ構成ですが、一般的なこれです。

--
 |- assets
 |- components
 |- layouts
 |- middleware
 |- pages
 |- plugins
 |- static
 |- nuxt.config.js
 |- package.json
 |- vercel.json
 |- README.md

まずは、 vercel.json を nuxt.config.js を同じディレクトリにおこう。

{
  "version": 2,
  "public": true,
  "builds": [
    {
      "src": "nuxt.config.js",
      "use": "@nuxtjs/vercel-builder",
      "config": {
        "serverFiles": ["package.json"]
      }
    }
  ],
  "routes": [
    { "src": "/_nuxt/.+", "headers": { "Cache-Control": "public, max-age=31536000" } },
    {
      "src": "/sw.js",
      "dest": "/_nuxt/static/sw.js",
      "headers": {
        "cache-control": "public, max-age=43200, immutable",
        "Service-Worker-Allowed": "/"
      }
    },

    {
      "src": "/(.*)",
      "headers": { "cache-control": "s-maxage=1, stale-while-revalidate "},
      "dest": "/"
    }
  ]
}

Build & Development Settings はすべてデフォルトで十分。

サブディレクトリでのSSRデプロイ

よくある構成?は以下のような感じでしょうか。src配下にnuxtを入れる構成。

--
 |- .idea
 |- src
    |- assets
    |- components
    |- layouts
    |- middleware
    |- pages
    |- plugins
    |- static
    |- nuxt.config.js
    |- package.json
    |- vercel.json
 |- .gitignore
 |- README.md

まずは、vercel.jsonをsrc配下、すなわち、nuxt.config.jsを同じディレクトリにおこう。

{
  "version": 2,
  "public": true,
  "builds": [
    {
      "src": "nuxt.config.js",
      "use": "@nuxtjs/vercel-builder",
      "config": {
        "serverFiles": ["package.json"]
      }
    }
  ],
  "routes": [
    { "src": "/_nuxt/.+", "headers": { "Cache-Control": "public, max-age=31536000" } },
    {
      "src": "/sw.js",
      "dest": "/_nuxt/static/sw.js",
      "headers": {
        "cache-control": "public, max-age=43200, immutable",
        "Service-Worker-Allowed": "/"
      }
    },

    {
      "src": "/(.*)",
      "headers": { "cache-control": "s-maxage=1, stale-while-revalidate "},
      "dest": "/"
    }
  ]
}

ポイントは、vercelの画面でRoot Directoryで src を選ぶこと!

Build & Development Settings はすべてデフォルトで十分。

SSRでデプロイするときにはまった点

static内の画像がとれない問題

なぜだかわからないが、static内の画像がうまく取得できなかった。そのため、vercel.jsonにroutesを増やして対処した。

ディレクトリ構成で以下のように、static内に sディレクトリを作った。もちろん、ディレクトリ名は任意。

--
 |- pages
 |- static
   |- s
     |- sample.png
     |- hoge.jpg
 |- nuxt.config.js

そして、vercel.jsonでroutesに /s を参照するように明示的に指定をする。

追記分

{
   "src": "/s/(.*)",
   "headers": { "cache-control": "public, max-age=31536000" },
   "dest": "/s/$1"
},

全体でvercel.jsonを見るとこんな感じ。

{
  "version": 2,
  "public": true,
  "builds": [
    {
      "src": "nuxt.config.js",
      "use": "@nuxtjs/vercel-builder",
      "config": {
        "serverFiles": ["package.json"]
      }
    }
  ],
  "routes": [
    { "src": "/_nuxt/.+", "headers": { "Cache-Control": "public, max-age=31536000" } },
    {
      "src": "/sw.js",
      "dest": "/_nuxt/static/sw.js",
      "headers": {
        "cache-control": "public, max-age=43200, immutable",
        "Service-Worker-Allowed": "/"
      }
    },

    {
      "src": "/s/(.*)",
      "headers": { "cache-control": "public, max-age=31536000" },
      "dest": "/s/$1"
    },
    {
      "src": "/(.*)",
      "headers": { "cache-control": "s-maxage=1, stale-while-revalidate "},
      "dest": "/"
    }
  ]
}

そもそも、static内ではなく、assetsに入れて、importで読み込むべきなきもするが、どうしてもstaticに入れたかったから、このようになった。

Firebaseがうまくいかない問題

これに助けられた。

参考 Vercel(Now.sh)にNuxt.js(SSR)をデプロイすると、Firebase関連でSSR時にNuxt.js Internal Server Errorになるのを修正するQiita

参考記事

参考 Vercel へデプロイするには?nuxt.js 参考 Nuxt.js Vercel BuilderGitHub