久々にサービス作った際に、忘れていたり、触っていなかった事によって無駄に時間が掛かった最適化ポイントをまとめてみました。
HTML/CSS/JavaScriptの最小化や圧縮、サーバの設定などは元からできるものとして、最近変化した事や私が忘れていた事、気付いた事のまとめです。
事前に知ってると3日くらい実装時間を短縮できるかも知れない。
次回作る時のためのメモ。
faviconの作り方は変わっていない
faviconの種類は肥大化し続けている。自力での対応は面倒なので
Favicon Generatorに頼ると良い。
またfaviconの編集も割と面倒である。
画像編集ソフトを山ほどインストールしたけど、一番便利だったのは
Pinta。
私はいつもフリー素材で作ってるので、透過PNGをそのまま編集できて、レイヤをコピペで合成できる機能だけあれば十分なんだけど、
何年経っても
Pintaが一番簡単に思う。
faviconはインライン化する必要がない
画像をインライン化するとレスポンスが良くなりますが、
最近のブラウザはfaviconを遅延ロードしてくれるのでインライン化は不要です。
最近はfaviconの種類が増え過ぎて、インライン化すると端末依存の不要なものを読み込んでしまい、むしろ遅くなります。
4Gネットワークでは50~100ミリ秒のラウンドトリップ時間が発生する。
1パケットは14KBに制限されているので、1ファイルはなるべく14KB以内に収まるようにする。
またスクロールせずに見れるATFコンテンツを98KB未満にすれば3回のラウンドトリップでページを表示できる。
PageSpeed Insightsの指針に従って最適化しましょう。
<link rel="preload"> ができていた
linkタグにCSSのレンダリングをブロックしないための属性ができていた。
ファーストビュー部分をインライン化しておいて、残りをpreloadで読み込めば、高速化が簡単にできるようになった。
現時点では対応していないブラウザが多めなので、
loadCSSを併用する。
これも楽にはなったけど完璧ではないです。
CSSをpreloadでロードした後にdeferしたscriptを実行するためには、今のところライブラリが必要です。
loadCSSでは以下のように実装すると、#loadcssタグの前にCSSを読み込んだ後にスクリプトを実行してくれる。
<script id="loadcss">
loadCSS("path/to/mystylesheet.css", document.getElementById("loadcss"));
: // 何らかの処理
</script>
preloadよりは、後述するファーストビューのインライン化を先にやるべき。
ファーストビューのインライン化ツールができていた
ファーストビューのインライン化は
UnCSS,
Criticalの2つが有名みたいです。
説明は少し長くなるのでこちらを参考ください。
ファーストビューのインライン化は起動時間短縮にかなり効果があって、今回のサービスでも100msくらい早くなりました。
h2oでサーバの設定が終わってから気付いたので、これも今回は使っていない。
これを使えば面倒臭いインライン化回りを自動化できて開発が楽になる気がします。
今回はpreload回りのコードをビルドツールに組み込んでしまったのでセーフという事にしておいた。
他にも
Googleがいくつか新しい最適化ツールを推奨し始めた。
headタグに書ける事が増えた
Twitter Cardとか構造化マークアップとか出たらしい。
構造化マークアップでパンくずリストを作れるのは割と便利かも知れない。
でも今回は何も使ってない。
明らかに参考になって今後も使えそうなページだけ載せておくと以下。
Googlebotの機能を見るに、実はほとんど書かなくて良いのではないかという気がしている。
Macを使わなくてもiPhoneのデバッグできるようになったので、Linux使いの私は捗るようになった。
なおWindowsでは動かないらしい。
iOS12以降でBasic認証の処理が色々とよくわからなくなった
よくわからないけどまともに動かなくなってデバッグつらい。これはマジでつらい。
デモで見せたい時とか超困る。
適当なtokenをキーとしたページをでっちあげて短縮URLで送るくらいしか抜け道を思い付かないが…。
iOSでWebページを最大化表示できるようになった
Androidは以前からこの機能がありましたが、iOSでも対応しました。
ホーム画面に登録するとアプリっぽく動作してくれるようになります。
iOS/Androidの両方で最大化表示できるようにするには以下のように書きます。
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
iOSでWebアプリをホーム画面に追加するとリロードが効かなくなる
iOSでホーム画面にWebページを登録すると、独自の更新間隔でキャッシュをリロードするようになります。
HTTPサーバのキャッシュ情報が使い物にならなくなるので、検証中は content="no" にしないと検証が困難に。
<meta name="apple-mobile-web-app-capable" content="no">
日本語情報はまったく見つからなかったけど、
海外ではハマっている人が結構居た。
キャッシュを消すためには、端末のデータを直接弄って消すか、iOSのキャッシュを削除した上で content="no" にするしかないのかなあ。
運用時もキャッシュが効き過ぎて割と困る。
PWAを設定するとService Workerを見てくれてその更新モードが適用されるみたいなので、PWAの利用を前提に使ったほうが良さそう。
これはPWAに対応していない古めのiOSやSafariのバージョンをどうするかという話にも繋がってくる。
PWAができていた
iOS 11.3 / Safari 11.1からiPhone/iPadでも対応し始めたらしい。
色々な使い方があるけど、コンテンツキャッシュとアドレスバーを消してアプリっぽく利用できるようにするためだけに利用している。
最近のスマホだとPWAを使えば先に述べた指定をしなくてもアプリっぽくなる。
PWAのキャッシュ更新は手動で調整できて嬉しい。
PWAのおかげでかなり早く起動できるようになった。対応も簡単なので、これはどんなサイトでもやったほうが良い。
今回は使ってないけどGoogleフォントはPWAに対応しているし、結構色々なものがキャッシュできる。
適当な実感値だとスマホは200msくらい改善できる気がする。
他にもPWAは設定しているだけで簡易的なF5アタックブロッカーになるので、割と良い仕組みだと思った。
Chrome 67からデスクトップでもPWAが使えるようになった。
インストールするとデスクトップにアイコンまで作ってくれる。Electronより楽かも?
スマホほどの速度改善は期待できないし、まだ試験的機能でしかないけど、将来には期待が持てる。
いずれ解決される気がするけど気になる動作が色々。
DevToolsのネットワークのロード時間がService Workerのせいでおかしくなる。
遅くなっているように見えても実際には早くなってるので注意が必要。
他にも普段からキャッシュが効きまくってデバッグがしにくくなる問題もある。
毎回キャッシュを消して確認してる。
AMPができていた
CSS/HTML/JavaScriptに様々な制限を加えてキャッシュする事で高速な表示を可能にする技術。
こちらは対応が面倒臭い。
制限がキツ過ぎて、正直いくら早くなると言ってもJavaScriptバリバリのサイトへの適用は困難を極める。
そもそもファーストビューのインライン化では !important を使ったほうが楽だけど、使ってしまうとAMP化できなくなる。これはキツイ。
今回作ったサイトでは使えそうもないので使ってない。
様々な最適化ツールの進化によって、今回のサービスで一番のボトルネックは外部サービスの遅さと
jQueryのロードの遅さになりました。
ネットワークとDBの細かなボトルネックをきちんと処理して負荷が大きく掛かってない状態なら、確かに
jQueryはキャッシュが効いていなければ100ms近く掛かってしまうので、現状一番重いです。
jQueryより前に色々処理するのが最初の対策ですが、残りの部分はやはり
jQueryを使う事になるのでどうしても遅くなる。
うまくネイティブ化して50ms以下にしたい気持ちはあるけど未着手です。
先に述べたようにロード時間のほうが問題なので、ほとんど使ってない
jQueryでも良いかなと思ってるんだけど、今も採用の候補にはある。仮想DOMを自前で処理してると別にフレームワーク自体の機能はそんなに関係ないんだよなあ。
一番気になるのはPWAの進化に対して
Vue Nativeなどのネイティブ化技術がどれくらい強さを維持できるかどうか。
ところで
Bootstrap v5では
jQueryへの依存がなくなるらしい。
私はアニメーションと
Bootstrapの依存ライブラリのためにしか使ってないので、そこを提供してくれれば移行は困りません。
ただ意外とそこが面倒。
前者は
Velocity.jsが出てきたけど別にサイズが軽い訳ではないし、ライブラリのjQuery離れもどれくらいの速度で進むかな。
Native JavaScript for Bootstrapやv5が安定してから採用するほうが
Vueを使うより楽だし軽いと思うので待ちですかね。
v5が出るまでは基盤ライブラリに何を使うかは迷い所かも。
煩雑なHTML/CSS/JavaScritptを何も設定せず最小化してくれる
Parcelという素敵なツールが出ていた。
便利なのは理解したけど、最小化やキャッシュ周りで最も注意が必要なのはService Workerで、ここをミスするとバグに気付けなくなるので、ここを自動化するためにもビルドツールは完全に自作した。
ただこれは
workbox-webpack-pluginを知らなかったからであり、このプラグインは上記で述べた事を良い感じにやってくれるので、今だったらこちらを使うかも。
workbox-webpack-pluginがかなり便利なので、次回作る時は
Webpackでも良いかなとも思っている。
Parcelはそのへんが安定してきたら候補に上がる。
レイアウトのリフロー対策はよくわからない
とりあえず完成したサイトは
PageSpeed Insightsでパソコン版は99点だった。
その後モバイル最適化のためにあえて点数を少し落としたけど、1つ気になったのは
過大な DOM サイズの回避というもの。
リッチサイトじゃどうしようもないような。
もしかしてレイアウトのリフローを避けるためには、iframeを使うべきなのだろうか。
ChromeのDevToolsから色々なSEOのチェックができるようになった
DevTools -> Auditから確認してもらえる。
PageSpeed InsightsのようなレスポンスのチェックだけでなくSEO周りもチェックできるようになって嬉しい。
jQueryでWarningが出るという。
その問題を無視すれば、Performanceを以外を100点にするのは今のところ簡単。
WebPが良い感じになってきた
WebPは以前からたいていのブラウザでHTML経由の表示はできていたと思うのですが、2018/01/29でリリースされたFirefox65の正式採用によって、ついに実用的な利用が視野に入ってきたように思います。
確認テストもしてみた感じでは、画像の多いサイトでは通信量を1/10以下にできる可能性もありそうですね。
CGIはSSHが使えないとつらい
もしくはリバースプロキシがいかに天国であるか。
もしくはレンタルサーバとVPSの選び方。
結構長い話になるので
詳しくはこちらをどうぞ。
さらに
EC2やGCP、S3なども含めて運用基盤全般も軽く調査し直したけど、
今回は検討の結果、
Vultrを利用した。
価格のバランスが良くてネットワーク速度が早かったので選んでみたけど、適宜増設していくつもりです。
マイクロWebフレームワークが増えて選択肢が広がった
昔は
Ruby on Railsや
Djangoなどの巨大なフレームワークしかなかったけど、
マイクロWebフレームワークの種類が凄く増えた。
Ruby/Pythonでも早いものが増えたので、気軽に実装できるようになった。
静的ファイルを作り過ぎてinodeが枯渇した
静的ファイルのほうが早いものはひたすら静的化していたのですが、容量の小さなVPSで小さなファイルをたくさん作ると、容量より先にinodeが枯渇する事を知りました。
ちなみにext4でinodeが枯渇するとファイルシステムを作り直さないといけない。これはあかん。
ファイルに書き出しまくるとこういう問題もあるんだなあ。
レンタルサーバはVPSよりクリティカルな問題にならないかなこれ。
仕方がないのでKVS実装にサクっと書き直した。
ほぼファイルシステムとしてしか使ってないけど、
ファイルシステムより効率は良いのでファイルサイズが1/3になったし、リクエスト数も減らせて高速化した。
レンタルサーバにこだわらなければハマる事はなかった問題だったけど、勉強になった。
いつも超迷う /etc/init.d/service でサービス登録するテンプレートができていて、凄く簡単にサービス登録できた。
決済周りが一番時間が掛かった
コア実装は満足のいくレベルの1万行〜くらいを3週間でパパっと書けたので、速攻でリリースしようと思ったものの、実際にはかなり時間が掛かっている。
調査に1週間、少額決済の実装に1週間、申請に5週間、利用可能までに2週間掛かった。
調査の時間が長いのは久々にWebサービス作ったせい。
決済の実装が思ったより闇が深くて検証に時間が掛かって、審査にも凄く時間が掛かった。
やっぱ申請って疲れるなあ。
最初からすべてOKをもらってから運用開始しようとするのは凄い時間掛かるのでやめたほうが良い。
申請中にまったり機能改善をするのが良さそう。
今回は割と学びの多い開発になった。