Code

2016年12月29日木曜日

Website Performance checklist

 Smashing Magazine から:
 Front-End Performance Checklist 2017

 いくつか Quick Win アイテムがリストされています。その中に website を 3 秒以内ロードするとか、会社のパフォーマンスチェックチームも実施していますが、Critical Path とかは特に考えてないようです。なぜなら Adobe の AEM を使っているので、古いサイトの新しいコンポーネントベースのページが両方存在していますため。予算がないので、この2、3年は変わらないでしょうと。
 しかし、その中に、古いサイトが残していても、実施できる項目も結構あります。例えば、画像の最適化とか、FOUT / FOIT など Font 関係の Fix とか。まぁ、HTML, CSS など古いサイトでも、新しいサイト共通の部分は結構あるので、それらを精査して、一つ一つやれば、だんだんサイトが速くなります。
 JavaScript に関しては、モジュール化が絶対必要です。Tree Shaking や Code Splitting などを使って、使わないコードを最終 JS に含まないことも可能なので、ぜひチャレンジしていきたいです。例えば、Modernizr にはいろんなテストがあって、実際はほんの1、2個の Class が使われています。その他のものが必要ないので、Front End に Ship することももったいないです。
 これからも HTTP2 を考えないといけないなと。

 それでは、Happy new year!

2016年12月10日土曜日

React.js stateful component 独自で更新可能

 最近、React.js の Component を作るとき、属性を親から、子や 孫 Component まで渡すにはちょっと面倒だなと思いました。Component Tree が大変深いからです。。。
 それで色々調べて、考えました。まず解決方法として、React.js には ChildContext という概念があります。まず親でどういうデータを Context に設定するかを指定して、孫の Component などは ContextType を定義すれば、this.context でそのインスタンスがアクセスできます。しかも shouldComponentUpdate に第三の引数が nextContext となっています。ただし、もし孫の Component と親の間に、shouldComponentUpdate が false を返す親がいると、孫が更新されません。。。これは最大の問題です。
 今アプリの作りでは、childContext はちょっと使いにくいです。。。

 次となる方法としては Redux を使って、子や孫 Component に store と直接連携するようにして、もし何か state 変更が発生すれば、store からの Event がトリガーされます。これはとっても便利ですね。具体的には store からのデータを孫 Componet の state に保存して、ajax call や、どこかの View でイベントが発生したら、Redux store が自分の state を Reducer で更新して、イベントを登録している Component には送ります。その Component のイベントハンドラーで setState() を使うと、その Component のみ更新されます。とても便利です。

 それで、もう一回 React.js Component の仕組みを考えてみると、完全に独立で自分を動けます。他の Component や、アプリ他の部分と関係ありません。別に親は普通の HTML Div でも、React Component でも、Angular Directive でも。

 これはアプリが一定程度に複雑になった話しです。通常であれば、属性で関数とかを子や孫に渡すべきです。

 それでは。

Akamai Bad Request (400) Restful API Delete method

 TL; DR: If you don't have time to find the root cause, just change Delete method to Post.

 In the past several weeks, we were experiencing an issue with Akamai: in a special sequence like Get + Delete + Get, or Post + Delete + Post, the request after Delete returned a Bad Request with reference no (xxxx.xxx.0) from Akamai edge server. But it never happened in our own environment, even the prod evn behind Akamai.

 We had some meetings with Akamai support engineers. They suspected that there may be some function keeping the HTTP connection with their edge server. At first, they thought our endless scrolling function caused the issue. But in fact we just load more data at the first time, then render only the first part of the data in the screen. When user scroll, we load other parts.

 After they checked their log, they found browser is using the same TCP connection for our Delete request. Which happens in the following case:
   Get /favourites  => setting up a connect with content-length some number
   Delete /favourites/{id} => using the same connection, with content-length xxx
   Get /favourites => bad request (400) from Akamai

In this case, Akamai edge server is sending Keep-Alive header to browser, so browser may use the same TCP connection to send the Delete request => Akamai edge server counts Delete request content-length as something not correct => edge server is waiting for more data from the next request => so next Get doesn't count as a separate request, and because it doesn't match what edge server expects, edge just returns 400 bad request to browser.
(It happens as if something like nullPost, nullGet when content-length is not correct - by support engineers).

 Their explanation sounds reasonable, but I used Fiddler and Wire Shark to check the content-length for all the requests,  couldn't find any incorrect data. All numbers seemed to be correct.

 We didn't have enough time to look into this issue further, and thinking of the request after POST never fails, I changed our Restful API Delete method to Post. This fixed everything.

 I am still not sure where the problem is, but at least changing Delete to Post makes everything good...

 Hope in the future, I can get some chance to make this clear. :)