Nuxt.jsのUniversalとSPAが全然理解できなかったので実際に動かして学ぶことにした

シェアする:

今回はNuxt.jsのUniversalとSPAについて考えます。

対象者は僕と同じように「WordPressばっかりだったけどNuxt.jsに興味を持った人」、あるいはそれに類似するレベルの人で、

  • Node.js
  • Vue.js
  • Nuxt.js
  • その他JavaScript系フレームワーク

に関する知識があまりない人です。

UniversalとSPAの違いについてはいろんなサイトで解説されていますが、当初の僕は全く理解ができませんでした。

なので、「ベテランから初心者へ向けた解説」ではなく「初心者が初心者へ送るメモ書き」のような、ちょっと変わった切り口でお話したいと思います。

それ故に伝わりやすい部分もあると思っていますが、逆にいい加減な部分もきっと含んでいます。 しっかり理解したい人はもっと知識のある人の解説を読んでください。

なるべくいい加減にならないよう、具体例や根拠、実験結果とともにお届けします!

WordPressの上でな!

※ このブログはまだWordPress製です

いきなり迫られるUniversalとSPAの二択

Nuxt.jsをインストールすると、早々にこの二者択一に迫られます。


? Rendering mode: (Use arrow keys)
❯ Universal (SSR / SSG) 
  Single Page App 

両方なんのこっちゃ分からんので、少し調べると「Universal」はSSR=サーバサイドレンダリングであることが分かります。

何をサーバでレンダリングするのかは分かりませんが、となると対義語は「クライアントサイドレンダリング」のはず。

ところが実際にはSPA=シングルページアプリケーションとなっていて、さっそく訳が分かりません。

そもそもアプリじゃなくてWebサイト作ろうとしてるねんけど…。

で、まぁテキトーに「Universal」を選ぶと今度↓は新たな二択。


? Deployment target: (Use arrow keys)
❯ Server (Node.js hosting) 
  Static (Static/JAMStack hosting) 

いやいや、さっきサーバのやつ選んだやん…。

「Server」はともかく、余事象の「Static」は「サーバサイドだけどServerじゃない」という謎極まる選択肢になってしまっています。

さらには「SPA」の方を選んでもこの選択肢が出てきます。 今度は「サーバサイドじゃないのにServer」という謎選択肢です。

なんでこんな事になるかと言うと、当然僕が無知なせいでして。 Nuxt.jsはこの辺の知識がある程度ある人向けのフレームワークなんでしょう。

今回の記事は、あの日の僕が、

その説明なら理解できるよおおお!。

と言ってくれそうな内容にします。

オレにも分かるUniversalとSPAの違い

一般には前者を「SSR=サーバサイドレンダリング」、後者を「SPA=シングルページアプリケーション」と説明していることが多い気がします。

で、そこから「SSRとは!?」「SPAとは!?」みたいな流れになるんですが、今はそんな知識いりません。

UniversalとSPAの違いは、

HTMLの<body>に本文が含まれるか含まれないか!

です。

実際にビルドしたHTMLファイルをお見せします。 一目瞭然です。

サンプルとして以下のような超シンプルなページを作りました。


<div>
<h1>ここはHOMEです</h1>
<a href="/">HOME</a>
<a href="/test/">TEST</a>
</div>

Universalで出力したHTML


<!doctype html>
<html data-n-head-ssr>
<head>
(略)
</head>
<body>
<div data-server-rendered="true" id="__nuxt">
<div id="__layout">
<div>
<div>
<h1>ここはHOMEです</h1>
<a href="/">HOME</a>
<a href="/test/">TEST</a>
</div>
</div>
</div>
</div>
</div>
<script>
window.__NUXT__ = { staticAssetsBase:"/_nuxt/static/1598422137", layout:"default", error:null, serverRendered:!0, routePath:"/", config:{}}
</script>
<script src="/_nuxt/runtime.4a5d85c.js" defer></script>
<script src="/_nuxt/pages/index.2ea7947.js" defer></script>
<script src="/_nuxt/vendors/commons.08b56d8.js" defer></script>
<script src="/_nuxt/app.a7abfbc.js" defer></script>
</body>
</html>

Nuxt.jsが自動生成したコードが多数ありますが、先ほどの本文が赤字の部分に確認できます。

SPAで出力したHTML

それに対してSPAのHTML。


<!doctype html>
<html>
<head>
</head>
<body>
<div id="__nuxt">
<style>(略)</style>
<script>
window.addEventListener("error",function(){var e=document.getElementById("nuxt-loading");e&&(e.className+=" error")})
</script>
<div id="nuxt-loading" aria-live="polite" role="status">
<div>Loading...</div>
</div>
</div>
<script>
window.__NUXT__={config:{},staticAssetsBase:void 0}
</script>
<script src="/_nuxt/runtime.4d56fe6.js"></script>
<script src="/_nuxt/vendors/commons.71074a9.js">
</script><script src="/_nuxt/app.398b391.js"></script>
</body>
</html>

本文と思しき部分には「Loading…」と書かれ、僕が書いた<h1>と<a>が確認できません。

いやいや、SPAかなんか知らんけど勝手に本文消したらあかんやん。

と思うかもしれませんが、ブラウザで開くときっちり本文も表示されます。

これがUniversalとSPAの違いです。

HTMLに本文が含まれるか含まれないか!

カラッポのHTMLなのに何故SPAはページを表示できるのか?

ブラウザで表示する際にJavaScriptが本文をレンダリングするからです。

ソースには本文がないけど、ブラウザで開くとちゃんと表示される。

言い換えると、表示の際に「クライアント(ブラウザ)サイドでレンダリング」です。

上で「SPAはSSRの対になっていない!」と言いましたが、ちゃんと対になってたんですね。

損得勘定で知るSPAの特徴

SPAとは「出力したHTMLに本文を含まないもの」でした。

なんかこれ、デメリットしか感じなくないですか?

というわけで、メリット/デメリットを中心にSPAの特徴を説明していきます。

SPAのデメリット

本文がない故にSEO的に弱い

HTMLに本文がないということは、検索エンジンが見た場合にもすっからかんということです。

つまり検索エンジンはページの内容が理解できず、SEO的に弱い……

と書いているサイトがけっこうあるんですが、Google公式によると、

Googlebot のリソースに空きができると、ヘッドレスの Chromium がページをレンダリングして JavaScript を実行します。 Googlebot はレンダリングされた HTML のリンクを再度解析し、見つかった URL をクロールするためキューに入れます。 また、Googlebot はレンダリングされた HTML を使用してページをインデックスに登録します。

ちゃんと中身読んでるぞ、と。

さらにはこんな↓記述もあり、

ボットによっては JavaScript を実行できないものもあり、ユーザーやクローラに対してウェブサイトを高速化する効果もあるので、サーバー側でのレンダリング(プリレンダリング)も有効な方法として検討してみてください。

GoogleはちゃんとJavaScript読むけど、そうじゃない検索エンジンもあるからサーバサイドでレンダリングした方がいいよ、ってことなんでしょう。

1ページ目の読み込みが遅い

SPAはシングルページアプリケーションの略で、その名の通り1ページだけで出来ています。

他のページへ移動する際は今のページに、次のページとの差分だけをロードするんですが、これをやるために初回に全ページの情報を読み込むそうです。 リンクの貼られているページの情報を先に読み込みます。

先ほどのテストプロジェクトをChromeデベロッパーツールのNetworkで確認すると、

(クリックで拡大)

トップページを開いただけで「/test/」ページ用のスクリプト(最後の行)を読み込んでいるのが確認できます。

このような2ページ構成くらいなら影響は微々たるものですが、100ページとかになってくると初回のロードにけっこう時間がかかりそう。

SPAのメリット

ページ移動がめちゃくちゃ速い

「1ページ目の読み込みが遅い」の反対の側面です。

他のページを先読みするせいで1ページ目の表示は遅くなりがちですが、対して2ページ目以降の移動。

爆速です!

一度経験すると、もうSPA以外で作りたくなくなるくらいにページ移動が速いです。

サイトを見てるユーザからすると非常にありがたいメリットになるでしょう。

SPAで作ったサイトがあるので是非実感してみてください。

ただし、高速とは言っても初回ロードで判定しているPageSpeed Insightsには評価してもらえず、むしろ点数は悪化しそう。

SPAの「Server」は何なのか?

Nuxt.jsのインストール時に、ここ↓でSPAを選択。


? Rendering mode: (Use arrow keys)
❯ Universal (SSR / SSG) 
  Single Page App 

その次に「Server」を選択するケースのことです。


? Deployment target: (Use arrow keys)
❯ Server (Node.js hosting) 
  Static (Static/JAMStack hosting) 

UniversalとSPAを「サーバサイドかどうか」で考えると訳が分からなくなりますが、「HTMLに本文を含むかどうか」で区別するととりあえずの謎は消えます。

あとは「Server」と「Static」の違いだけ。

Nuxt.jsはNode.js上で動くプログラムで、開発中(npm run dev)はまさにNode.js上で動的に動いています。

これを公開するサーバ側でもやるのが「Server」です。 当然、Node.jsが動いて、なおかつ永続化できるサーバが必要になります。

これに対して、開発環境でHTMLファイルとして出力してしまうのが「Static」です。 もう静的なファイルに書き出してしまっているので、サーバ側にNode.jsは不要。 HTMLファイルをアップロードするだけで使えます。

SPAの特徴まとめ

端的に特徴をまとめると、僕の解釈ではこんな感じになりました。

HTMLに本文を含まない!

ページ移動がめちゃくそ速い!

ただし初回ロードはちょっと遅いよ…

Universalを選ぶとSPAは諦めないといけないのか?

Universalについて説明する前にこのお話を。

SPAはいくつかのデメリットと引き換えに、笑いが出るほどにページ切り替えが速いことを説明しました。

これ、めちゃくちゃ大きいメリットだと思うんですよね。

Universalのメリットがなんであれ、この1点のためだけにSPAを選ぶ価値があると思っています。

なのでまずは「Universalを選ぶとSPAは諦めないといけないのか?」について。

結論:UniversalもSPAである

「何がどうならSPAと呼んでいいのか」

その辺が僕には分からないので本当にSPAと呼んでいいのかが分かりません。

ですが、Universalで作ったサイトもSPAと同様に爆速ページ移動が可能です。

先ほどのサンプルをUniversalで作り直して、ChromeデベロッパーツールのNetworkで確認してみました。

(クリックで拡大)

トップページを開くとSPAの時と同様に「/test/」ページのスクリプトが読み込まれていて、「/test/」ページへ移動しても新たなファイルのロードがありません。

当然、移動は爆速です。

つまりUniversalもSPAで動いている。

UniversalはSPAの上位互換なのでは?

という気がしてなりません。

UniversalでもSPAが有効ならSPAモードとは一体なんなのか…。

今のところ、僕にはSPAを選択する理由が分かりません。

損得勘定で知るUniversalの特徴

はい、だいぶ引っ張りましたがUniversalの番です。

引っ張ったくせに、メリット/デメリットはSPAを反転させるだけという。

Universalのメリット

出力されたHTMLに本文が含まれる

SPAの逆ですね。

ページに本文が含まれるので、検索エンジンやその他のBOTがJavaScriptを実行してレンダリングしてくれなかったとしても、ページの内容を伝えることができます。
(Googleは大丈夫そうでしたが)

SPA同様にページ移動が爆速

上で紹介した通りです。

何故かは分かりませんが、Universalを選んでもSPAになっています。

SPAのSEO的なデメリットを解消できる

HTML自体に本文を含むため、SEO的なデメリットが発生しません。

Universalだと「SEOに強い!」と書いているサイトもあるんですが、思うところあるので後で書きます。

Universalのデメリット

初回のページ読み込みが遅い

SPAモードを選んだ時と同様です。 SPAが有効なせいでリンクが貼られているページの内容を先読みします。

リンクを貼っているページ数が多いと初回ロードがけっこう遅くなりそう。

ただし、これは自分でコントロールが可能で、<nuxt-link>ではなく<a>タグを使ったり、<nuxt-link>を使っても「no-prefetch」にすることで先読みを回避できるようです。

逆に言うとUniversalだろうがSPAだろうが、<nuxt-link>にしないと爆速ページ移動は有効になりません。

Universalでも本文が含まれない場合がある

Nuxt.jsでサイトを作っていく場合、外部のCMS(WordPressとか)からAPIというのを経由してコンテンツを取得することが多いようです。

この際にasyncDataでAPIと通信した場合には、HTMLに本文が含まれます。

ですが、mountedでも同様の処理ができ、mountedでAPIと通信した場合にはHTMLに該当部分が含まれなくなります。
(SPAモード同様に実行時にレンダリング)

コンポーネントの中ではasyncDataが使えないので、コンポーネント内でAPIを取得する必要がある場合はmountedを使うことになります。
(=その部分はHTMLに含まれない)

設計次第ですかね。

Universalの特徴まとめ

端的に特徴をまとめると、僕の解釈ではこんな感じになりました。

ページ移動が速い!SEO的に安全!

デメリットはない!(に等しい)

Universal選んどけば間違いなし!

初回ロードのデメリットは、多大なるメリットの副作用なのでデメリットには含めないことにしました。

「SSRだからSEO対策になる」はかなり誤解あると思う

いや、意味は分かるんですよ。

SPAモードと比べて、ちゃんとHTMLに中身があるから検索エンジンに情報を伝えやすいって意味だと思います。

でもね…、これを「SEO対策になる」と呼んでもいいものでしょうか?

根拠① 別にプラスになっているわけではない

SSRがSEOに強いというのは、中身すっからかんなSPAモードに比べて、の話です。

SPAのマイナスを0に持っていくだけで別にプラスになっているわけではないはず。

根拠② GoogleはJavaScript込みでレンダリングしている

上でも書きましたが、GoogleはJavaScriptをレンダリングしてからページをインデックスしているようです。

これを信じると、「そもそもSPAモードでマイナスだったのか?」という話になります。

SPAにマイナスがなかったのなら、①の「SPAに比べてSEO的に良い」という部分から怪しくなってきます。

Google以外の検索エンジンの場合はその限りではないケースもあるようなので、①に関してはメリットと言えそうです。

根拠③ SSRだからってSEOの勉強しなくていいわけではない

SEOって「SSRにしとけばSEOできるよ!」「AMPにしとけばSEOできるよ!」ってなもんじゃないと思います。

もっと言えば、PageSpeed Insightsの評価が低かろうが、レスポンシブになってなかろうが、SSLに対応してなかろうが、キーワードによってはそんなページが検索1位を取ってます。

たぶんコンテンツが良いからです。

つまりSEOやりたいなら良いコンテンツを作ることを考えるべきであり、SSRにしたからってそれを免除されるわけではありません。

たぶん結果は「SPAだけど良いコンテンツ」>>>>>>>>>>「SSRだけどいまいちなコンテンツ」のはず。

「Server」を選ぶ必要があるケース

最後になりましたが、この↓「Server」ですね。


? Deployment target: (Use arrow keys)
❯ Server (Node.js hosting) 
  Static (Static/JAMStack hosting) 

「Server」を選ぶとサーバ上のNode.jsでNuxt.jsを走らせて、動的にページを出力します。

対してStaticはHTMLとして出力してしまって、アップロードするだけ。

実は僕はこの「Server」をテスト以外でやったことがないです。

というのもデメリット↓が目立つ気がするんですよね。

「Server」を選ぶデメリット

  • 動的出力になるのでStaticに比べて速度的に不利
  • サーバサイドにNuxt.jsを動かす環境が必要
  • Node.jsが動くサーバでなければならない
  • Node.jsを永続化できるサーバでなくてはならない

僕みたいに脱WordPressを考えてNuxt.jsを始めたような人間からすると、デメリットがとても気になります。

特に速度の問題がある以上、どうしてもServerでなければならないサイト以外はStaticでいいんじゃないでしょうか。

Serverでなければならないケース…。

なんだろ。

ログインして、ユーザごとにコンテンツを切り替えるようなケースとか?

ブログ想定だと、記事公開ごとにいちいちビルドしなくていいとか?

僕がやっている範囲では今のところ必須になっていないです。

WordPressのNuxt化でも今のところStaticで問題ありません。

正直、実験不十分なのでまた何か気付いたら書きますね。

まとめ

Nuxt.jsでサイトを作るなら、Universal一択でいいんじゃないかと思います。

なぜならSPAの爆速ページ移動はUniversalでも有効だったので…。

よく分からないなら「Universal」で「Static」!

「Server」じゃないと困る、「Server」で動かす用意がある場合は「Universal」で「Server」!

以上、WordPressからお届けしました!

シェアする: