元記事
https://coincidence.netlify.app/post/blog-display-speed
(ブログからの転載になります。)
表示が遅い!!
このブログ、現状でもかなり表示が遅いのですが、本記事での取り組みをやる前はさらに遅かったです。
参考までにLighthouseのスコアをお示ししますと、Performanceスコアが32〜36点ほどでした。
この状態から以下の対応を行なったことで、50点以上を安定して取れるようになりました。正直このブログにとっては意味のない対応もありましたが、勉強の意味で残しておこうと思います。
各施策の最初には星印で効果の度合いを示しました。黒星(ぬりつぶし)が多い方が、効果があったものになります。ただしこれは、私のSPAブログ環境ではこうだった、という話ですので、設計が異なれば有効な対策も異なるということはご注意くださいませ。(大丈夫だと思いますけど)
施策1:APIへの問合せ回数減
効果 ★★★☆☆
これは、トップページ(/page/1)の表示時間短縮には直接影響しない部分ですが、画面遷移時のオーバーヘッドを減らす意味で非常に役立ちました。
SPAの基本的な振る舞いとして、「情報の更新が必要であればその都度サーバーサイドに問合せ、結果を取得して表示更新する」という像があると思うのですが、WebページというよりWebアプリエンジニアの私はこの考えに縛られすぎていたようです。ページの表示、タグ一覧の表示、タグに紐づく記事一覧の表示…といった振る舞いをSPAブログにさせるために、毎回Contentfulに問い合わせをしていたのです。情報の更新はされていないにもかかわらず。
これはあまりに無駄が大きいので、ビルド実行前にContentful APIから情報を取得してjsonとして保存するスクリプトを書きました。記事数が増えてきたらまた対応を考えなければならないかもしれませんが、とりあえずは表示速度改善の意味で満足できる結果になりました。
施策2:コードチャンクの整理(highlight.js)
効果 ★★★★☆
スコア向上の意味ではこれの効果が大きかったです。
Vue CLIで作成したプロジェクトは、yarn run build --report
すると/dist/report.html
を生成してくれます。webpackでバンドルしたコードチャンクのうちなにが重いか?を可視化してくれる素晴らしいツールです。(単体ではwebpack-bandle-analyzerとして配布されています。有名だから今更かも。)
見ると、highlight.jsが大量のチャンクを吐き出していたので、何事かと思い調べたら、どうやら単にrequire
するだけでは不要な言語パックまで引き連れてきてしまうそうです。面倒でもちゃんとregisterLanguage
した方がいいみたいね。
// このやり方だと重くなります
import hljs from "highlight.js";
// こうしたらマシです(ちなみにhtmlはデフォルトでハイライトしてくれるっぽい)
import hljs from "highlight.js/libs/highlight";
import javascirpt from "highlight.js/lib/languages/javascript";
import css from "highlight.js/lib/languages/css";
hljs.registerLanguage("javascript", javascript);
hljs.registerLanguage("css", css);
ちなみに、最新バージョンだとregisterLanguage
がまともに動いてくれないバグがあるようなので、大人しくバージョンを下げて使いましょう。package.jsonを以下のとおり更新して、yarn
もしくはnpm i
です。
{
"dependencies": {
"highlight.js": "~9.18.1",
...
}
}
施策3:トップページのプレレンダリング(prerender-spa-plugin)
効果 ★☆☆☆☆
SPA高速化の手段の一つとして代表的なのがプレレンダリングですが、私の場合はそもそもHTMLの構造が複雑なために速度低下を招いていたわけではなさそうなので、これはあまり効果がありませんでした。また、ブログという性質上ルーティングが動的に変わるので、とりあえずよく参照されるトップページだけこの対応を埋め込みましたが、全てのブログページをプレレンダリングするのはやや設定が面倒そうな印象でした。
(ちょっと頑張ればやれなくもなさそうですが、記事数が増えるに従ってビルド時間がとんでもないことになりそうな気がしています。)
ページ数が限定されているSPAなら、やってみるのは大いにアリなのではないでしょうか。
施策4:ルーティングコンポーネントの非同期読み込み
効果 ★★★☆☆
これもなかなか良い感じに速度を改善してくれました。
メインの領域はVue Routerで切り替えているのですが、どのルートにアクセスしても、直近で必要のないJSを読み込んでしまっていたようなので、とりあえずはそのルートに必要なJSだけ呼び出してもらうように設定しました。Vue Router公式ドキュメントが参考になりましたが、要するにrouterの処理を書いているファイル内のコンポーネントのimport文を、なにも考えずに書き換えれば良いです。
// before..最初に全部読み込み
import HogeComponent from "@/components/HogeComponent.vue";
// after ..遷移時に必要に応じて読み込み
const HogeComponent = () => import("@/components/HogeComponent.vue");
Nuxt.jsとかGridsome、VuePressに移行したい
施策3でプレレンダリングを試してみたとはいえ、結局のところは静的サイトジェネレータに対応した上記のライブラリを使った方がよいのでは?感が拭えない結果となりました。Lighthouseのスコアも50止まりですしね。大人しく、JAMStackな設計のベストプラクティスに従ったほうがよさそうだ、というなんともしょっぱい結論となり恐縮です。
Nuxtとか使う時はまた記事書きます。ではでは。