SSRしないNuxt.jsでページロード時に非同期部分を更新する方法

Nuxt.jsでは、外部サーバ等から非同期でデータを取得・表示する場合にも asyncData を使ってあげることでクライアントサイドはもちろん、サーバサイドでもデータを取得し、HTMLで出力することが出来ます。

SSRできる本番環境があれば何の問題もないのですが、SSRせずプリレンダリングのみで運用する場合には、 asyncData は静的ファイルをgenerateした時点でしか走っておらず、ページロード時にデータが更新されていない問題が起こり得ます。

例えばコーポレートサイト等で、別のサーバにWordPressが設置してあり、トップページのお知らせとしてWordPressから記事を取得するような場合を想定すると、こんな感じで作ってあげることで解決できます

// 非同期でデータを取ってくる関数
async function getPostData() {
  return { data } = await axios.get('https://blog.example.com/wp-json/wp/v2/posts');
}

export default {
  async asyncData(context) {
    const obj = {};
    if (context.isServer) { // asyncDataするのはサーバサイド(プリレンダリング時)のみ
      obj.posts = await getPostData();
    }
    return obj;
  },
  async created() {
    if (!this.$isServer) { // クライアントサイドはここで更新をかける
      this.posts = await getPostData();
    }
  },
};

要は asyncData を使うのはサーバサイド(プリレンダリング時)のみ。
クライアントサイドでは created でデータの更新をかけてあげるわけです。

こうすることでプリレンダリング運用でも、一応(少し古いかもしれないけど)非同期データのHTMLもプリレンダリングされていて、ブラウザで訪れた際にはちゃんと最新の情報に更新されます。

PhpStormでnode製サイトのプレビューをする

node製サイトを開発時はwebpackを利用していればwebpack-dev-serverなどを利用するのが常ですが、プロダクションビルド後のファイルで確認したい場合もあります。

そういうときにわざわざサーバーにアップロードしたり、MAMPなどを利用するのは面倒です。ですが、PhpStormであればビルドも含めてショートカット1発でサーバーを起動することができます!

今日はその設定をしていきましょう。設定は1分で終わります。

Step.1 サーバー設定

「Run」->「Edit Configurations」から「Run/Dubug Configurations」のウィンドウを表示し下記に設定します。

  • Name: Preview server(好きな名前を設定してください)
  • Single instance only: チェックを入れる(重複起動を許可しないかのチェックです)
  • Host: localhost
  • Port: 3001
  • Document Root: ドキュメントルートへのパス

HostとPortは他のアプリケーションが利用中だと起動できないので、webpack-dev-serverやMAMPなどを利用している場合は被らないように設定するのが吉です。

Step.2 npmスクリプトの起動設定

次に「Before launch: Acvtive tool window」で「+」をクリックして「Run npm script」をクリックします。

すると「NPM Script」のウィンドウが開くので下記に設定します。

  • Command: run
  • Scripts: build(など自分でpackage.jsonに設定したスクリプト名)

Step.3 起動

あとは^ Rまたは「Run」->「Run 'Preview server'(上記のName:で設定した名前)」をクリックすれば指定したHostとPortでサーバーが起動します。

PhpStormなどJetBrains製のIDEはWeb関係の技術と親和性が高いので、Web開発者は必携ですね。

Vue.jsでSSRする場合にv-forでエラーが出る

Nuxt.jsを含めて、Vue.jsの2.xを使ってSSR(サーバーサイドレンダリング)をする場合に、 v-for の箇所で下記のようなエラーが出る場合がある。

The client-side rendered virtual DOM tree is not matching server-rendered content.

再現したコードはこれ( items は単純な文字列の配列)。
ちなみにVue.jsのバージョンは 2.2.6

<template v-for="item in items">
  {{ item }}
</template>

回避するには、下記のように個々を要素で囲ってあげる。

<template v-for="item in items">
  <span>{{ item }}</span>
</template>

クライアントサイドのみではエラーは出ず、ちゃんとレンダリングされるので、サーバ側の実行ロジックにバグがあるのかもしれない。

WP REST API では1回のリクエストでカテゴリーを全件取得することはできない

タイトルの通りですが、WP REST APIでカテゴリー情報を取得する場合、下記のエンドポイントを使いますよね。

/wp-json/wp/v2/categories

これに対してパラメータ per_page で取得件数を設定できるのですが、実はこのパラメータ、1〜100の数値以外を渡すとエラーになります。

ドキュメントにも取りうる値の範囲は記載されていません
https://developer.wordpress.org/rest-api/reference/categories/

なんとなく語感がget_postsでよく使う posts_per_page に似てるので-1を指定すれば全件取得できそうな気がするのですが、ところがどっこいできません。

おそらくパフォーマンスの問題で無茶な使い方を塞がれてるんだと思うのですが、100件以上になりうる可能性がある場合は、本当に必要なカテゴリーだけをパラメータ include で指定して取得してあげるほうが良さそうです。

それでも100件以上欲しい場合は、パラメータ page でしっかりロジカルにページングする必要がありそうです。