🏔️

Nuxt SSR × Wordpress × Vercel = Super Cool Website !!

2022/08/20に公開

なんでこの記事を書こうと思ったのか

こんにちわ。東京の原宿という意味わからない街にあるクリエイティブエージェンシーで働いている。いとうです。

今回は表題にある通り、WordpressとNuxt SSR、ホスティングサーバーはVercelの構成を紹介していきたいと思います。

早速説明に入る前に、画面の前のあなたはHeadlessCMSをご存知ですか?

簡単に説明すると、従来のサイトは記事を更新するために一つのサーバーにMovable TypeやWordpressといったコンテンツを管理するシステムとデータベースが入っていました。HeadlessCMSはその前提を無くし、ホストするサーバーとコンテンツを配信するサーバーに分けたものになります。ホストするサーバー内で、SSG(静的サイト生成)であれば生成する際にコンテンツを取得、静的なHTMLとして書き出し。SSRであれば、サイトを閲覧する都度、サーバーからコンテンツを引っ張って生成する仕組みです。

ざっくりとそんな感じで、何がいいかというとホストするサーバーとコンテンツを取り扱うサーバーを分けることで

  • 閲覧ページからの悪意あるアクセスを防ぐ。
  • 静的な生のHTMLだけを配信すればデータを取ってくるスピードのロスがないので表示速度が上がる。
  • (開発者にもよるが)Nuxt.jsやNext.jsといったNode.jsで動いているフレームワークなら表現の幅も広がる
  • etc….

といった恩恵を受けることができます。

今回の要件

今回の構成では Nuxt2.16、Wordpress6.0を使用しています。

Nuxtは最新版だとNuxt3 RC6 が出ていますが、2022年8月現在、まだアニメーションや表現などの都合上実用的でないなどの判断で採用を見送りました。

また、クライアントからの要望でコンテンツを柔軟に管理できるようにするために、ACFを導入します。

APIとして使用するのは、かの有名なWP-REST-API です。英語日本語含めて、ドキュメントが多いのがいいですね。海外の記事でも今は DeepLがあるので簡単に勉強することができます。

Wordpressの設定

プラグイン

  • Advanced Custom Fields PRO
  • All-in-One WP Migration
  • Contact Form 7
  • Contact Form CFDB7
  • Redirection

最低限、以上の5つのプラグインがあれば大丈夫だと思います。

権限など

他の記事を見かけると、Application Password というプラグインを入れるように推奨している記述が見えますが、どうやらいらないみたいです。Wordpress5.6以上から同じ機能を持ったアプリケーションパスワードの機能が追加されています。

CMSのサイドバー > ユーザー > 管理者権限のあるユーザー から一番下にある「アプリケーションパスワード」の欄で、任意の値を設定しましょう。

ここで設定しないと

  • 記事の取得
  • コンタクトフォームへの送信
  • 下書きの取得

などが使えません。

Nuxtの設定

nuxt.config.jsの設定

前提として、@nuxtjs/axios をインストールしておきます。

色々と省略しますが、設定は以下のような感じになります。

nuxt.config.js
import axios from 'axios'
const cmsUrl = "CMSのURL"
export default {
	publicRuntimeConfig: {
    baseURL: cmsUrl,
  },
  modules: [
    '@nuxtjs/axios',
  ],
  // modules
  axios: {
    proxy: true,
    baseURL: cmsUrl,
    headers: {
      Authorization: 'アプリケーションパスワードで設定した情報',
    },
  },
}

となります。

CMSのURLを定数に代入した上で、publicRuntimeConfig と axiosの baseURLに格納しています。


アプリケーションパスワードで設定した情報 にはユーザ名とパスワードを ユーザ名:パスワード と1文字にした上で、Base64形式でエンコードした文字列を貼り付けます。

例えば

ユーザ名 : hogehoge
パスワード : 123456

であれば hogehoge:123456 となり、これをBase64で変換すると、aG9nZWhvZ2U6MTIzNDU2 となります。

設定としては

nuxt.config.js
axios: {
  proxy: true,
  baseURL: "CMSのURL"',
  headers: {
    Authorization: 'Basic aG9nZWhvZ2U6MTIzNDU2',
  },
},

となるかと思います。

これを設定することによって、Vuexなどでサイトデータを取得する際に

store/index.js
// const endpoint = ''
export const state = () => ({
  news: []
})

export const actions = {
  async nuxtServerInit({ dispatch }) {
    await dispatch('getNews')
  },
  async getNews({ commit }) {
    const news = await this.$axios
      .get('/wp-json/wp/v2/news?_embed&per_page=100&order=desc')
      .then((res) => res.data)
      .catch((err) => {
        return []
      })
    commit('setNews', news)
  },
}

export const mutations = {
  setNews(state, data) {
    state.news = data
}

とヘッダー情報とbaseURLを省略した書き方ができます。

ボトルネックだった部分

ここではボトルネックだった詰まった部分を書いていきます。

フォーム機能

前提としてフォームの仕様要件は

  1. 複数フォーム
  2. 確認画面の実装
  3. 送受信者両方にメール通知
  4. 受信内容をCMSで見れるようにする

といった感じです。

前提として、フォームにaxiosでポストできて、通知メールも飛ばせて、CMSで受信内容も見れるとなるとこちらの2つのプラグインが必要になります。

  • Contact Form 7
  • Contact Form CFDB7

インストールして設定を終えたら、

pages/contact/index.vue
async send() {
  const axiosConfig = {
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
    },
  }

	const data = {
		name: 'itoh',
		mail: 'hoge@hoge.com'
		message: ' Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut e'
	}
	const id = "contact-form 7でフォームを作った際にできたスラッグ"
  const formData = new FormData()
  Object.entries(data).forEach(([key, value]) => {
    formData.append(key, value)
  })
  await this.$axios
    .post(
      `${this.$config.baseURL}/wp-json/contact-form-7/v1/contact-forms/${id}/feedback/`,
      formData,
      axiosConfig
    )
    .then((response) => {
      this.$router.push('/contact/thanks')
    })
    .catch((error) => {
      console.log(error)
    })
},

といった感じでメソッドをcontactページに実装していきます。

あとは送った後でサンクスページに飛ばすようにすれば完了です。

下書き機能

こちらが地味に実装がめんどくさい下書き機能。

Wordpressだと標準で兼ね備えてる機能なので、Nuxtを採用した手前、実装しないとCMSを使う側でフラストレーションが溜まります。

そもそもWP-REST-APIは一覧を取得した際に、?status=draft とつけると下書きの情報を取得できる状態になっているのですが、しかしこれは動きません。

この機能はそもそも、Wordpressにログインしてるユーザにしか取得できないようになっているからです。

しかし前述、アプリケーションパスワードの設定でBase64の形のユーザ名とパスワードはあるので、シンプルにNuxt上でマウントしたらaxiosのヘッダーに同じように認証情報を送れば取得できるようになります。簡単ですね。

しかし、これだけだとWordpress上の編集画面にある「変更をプレビュー」を押したところでNuxtで作ったフロントの画面には飛びません。

このときに必要になってくるWordpressのプラグインがRedirectionです。

物としてはWordpress上でページに飛んだ際に別の場所にリダイレクトできる物なのですが、こちらを使って、例えば https://cms.com/news/123 などに飛んだらフロント側にある https://front.com/news/123 へとリダイレクトするようにします。

さらに設定する際にクエリーを渡せるように「無視してターゲットにパラメータを渡す」を選択しましょう。

私は以下のように設定しました。

そうすることでhttps://cms.com/news/123?preview=truehttps://front.com/news/123?preview=true に遷移するので、Nuxtのmounted関数などで「もしもpreviewというクエリがあったら下書きを取得」などで分岐するようにしてください。

サイトマップ

サイトマップは本当にめんどくさい仕様でした。これはWordpressやNuxtがどう、というよりもVercelの仕様がめんどくさい仕様でした。

Nuxtでsitemapを生成する場合は、@nuxtjs/sitemap をインストールしてください。

基本的には記述方法もインストール方法も公式のドキュメントに沿って大丈夫です。

Introduction

ただし、これだけではローカルでは生成されるのですが、VercelでSSRしてる状態だとサイトマップは生成されません。

Nuxtのビルドとホストコマンドは npm run buildnpm run start なので、そこは念頭にき、Vercelでは vercel.jsonというファイルをリポジトリルートに置くことで様々な設定ができるようです。

私は以下のように書きました。

vercel.json
{
  "version": 2,
  "builds": [
    {
      "src": "nuxt.config.js",
      "use": "@nuxtjs/vercel-builder",
      "config": {
        "serverFiles": ["package.json", ".nuxt/dist/sitemap-routes.json"]
      }
    }
  ],

  "routes": [
    {
      "src": "/sw.js",
      "continue": true,
      "headers": {
        "Cache-Control": "public, max-age=0, must-revalidate",
        "Service-Worker-Allowed": "/"
      }
    }
  ]
}

こう書くことで .nuxt/dist/sitemap-routes.json を参照して sitemap.xml を生成してくれます。

公開設定

公開するときは当たり前ですがBasic認証を外して、サーチコンソールに登録して、、、といつもと変わらない作業をするだけですね。簡単です。

ドメインもVercelに接続して完了です。

もしもサイトのリニューアルの場合は、メールサーバーと繋げなくてはいけないので注意して下さい。いつも使ってるサーバーからVercelにネームサーバーを変えたらメールが来なくなったなんて悲劇は何度も起こってきました。

最後に

インタラクティブなサイトを作る上で、純粋にJavascriptだけでサイトを作れてしまうHeadlessCMSという技術の恩恵を一度受けてしまうとなかなか難しいところがあります。

「良いサイトを作る」という目標を持つならWordpressのヘッドレス化は今の時代必要な知識かもしれません。
文章を書くことに慣れていないので、記述した内容で間違えている部分や、わからない部分があればここのコメントかTwitterにリプを飛ばしていただけると嬉しいです。

こちら私が今まで作ったサイトをまとめたモーメントです。1度でも良いので見てくれると励みになります。
https://moment.frontartgraph.com/

ここまで読んでいただけてありがとうございました。またどこかで。

Discussion