https://www.youtube.com/watch?v=VkTCL6Nqm6Y
1 comment | 2 points | by WazanovaNews 約9時間前 edited
OSCON 2014におけるInstagramのWebチーム責任者であるPete Huntの講演。PeteはInstagramに異動する前は、FacebookのPhoto/Video/Product Infraチームに在籍。
今回は、InstagramのwebサイトInstagram.comにおいて、シングルページアプリの課題である最初の読込みスピードを上げるために、どのような工夫をしたかについて紹介してくれてます。
- Instagram.comのJavaScriptファイルは、縮小化後で9.5MB & gzip圧縮後で2.5MB。そのサイズだと、一つのファイルにまとめてダウンロードするには向いてないし、リソースに限りのあるモバイルサイトでパースするのもパフォーマンス的に問題。
- そこで、17個のエントリーポイントを用意し、各ページに必要なJavaScriptだけをダウンロード。エントリーポイントは共有ライブラリ的な位置づけとし、別のエントリーポイントにユーザが遷移したときに、既にダウンロードしたJavaScriptは再度読込まないように工夫した。
- モジュール単位の仕組みとし、依存関係はCommonJSで管理。モジュールは各エントリーポイントごとに必要なコンポーネントを組み合わせる。例えば、React とPhotoModalは、profileエントリーポイントとFeedエントリーポイントの両方で必要になるので、まとめて共有のJavaScript bundleに入れて再利用できるようにする。HTTPリクエスト数とダウンロードバイト数を減らすベストなバランスをオブティマイザーが担ってくれる。
- 全てのエントリーポイントにクライアントサイドrouterを置いている。routerがまとめて全部をrequireするのではなく、必要なものだけを適宜処理できるよう、bundleを非同期に読込むかたちとした。
- CSSや画像ファイルは、
require(‘./bootstrap.css’);やmyImage.src = require(‘./myimage.png’);などのように適宜インライン化し、モジュールに組み込んだ。less / sass / CoffeeScript / TypeScriptも同様。- このモジュールシステムで、静的アセットは全て管理できるようになったので、ビルトシステム(Grunt)は不要になった。
- 複数のメンバでCSSを書いていると、詳細度 / Class名のコンフリクトで予想外のコードが反映されてしまうことがある。また、必要なくなった箇所を削除できるかどうかの判定も相当難しい。そこでInstagramチームのガイドラインは、
- 例えば、
.igUserProfileAvatarのように、誤って被ることのない明確なclass名をつけるようにして、積極的にネームスペースを確保。- 階層を排除。CSSルールごとに単一のクラス名のセレクタのみ。その名称でgrepするだけで、ルールが生きているかどうか判別できる。
- 上書きは極力避ける。
- module bundlerとしては、webpackがパフォーマンス的に最適だった。そこで得たノウハウはwebpack-howtoページにまとめた。その他の検討したツールは下記の理由で不採用。
- Browserify: JavaScriptを一つにまとめるためのソリューション。
- RequireJS: HTTPリクエスト or 一つのJavaScriptファイルの選択で、複数のエントリーポイントという仕組みには使えなかった。
- Grunt: テストにはものすごく役立ったが、依存関係の管理には向かない
- gulp.js: パフォーマンスとしてはGruntより優れているが、モジュール単位でなくファイル単位というコンセプト。
#facebook #instagram #シングルページアプリ #commonjs #react