#2」が開催されました。Web技術の発展とともに多様化し始めているフロントエンド領域。さまざまなノウハウを持つエンジニアたちが、自身の知見を語ります。プレゼンテーション「日経電子版を速くするためにやっていること」では、日本経済新聞社の宍戸俊哉氏が登場。高速化のためにフロントエンドですべきこと宍戸俊哉氏(以下、宍戸):フロントエンドの話をしていきます。「高速化のためにフロントエンドですべきこと」を4つあげさせてもらいました。「あとでいいことはあとでやる」「必要なことは先にやる」「使い回せるものは使いまわす」「クライアントにとって最適なものを配信する」。だいたいこの辺の原則に則って今のフロントエンドの高速化のプラクティスってあるのかなと思っています。「あとでいいことはあとでやる」というところで、1つはクリティカルレンダリングパスですね。これを減らしていくというところですね。クリティカルレンダリングパスはもう説明いらないかなと思うんですけど、CSS、JavaScriptのファイルが読み込みにいくときにレンダーブロッキングを発生させているので、なるべく非同期化したり、インラインしたりしようというところですね。JavaScriptは基本的に全部非同期で読み込むようにしています。serviceというライブラリを使っています。このライブラリはブラウザ間によってはまだ実装されていないAPIなどの差分を吸収してくれるサービスです。こいつを使っているのでほかのコードというのは全部polyfillが存在する前提で書いているんですね。polyfillをロードしてからほかのスクリプトを実行するような書き方をしています。DOMContentLoadedは一切使わずに、ほとんどのものがpolyfillのonloadイベントをキャプチャして初期化するようになっています。CSSという概念があると思うんですけど、一番最初に画面に映るスタイル以外は全部あとから読み込もうというようなアプローチですね。これやるとCSSのクリティカルレンダリングパスをなくすことができるんですけど、r.nikkei.comでは、いろいろ試行錯誤はしたんですけど、まだ入っていないです。なんでかというと、会員種別によって画面が違うだとか、レスポンシブ対応が必要だとか、そういった要素が入ってきてまだうまく行ってないですね。CSSをインラインに埋め込むというようなライブラリがあったりします。これでも、いろいろトライした結果、「最終的にはマニュアルで全部メンテしていく勇気と覚悟が必要そう」という結論に今はいたっています。必要なことは先にやる次はセクションの遅延ロードですね。画像は遅延ロードするのはみんなやっているかなと思うんですけど、r.nikkei.comだとセクションごとに遅延ロードを行ったりしています。「コンテンツのサイズ」というのはDOMノードの大きさとか深さですね。これはパフォーマンスにすごい大きく影響してきて、モバイルだとさらに顕著だったりします。今のPCの日経電子版ってトップページだけだと60記事以上リンクがあって、ビジネスサイド的には全部出してほしいというような要望があったので対応しました。最上部除いてセクションごと全部遅延読み込みさせるような仕組みで、初回レンダリングのコストを下げる工夫をしています。Loadingをやるために「スケルトンスクリーン」というのを実装していました。Observerを2回に分けて非同期で読み込むような処理ですね。ObserverでスケルトンだけのセクションをDOMに追加します。そのあとスクロールが進んできたら実体で入れ替える。Observerの長めの1回目の読み込みでこのスケルトンスクリーンに出しているDOMサイズを減らす処理をしています。これによってリフローもあんまり起きないかなという感じですね。画面の表示に必要になるリソースというのはなるべく速く読み込むようにする必要があって、これもFastlyのHTTP/2の機能を有効化して実現しています。Curlでちょっと見づらいんですけど、Curlでr.nikkei.comのトップページを叩いてみると、中は死ぬほどLinkヘッダが入っているんですね。Cacheの中に入れておく。すると、index.htmlを読み込んだあとに、例えばCSS取りに行ったりJS取りに行ったりでネットワークリクエストを発生させずに返すことができる仕組みになっています。日経電子版だと、朝夕刊といってその日の紙の新聞とまったく同じ構成の記事を表示するページがあります。ほとんどユースケースとしては、毎日紙の新聞を読む人が1面からなんとか面までずっとガーって読んでいくのと同じように、各面をバッと舐めるように閲覧するユーザーが多いんですね。Hintsでキャッシュしてしまおうという処理ですね。これはprefetchというものを使っています。prerenderとdns-prefetchというのも使っていて。prerenderは検索への導線ですね。マウスカーソルがアイコンに近づいたらリンクタグを動的に挿入します。あとは広告のサードパーティドメインに対してdns-prefetchをするなどして先読みを行っています。Workerを使った事前キャッシュですね。Workerの中でAPIから記事の一覧を取りに行って、その返ってきた記事の一覧から実際に記事のオブジェクトを取り出すというような処理ですね。APIの中に入れてあげる感じですね。だいたいこれを使うと記事のページというのは20〜30msぐらいで返せるようになっています。あとはオフラインで使えるようになるなどいろいろな恩恵があります。Workerのレスポンスからだと記事のページのレスポンスは取れるんですけど、必要になるJSとかCSSとかそういうサブリソースが取れないんですね。WorkerのaddAllを使ってキャッシュすることで実現しています。キャッシュ同期の問題というのがありまして、ログインしたとき、あとは非ログインのとき、古いキャッシュがどうしても残ってしまうというのがあります。有料会員のはずなのに「この記事は有料会員限定です」という画面が表示されてしまいました。Worker内でキャプチャして対応しています。そのログイン・ログアウトのURLをキャプチャして該当のURLが来たらキャッシュ削除する処理ですね。1つはpostMessageですね。Workerから返されたレスポンスに含まれるユーザーの会員属性、それとCookie内に保持している最新の会員属性。Workerにメッセージを投げてキャッシュ削除するという形ですね。古いキャッシュの削除どうやってやっているかというと、キャッシュしたURLとタイムスタンプをIndexedDBに入れています。Storage内のリソースを同期させることで実現しています。だいたいこんな感じですね。Workerは新しいキャッシュ要求を行う前にIndexedDBを参照して、そして古いキャッシュが残っていればそれを削除するといった処理ですね。「使いまわせるものは使いまわす」は一般的な話なんですけど、静的ファイルにはハッシュ値をつけて長時間キャッシュするようにしています。リロードの対策としてimmutableをつけてあげると、リロード時もキャッシュの再読み込みがなくてよいなという感じですね。サイト高速化の基本はUX改善デザインシステムですね。UI」というコンポーネントベースのスタイルガイドを作成していて、それをr.nikkei.comでは使うようにしています。いうメリットがあるかというと、マークアップの開発コスト削減やスタイル定義が重複しないように開発ができます。UIに一貫性が出ることと、アクセシビリティ、このあたりを担保できます。私は鼻から......。あ、これ言いたかっただけです(笑)。ToolsのNetworkパネルのInitiator、あとはsizeの部分から判断するしかないかなと思っています。Workerを無効化する。Webページ速度改善ガイド』、これを読むといいかなと思っています。plus)「最適なリソースを配信する」というところでpictureタグですね。pictureタグを使ってクライアントの画面幅に合わせて最適な大きさの画像を設定しています。これはHandlebarsのヘルパーを使って実装しています。これつい先週のやつなんですけど、画像配信を少し見直したんですね。今までjpeg画像のクオリティはけっこう高めに設定してたんですけど、見た目に大きな変更のない範囲で、見た目に大きな劣化のない範囲で変更して、だいたいコンテンツのサイズが半分ぐらい改善することができました。Budgetを定義しておくと、定期的にBudgetオーバーしてるから改善しなきゃねというきっかけになるので便利です。Timeなのか、こういったものが取得可能になります。Workerで大きめなリソースをガッとキャッシュすることがあるんですけど、そういうのはWi-Fi接続時のみに限定したりしています。最後まとめになります。高速化は一番根本的なUX改善になるのかなと思っています。Lighthouseを使ったりwebpagetestを使って分析をしていきましょう。SpeedCurveなどを使って継続的にモニタリングできる仕組みを作ると、一気にパフォーマンス改善というのはやりやすくなります。フロンドエンドだけじゃなくてCDNやサーバサイドのパフォーマンスというのも重要になっています。あとはキャッシュの効率化、クリティカルレンダリングパスの削減、そういう手がつけられるわかりやすいところから始めるといいのかなと思ってます。さっきのこの画像と同じように、パフォーマンスの改善というのは定期的にやっていくとよいです。そのときにBudgetを定義しておくとやりやすいです。速くすることを考えるよりも、遅くなる要素を減らしていくことが一番大事かなと思っています。ありがとうございました。Frontendに関する記事をまとめています。Frontendに関する新着記事が公開された際に、通知を受け取ることができます。