パフォーマンスチューニング、ちょっとその前に
pastak.iconPasta-K @ Kyoto.js 17
こんにちは
https://gyazo.com/422954eb4591d345c7d507cae73748ae
誰
京都大学工学部情報学科7回生
株式会社はてな アルバイト
TypeScript
Nota Inc Gyazo開発チーム アルバイト
JavaScript / React / Ruby on Rails / Browser Extension
ビール仕入れ業 / ビールサーバー運用エンジニア
趣味: ビール🍻
今日のトークテーマ
主にウェブページの表示に関するパフォーマンスの話
ウェブページのパフォーマンス
素朴なHTML
CSS無し
テーブルレイアウト
ウェブアプリケーションを作っていると、素朴だったページも雪だるま式に色んなものがくっついてくる
画像
JS/CSS
あらゆるモジュール
jQuery/React/axios/lodash ...etc
ルーティング機構
最初は早かったはず…
徐々に開発していくにつれてパフォーマンスが低下していく
そもそも、実はそんなに頑張ってなくて遅かったよねということもある
100点は無理でも、60点くらいと思いつつも、結果的には30点くらいになっている
高速化をする前にまずは60点になろう!!!!!
というわけで
60点を目指すためのやっていきリストです
多分やってない場合はシュッとやるとなんか効果があったりすると思います
一般的なテクニックを適応しようという話なので、感動的なテクニックや面白ハックとかは出てきません
ウェブページの表示について
https://gyazo.com/e913e880f6f95ac82e070003ee101b90
lightroomとか使うとこういう文言が出てきます
FMPまでを高速化出来るとひとまず良さそうですね
やっていきます
前提のご共有
まずは計測するのが良いと思います
lighthouseとかでサクッと見ましょう
First Contentful Paintなどが遅いと効果的だと思います
どういう問題があるかは計測結果を参照してください
スローガンご紹介
復唱お願いします
読み込ませない
実行させない
読み込ませない
画像を読み込ませない
JS/CSSを読み込ませない
そもそもHTMLを減らす
必要なものだけ読み込む
ファーストビューに出るものだけ読み込んでレンダリングさせる
必要な画像だけ表示する
<img>のloading属性を使うとChromeではLazyLoadingしてくれる
<img loading="lazy" src="...">
IntersectionObserverなどを使って画面内に登場する要素だけを読み込むようにコントロールするという手もある
SNSボタン
YouTube埋め込みなど
もっと見るボタン
読み込む要素を減らす
素朴にやってるとCSSで見た目上は隠しているけど、一方画像は読み込んでいるとかもある…
この辺はUXとのバランスを取っていく必要がある
実行させない
現代的なウェブページやウェブアプリケーションはJavaScriptの実行が必須
そもそもReact/Angular/Vueなど使っていると実行しないことには始まらない
一方でJavaScriptを読み込んで、実行するコストは高い
JavaScriptの読み込みをへらす
図です
https://gyazo.com/59010bf5d1d15f644976486de7f3a4e7
JavaScriptを読み込むサイズが大きいとそれだけで大きなコストになる
画像サイズ削るのとJSのサイズ削るのとでコストがこれくらい変わるの言われると納得感あるけど、直感と少し違うようにも思う
前述のSNSボタンの読み込み遅延も結果的にJSを減らすことに繋がる
JSのサイズ削っていき
不要なモジュール無くす
webpack-bundle-analyzer
$ webpack --profile --json > stats.json
$ npx webpack-bundle-analyzer bundle/output/path/stats.json
https://cloud.githubusercontent.com/assets/302213/20628702/93f72404-b338-11e6-92d4-9a365550a701.gif
不要なモジュールの例: lodashやめる
イマドキ大体ESに標準で入ってます
あと手で書けるのも多い
一旦 lodash-es に置換したら良いと思います
tree shakingされて使わないやつは消えます
lodash-esに移す様子
before
https://gyazo.com/18105c8fc5c37411e014e048549676f4
after
https://gyazo.com/f5713c70068dc717587b202960ec295a
不要なモジュールの例: Moment.jsのlocaleを選択的に利用する
何もしないとMoment.jsは全てのlocaleを含んでいる
75% (160 minified KBs)¹ of Moment.js’ size are files used for localization. They are always included when you build your app with webpack.
code: webpack.config.js
const MomentLocalesPlugin = require('moment-locales-webpack-plugin');
module.exports = {
plugins: [
// To strip all locales except “en”
new MomentLocalesPlugin(),
// Or: To strip all locales except “en”, “es-us” and “ru”
// (“en” is built into Moment and can’t be removed)
new MomentLocalesPlugin({
}),
],
};
webpackのCode Splittingを活用する
dynamic importと組み合わせてJSを1つのファイルにまとめずにchunkに分割してくれる
エントリポイントになるJavaScriptファイルは小さくなり、パースや実行の時間を短く出来る
[ポエム]Chunkの分割を上手く戦略的にやったり、こちらもpreloadを設定しないと、メインの実行パス内でdynamic importをすることになってしまい結果的にJSの実行中にファイルの取得とパース等が起きてしまい終端のJavaScriptを実行するまでの時間が結果的に長くなり、レンダリングまでの時間が延びるということもある
なんかJSの実行に掛かる時間が長いなと思って調査したら、これだったことがある
ルーターみたいなやつがいると相性悪くないですか?
選択的にやっていく?
そもそもentrypointを分けたら良いやんみたいな気持ちになってしまう
CPUの専有を避ける
重たい処理や後回しに出来る処理はrequestIdleCallbackで先送りにする
メインコンテンツのレンダリングに関わるもの以外を一旦あとにする
ChromeとFirefoxで使えます
ここから先にやること
JavaScriptをasyncで読み込んで、DOMContentLoadedを待つ間に諸々の初期化をやっておく
必要なものはpreloadやprefetchを使って先に読んでおく
そもそもAPIとかHTMLの吐き出しが遅いとかない?
JavaScriptの実行自体のパフォーマンスを検証する
まとめ
ウェブページが遅いな?と感じた時にやってみると良さそうなことを紹介しました
現代的なウェブアプリケーションをやっていくときの基本という感じもするけど、1つ1つを気にして削ることってあんまりないと思っていて、油断すると増えていたりするので、定期的に棚卸しすると良いのでは?