【Snow Monkey】高速化しやすい WordPress テーマで PageSpeed Insights の高得点を狙う!

Snow Monkey Advent Calendar 2020 の18日を担当します、みんかぴです!
6年ほどプライム・ストラテジーという会社でエンジニアとして働き、今は株式会社mgnで働いています。
株式会社mgnはSnow Monkey エキスパートだったり、Snow Monkey の拡張パック「類人猿」を発表したりと、個人的にずっと好きだった Snow Monkey に深く携わることができて、毎日楽しみながら働いています。

私個人は、Snow Monkey を使い始めて1年ちょっとが経過しました。使いやすいテーマがあるとWordPressコミュニティ内でワイワイしていて、気になって気になって購入してからというもの、このサイトで利用させてもらっています。有料テーマを買うのは初めてでしたが、これのおかげでコードを書くことが本当に減りました。キタジマさんありがとうございます!!

今回 Advent Calender で何を書こうかなーと迷いましたが、つい最近までWebサイトの高速化ばかりしていたので、それについて書こうと思います。Snow Monkey はすごく高速化しやすいテーマなんですよ!

Webサイトの高速化は手がつけづらい

Google先生が「Wedサイトを高速化してください!」と言ってから何年も経過しました。PageSpeed Insights というツールも出て、サイトの表示速度をスコアで確認することもできるようになりました。
発表されてすぐに計測してみて、意外な結果に愕然とした方も多いと思います。
最近は「Core Web Vitals」がランキングの順位に組み込まれ、より高速化の重要性が上がってきているように思います。それでなくても、UX向上によって回遊率が上がるとかコンバージョン上がるとか、速ければそれだけサイトの売上に対する価値って上がりますよね。

Webサイトを高速化しよう!と思ったとき、どういった方法があげられるでしょう?

  • 画像の最適化や遅延読み込み
  • ひたすらキャッシュ、もしくは静的書き出し
  • CSSとJavaScriptの整理
  • サーバのスペックアップ

他にもいろいろなものが思い浮かびますが、いったいどこから手をつければいいのやら。簡単なものも少ないし。頑張った結果どれくらいの改善が見込めるのか。そんなこんなで結局後回しにしがちですよね。

Google の高速化に対する見解、PageSpeed Insights を知ろう

PageSpeed Insights はどのようにしてあのスコアを算出しているのでしょう。Googleが速度の指標として公開しているくらいです。これを知れば、どういった改善方法があり、どれくらいの改善が見込めるのか、なんとなくでも知ることができそうです。

PageSpeed Insights のスコアは、Lighthouse というツールが測定した結果です。ラボデータの項目ごとのウェイトも公開されています。以下はラボデータの項目を、Webサイトが表示されるまでの流れに極力合わせて並べ替えてみたものです。


First Contentful Paint

15%(高速判定:2秒以下)
ページの読み込みが開始されてから、ページのコンテンツの一部が画面に表示されるまでの時間を測定します。

Largest Contentful Paint

25%(高速判定:2.5秒以下)
ページの読み込みが開始されてから、最大のテキストブロックまたは画像要素が画面にレンダリングされるまでの時間を測定します。

Time to Interactive

15%(高速判定:3.8秒以下)
ページの読み込みが開始されてから視覚的にレンダリングされ、最初のスクリプト(存在する場合)が読み込まれるまでの時間を測定します。

Total Blocking Time

25%(高速判定:300ミリ秒以下)
FCPとTTIの間で、入力の応答性を妨げるのに十分な時間メインスレッドがブロックされた合計時間を測定します。

Cumulative Layout Shift

5%(高速判定:0.1未満)
ページの読み込みが開始されてからライフサイクル状態が hidden に変わるまでの間に発生するすべての予期しないレイアウトシフトの累積スコアを測定します。

Speed Index

15%(高速判定:4.3秒以下)
ページの読み込み中にコンテンツが視覚的に表示される速度を測定します。ブラウザに読み込まれるページをキャプチャし、フレーム間の視覚的な進行を計算します。

参考:User-centric performance metrics


Largest Contentful PaintTotal Blocking Time だけで、スコアの半分を占めています。ぜひそれぞれの詳細を読んでみてください。そのスコアを改善する方法なども記載されています。英語ですが、Google翻訳でなんとなく読むことができます。
(個人的には Cumulative Layout Shift ページの再現動画が好きです。押そうとしたボタンの位置がズレて、うおおおおぉぉぉぁあああああ!!!???ってなってるのが本当に面白い。)

そして、皆さんが必ず見るであろう PageSpeed Insights の「改善できる項目」は、スコアの数値には直結していません。この項目を改善すれば、ラボデータ側のスコアが改善するかもしれないよーという、間接的なものです。
改善項目をなくそうとするためだけの改修方法を検討するより、前述したラボデータがそれぞれ、どういった理由からどのような点を測定しているのかを理解したほうが、本当に必要な改善項目が見えてきます。

Webサイトが表示されるまでの流れ

ページの読み込みが開始されてから・・・などの記載がありましたが、Webサイトが表示されるまでの流れをおさらいしてみましょう。

Webサーバがリクエストを受け取る

閲覧者のブラウザから、WebサーバにHTTPリクエストが送られ、それをWebサーバが受信します。

Webサーバでアプリケーション・DBなどがページを生成する

HTTPリクエストを受け取ったWebサーバはそれをアプリケーションに渡し、アプリケーションはそのHTTPリクエストに応じたページを生成します。WordPressであれば、PHPが動き、MySQLが動き、ページが生成されます。

Webサーバがページを返す

生成したページをHTTPレスポンスとして、Webサーバが閲覧者のブラウザに返します。

ブラウザにページが表示される

HTTPレスポンスを受け取ったブラウザは、HTMLとCSS、JavaScriptなどを解析・動作させてページを描画します。

この流れを、青と緑と赤に色分けしてみました。青が「ネットワーク」の部分で、緑が「Webサーバの動的処理」の部分、赤が「レンダリング」の部分です。

ラボデータの項目の中で一番速く測定が終わるものは First Contentful Paint ですが、「ページの読み込みが開始されてから、ページのコンテンツの一部が画面に表示されるまで」です。すでにネットワークレイヤーの処理も、Webサーバの動的処理レイヤーの処理も終わっていて、レンダリングレイヤーの途中までということになります。この時点で、ネットワークとサーバ、アプリケーションの遅延は全ラボデータスコアに影響するということが分かります。

ネットワークとサーバ、アプリケーションだけを高速化すれば良いの?

改善前のこのサイトのラボデータをチラ見せします。

改善前のみんめものラボデータ

ページのコンテンツの一部が画面に表示された FCP 完了時点から、操作ができるようになる TTI 完了まで、だいたい10秒かかっていることになります。そして、この結果上の最初のサーバ応答時間は790ミリ秒だったのです(推奨は600ミリ秒未満)。

最初のサーバ応答ではHTMLが返され、その後に画像だったりCSSだったりJSだったりの必要なリソースをやり取りします。HTMLが返されているということは、その時点でWordPressは動作済み。その後のやり取りでは、JSなどでコンテンツ生成のためにアプリケーションやDBを起動しない限り、単に静的リソースを返すだけになります。そして、First Contentful Paint の高速判定は2秒未満です。

これだけの情報が集まれば、だいたいのボトルネックの想像がつきます。

  • ネットワークレイヤーのボトルネックと、リソースの多さ
  • JSなどでコンテンツ生成のためにアプリケーションを起動し、それを多用している
  • レンダリングレイヤーのボトルネック

そして先に言ってしまうと、レンダリングレイヤーがボトルネックであることがほとんどですし、もっと言えばこういった結果で遅い判定を受けているサイトがほとんどなのです。さらに言ってしまえば、このレンダリングレイヤーの改善こそが、エンジニアにとって一番厄介な部分なのです。

「レンダリング」って意外とよく知らないよね

レンダリングの流れを知り、さらにどういった部分がボトルネックになるのかを知るには、以下のページを読むのをおすすめします。

なんでAMPは早いの?

AMPページは以下のような制限を設けることで、全レイヤーのボトルネックをなくしています。

・AMPサーバから返すことで、ネットワークとWebサーバの動的処理レイヤーを最適化。

・JSやCSSの利用を制限することで、レンダリングレイヤーを最適化。

Snow Monkey で作られたこのサイトを速くする

つらつらと前置きが長くなりましたが、ではでは、Snow Monkey で作られた、この「みんめも」を高速化してみましょう!

改善前のみんめも

  • サーバ
    • KUSANAGI for さくらのクラウド
      • Premium Edition アップグレード済み
        (企業が運営するサイトじゃなきゃタダ!そして私のサーバは非推奨スペック!)
      • nginx と PHP7
      • bcache / fcache OFF
      • 翻訳アクセラレータ 有効
      • 画像最適化 有効
      • WEXAL 非導入
  • WordPress
    • Snow Monkey
    • Enlighter – Customizable Syntax Highlighter
    • Site Kit by Google
    • Snow Monkey Blocks
    • Snow Monkey Diet(設定はデフォルト)
    • Snow Monkey Editor
    • etc…
    • Google AdSense の自動広告あり

トップページと投稿ページそれぞれを測定してみます。

改善前のトップページのPSIスコア
改善前の投稿ページのPSIスコア

散々な結果ですね!!詳細ページなんか、レンダリングに時間がかかっているのがよく分かります。表示の推移が真っ白!

でもがっくりしている時間はありません!高速化していこう!

公式が提供している高速化手法

環境に依存せず、Snow Monkey 利用者ならすぐにできる高速化からやってみましょう。

カスタマイザー > ページ速度最適化

見てみたら、「軽量な FontAwesome を使用する」だけ ON になっていました。とりあえず全部 ON にしてみます。ブラウザキャッシュは nginx なので効かなそう。jQuery だけ心配でしたが、私のサイト構成では特にエラーは出ませんでした。

早速測定してみましょう!わくわく!

カスタマイザーのページ速度最適化を利用した改善後のトップページのPSIスコア
カスタマイザーのページ速度最適化を利用した改善後の投稿ページのPSIスコア

いい感じに改善しましたね!特にFCPが大きく改善しています。

設定できる項目を、ざっくりレイヤーに分類してみました。

ネットワークレイヤーに関する項目(青がなかった・・・)

・HTTP2 Server Push を使用する

・リンクの先読み機能(prefetch)を使用する

Webサーバの動的処理レイヤーに関する項目

・ブラウザキャッシュを使用する

・ヘッダーをキャッシュ

・フッターをキャッシュ

・メニューをキャッシュ

・ウィジェットエリアをキャッシュ

レンダリングレイヤーに関する項目

・jQuery の読み込みを最適化する

・CSS を head に出力する

・軽量な FontAwesome を使用する

Snow Monkey Diet

設定できる項目を見てみましたが、「再度有効化したときに再設定が必要になる場合があります。」という項目が怖かったのと、無効にできるものがそこまで表示速度に影響しなさそうだったので、今回はパスしました。サイトによってはがっつり無効化できる気がします!

KUSANAGI

ここからは環境依存の改善方法を進めます。私は前職の関係で、KUSANAGIとWEXALをずっと利用してきました。そういった手前とか関係なく、今でも私はこのプロダクト郡が好きです。なので、これらを利用して高速化を行っていきます。

KUSANAGI では、bcache と fcache を ON にしてみます。bcache は WordPress のキャッシュが、fcache は nginx の FastCGIキャッシュが有効になります。

[root@minkapi minkapi_style]# kusanagi bcache on
Turning on
Done.
[root@minkapi minkapi_style]# kusanagi fcache on
Turning on
use nginx
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Done.

こんな感じ。キャッシュなので、Webサーバの動的処理レイヤーに関わってきます。nginx の FastCGIキャッシュが HIT すれば、静的リソースを返しているのとほぼ同意義になります。

KUSANAGIのキャッシュを利用した改善後のトップページのPSIスコア
KUSANAGIのキャッシュを利用した改善後の投稿ページのPSIスコア

ほとんど改善は見られませんでした。誤差の範囲内のスコアの変動です。

ここで分かったことは、私のように最低限のプラグインしか利用していないシンプルな Snow Monkey サイトであれば、nginx の FastCGIキャッシュなどを利用しなくても、カスタマイザーのページ速度最適化だけで Webサーバの動的処理レイヤーの改善は事足りるということです。

これ、Snow Monkey すごくないですか!?

この先の最適化作業で邪魔になりそうなので、一度KUSANAGIのキャッシュはどちらもOFFにしました。

WEXAL

次に WEXAL(PST) を導入していきます。私はすでに KUSANAGI の Premium Edition にアップグレードしているので楽々。アップグレードの方法やPSTの導入手順は、Snow Monkey Advent Calender の趣旨から離れてしまいますし、長くなってしまうのでざっくりカットします。プライムさんが最近動画とかもアップしているみたいなので、覗いてみてください!

ちゃちゃっと導入して、管理画面にアクセスします。

WEXALの管理画面

ダッシュボードから PST を ON にして、画像最適化を行います。

WEXALのダッシュボード

これで、DocumentRoot 配下の全リソースの最適化が行われます。オリジナルのリソースは何も変わりません。最適化されたリソースが新しく作成され、それを読みにいくように変わります。

画像は、WebPと、クオリティは同じでも最適化ロジックの違う最適化済み画像を作成して、よりサイズの小さいものを読みにいくようになります。WebPのほうがサイズが大きいために採用されないこともあります。JSやCSSはミニファイをしたり、ベンダープレフィックスをつけてIEのときはこっちを読むようにする、ということをしたりもします。

測定前準備ということで、先程設定した Snow Monkey の「カスタマイザー > ページ速度最適化」の中で、PSTと競合しそうな項目をOFFにしました。

  • jQuery の 読み込みを最適化する
  • HTTP2 Server Push を使用する
  • CSS を head に出力する
  • リンクの先読み機能(prefetch)を使用する

WEXAL の AI におまかせモード

デフォルトの高速化戦略モードは「AI自動戦略モード」です。
ページごとにAIがどういった高速化が行えるのかを判別して、それに合わせてWebサーバがレスポンス内容を調整します。先程の最適化された画像を読み込むのはもちろん、ファーストビュー内でなさそうな画像や動画などのlazyload、遅延して読み込んでもよさそうなリソースの遅延読み込み、PageSpeed Insights に LCP の対象と判断されたリソースのプリロード、WordPressなら絵文字に関するリソースを読み込まない・・・などなど、いろいろやってくれます。
最近は機械学習も始めたみたいで、先が楽しみです。

ではでは、このモードで測定してみます。

PSTのAI自動戦略モードを利用した改善後のトップページのPSIスコア
PSTのAI自動戦略モードを利用した改善後の投稿ページのPSIスコア

おお、なかなかいい感じ!投稿ページのスコアもかなり持ち直しました。それでもまだまだ緑には到達しないですね・・・。もう少し調整をしてみましょう。

ちょっと手動で調整

高速化戦略モードを「AI自動戦略モード | リソースヒント」にすると、管理画面のリソースヒントページから、どのように高速化するかのヒントをAIに与えることができます。
リソースヒントページの「engagement delay の適用方針」タブで、リソースの遅延読み込みの方針を決められます。AIが高速化の判断を行ったページで利用されていたリソース一覧がここに並んでいます。

WEXALのリソースヒント

この「engagement delay」は、script タグの async / defer とは違います。サイト訪問者のサイトへのエンゲージメントやデバイスに応じて読み込み始めるタイミングを調整します。エンゲージメントが低い場合、デフォルトでは load イベントから更に待ち時間分読み込みを待って、リソースの読み込みをスタートします。スクロールなどのイベントも察知して、読み込み始めのタイミングを更に調整したりもします。
これを利用して、ファーストビューに関係のないリソースや、影響の少ないリソースなどをどんどん遅延させてみます。

私のサイトで「engagement delay の適用方針」を「有効」にしたリソースはこちら。

私のサイトで「engagement delay の適用方針」を「有効」にしたリソース
  • /wp-includes/css/dist/block-library/style.min.css
  • /wp-content/plugins/snow-monkey-blocks/dist/packages/slick/slick-theme.css
  • /wp-content/plugins/snow-monkey-blocks/dist/block/slider/style.css
  • /wp-content/plugins/snow-monkey-blocks/dist/block/spider-pickup-slider/style.css
  • /wp-content/plugins/snow-monkey-blocks/dist/block/spider-slider/style.css
  • /wp-content/themes/snow-monkey/vendor/inc2734/wp-share-buttons/src/assets/css/wp-share-buttons.css
  • /wp-content/themes/snow-monkey/vendor/inc2734/wp-like-me-box/src/assets/css/wp-like-me-box.min.css
  • /wp-content/themes/snow-monkey/vendor/inc2734/wp-oembed-blog-card/src/assets/css/app.css
  • /wp-content/themes/snow-monkey/vendor/inc2734/wp-pure-css-gallery/src/assets/css/wp-pure-css-gallery.min.css
  • /wp-content/themes/snow-monkey/vendor/inc2734/wp-awesome-widgets/src/assets/css/wp-awesome-widgets.min.css
  • /wp-content/themes/snow-monkey/assets/css/dependency/snow-monkey-blocks/style.min.css
  • /wp-content/plugins/snow-monkey-blocks/dist/packages/spider/dist/js/spider.js
  • /wp-content/plugins/snow-monkey-blocks/dist/block/spider-pickup-slider/script.js
  • /wp-content/plugins/snow-monkey-blocks/dist/block/spider-slider/script.js
  • /wp-content/plugins/snow-monkey-blocks/dist/block/list/script.js
  • /wp-content/plugins/snow-monkey-blocks/dist/block/categories-list/script.js
  • /wp-content/plugins/snow-monkey-blocks/dist/block/countdown/script.js
  • /wp-content/plugins/snow-monkey-blocks/dist/block/section-with-bgvideo/script.js
  • /wp-content/plugins/snow-monkey-editor/dist/js/app.js
  • /wp-content/themes/snow-monkey/assets/js/page-top.js
  • /wp-content/themes/snow-monkey/assets/js/fontawesome.js
  • /wp-content/themes/snow-monkey/vendor/inc2734/wp-oembed-blog-card/src/assets/js/app.js
  • /wp-content/themes/snow-monkey/vendor/inc2734/wp-share-buttons/src/assets/js/wp-share-buttons.js
  • /wp-content/themes/snow-monkey/assets/js/widgets.js
  • /wp-content/themes/snow-monkey/assets/js/sidebar-sticky-widget-area.js
  • /wp-content/themes/snow-monkey/assets/js/drop-nav.js
  • /wp-content/themes/snow-monkey/assets/js/global-nav.js

使う予定のないブロックに関連するものなども含めて、どんどん有効にしました。こんな感じで細かくリソースごとの設定が行えるのがとてもありがたいです!
サイトの作りによって有効にするかしないかが変わってくるので、参考程度にご覧ください。また、現時点でAIが有効と見なしていたリソースは記載していません(もはや自分用のメモでしかない)。不具合出てたら教えてください!

・・・と、実はここで、WEXALの不具合で高速化戦略モードが変更できず。。。(報告済み)
今回は裏ワザを使って、上記の手順と同じ結果が、パラメータを付与することで取得できるように準備しました。後述のスクショのサイトURLにパラメータがついているのはそのためです。気にしないでください・・・。

それでは、気を取り直して計測してみましょう。

PSTのAI自動戦略モード|リソースヒントを利用した改善後のトップページのPSIスコア
PSTのAI自動戦略モードを利用した改善後の投稿ページのPSIスコア

もういいでしょ!まんぞくー
サーバスペックが非推奨レベルなので、サーバ負荷が高めになっちゃいますが、それでもこれだけきちんと動いてくれています。

遅延できたリソースが多くて驚かれたかもしれませんが、単純にこのサイトで使用予定のないものが多かったためでもあります。スライダーとか使わないので。必要なものだけピックアップできる、このような構成は本当にありがたいんです!!!キタジマさんありがとうございます!!!(2回目)

高速化しやすい Snow Monkey

これまでの流れで伝えたかった、Snow Monkey が高速化しやすいワケはこんな感じです!

  • シンプルな構成のサイトなら、Webサーバやアプリケーション全体のキャッシュは不要!
  • リソースが細かく分かれているので、遅延読み込みや読み込み停止の指定がしやすい!

純粋に、テーマの作りが高速化に適しているのです!
今回、リソースの遅延読み込みや読み込み停止は WEXAL を利用しましたが、WordPressのフックを利用すれば読み込み停止は行なえますし、遅延読み込みだってテンプレートの出力内容を文字列置換とかすれば、async / defer くらいならできそうな気がします。

逆に、高速化しづらいサイトの特徴はこんな感じです。

  • JSでDOM操作しまくっているけど、サーバサイドレンダリングしていないサイト
  • CSSやJSが、それぞれひとつだけのファイルにまとめて書かれているサイト

WordPressではそんなに該当しなさそうですが、JSでDOM操作されまくってしまうと、その分レンダリングレイヤーのボトルネックになります。ソースコードを見てみるとコンテンツが何もない・・・というサイトをいくつも見てきました。この場合はオリジナルのリソースを改修するしかありません。

ひとつの大きなCSSファイルやJSファイルに全部の記述がまとめてあると、遅延読み込みできる箇所があっても、そこだけを遅延させることはできません。これも、遅延させたい部分だけを切り出して別ファイルにするなど、オリジナルのリソースを改修するしかありません。

いかがでしょうか?ぜひ皆さんも、Snow Monkey サイトをもっと高速化!お試しください!

Snow Monkey アドベントカレンダー2020