最近、なかなか時間が取れなくて、困ってます。プロジェクトも色々大変な事になって。。。
唯一いいことは Webpack 2 にアップグレードする事になりました。まぁ、やってる方はとても若いので、いつできるかはまだわからない。
Webpack2を使うと、自動的に code splitting をやってくれたり、css ファイルも<head> に入れてくれたりします。まぁ、いろんな loader を使う必要がありますが。
その中の HtmlWebpackPlugin はかなり使いやすいです。なぜなら、HTML を書かないで、webpack は自動的に作成して、bundle した js ファイルや css ファイルを入れてくれるからです。
それに、loader も使ってくれるため、handlebars などのテンプレートも簡単に変換してくれます。
もしもう少し自分で作成された HTML をコントロールしたい場合、options 中の template を js ファイルにせってして、js から HTML code を作成する関数を export して置けば、その関数が呼ばれるので、色々便利です。
さらに、 もし React.js を使ってる場合、react-to-html-webpack-plugin も使えるので、パワフルなツールになります。
ほかに、Webpack 2 も dev server がついています。dev server を使うと、必要なリソースが動的に作成して、hot reload 機能も使えるようになります。これは便利の一言。
さらに、Express を使っている場合、Webpack もサーバー側のファイルを一つファイルにまとめることができます。これは Server Side Rendering を使うとき、Client サイドのコードをそのままサーバー側に実行することができます。
また環境ができたら、後日詳細をメモしておきます。
Code
2017年4月7日金曜日
2017年3月11日土曜日
a11y - アクセシビリティ
最近引っ越しのため、あまりパソコン使ってませんでした。iPhone とiPad は確かに便利です。
昨日、アップルからのアクセシビリティレクチャーを参加しました。前では、あまり知らない機能など、なぜアクセシビリティを重視するかを勉強しました。
例えば、アクセシビリティを実装することで、どんなユーザでも使いやすくなります。色のコントラストは目の不自由な方だけではなく、通常のユーザも多大な影響があります。
そして、幾つか認識間違いがちなところを書こうと思いました。
まず、アクセシビリティは Screen Reader のことだけではないし、aria 属性を使うことだけではありません。キーボードのみでウェブサイトを操作できることや、色のコントラスト、文字の大きさなどもその範囲内です。
ただ、一番難しいものはやはり Screen Reader の対応です。基本的に、NVDA や Jaws、アップルの VoiceOver に対して、各ブラウーザーはインターフェースを提供していますが、実装により、いろいろ違いがあります。そこで、HTML タグで解決できないものを aria 属性を使うことです。
HTML は基本中の基本です。まず、一ページには各メインコンテンツにジャンプするリンクを入れたほうがいいです。Tab キーを押すと、隠しているリンクを画面 上に表示して、ページ中のコンテンツにジャンプします。
次、header, h1 - h6, nav, fieldset, label, form の HTML コードはできるだけ正しく書かないといけないです。screen reader を使うユーザーは主にショートカットキーを使うので、Jaws の場合、Insert + H ですべての h1 - h6 のタグをリストすることができます。同じように、一つのキーですべてのリンクをリストして、一つ一つ見て、好きなところに行くこともできます。だから、リンクはできるだけ意味を持った文言を使わないといけません。"Learn more" とか全然わからないものを使わないでおこう。
そのあと、もし HTML のタグが解決できないことを Aria 属性と JavaScript を使うことです。例えば、pop up dlg の tab order や、aria-live を使って、ユーザーに画面に何か起こったかを知らせるとか。いろいろあります。
最後に、特殊のデバイス対応する場合、特殊のことをしないといけない。例えば、auto complete など複雑な Input を機能を説明するために、aria-label などを使うとか。
それでは、後日また。
昨日、アップルからのアクセシビリティレクチャーを参加しました。前では、あまり知らない機能など、なぜアクセシビリティを重視するかを勉強しました。
例えば、アクセシビリティを実装することで、どんなユーザでも使いやすくなります。色のコントラストは目の不自由な方だけではなく、通常のユーザも多大な影響があります。
そして、幾つか認識間違いがちなところを書こうと思いました。
まず、アクセシビリティは Screen Reader のことだけではないし、aria 属性を使うことだけではありません。キーボードのみでウェブサイトを操作できることや、色のコントラスト、文字の大きさなどもその範囲内です。
ただ、一番難しいものはやはり Screen Reader の対応です。基本的に、NVDA や Jaws、アップルの VoiceOver に対して、各ブラウーザーはインターフェースを提供していますが、実装により、いろいろ違いがあります。そこで、HTML タグで解決できないものを aria 属性を使うことです。
HTML は基本中の基本です。まず、一ページには各メインコンテンツにジャンプするリンクを入れたほうがいいです。Tab キーを押すと、隠しているリンクを画面 上に表示して、ページ中のコンテンツにジャンプします。
次、header, h1 - h6, nav, fieldset, label, form の HTML コードはできるだけ正しく書かないといけないです。screen reader を使うユーザーは主にショートカットキーを使うので、Jaws の場合、Insert + H ですべての h1 - h6 のタグをリストすることができます。同じように、一つのキーですべてのリンクをリストして、一つ一つ見て、好きなところに行くこともできます。だから、リンクはできるだけ意味を持った文言を使わないといけません。"Learn more" とか全然わからないものを使わないでおこう。
そのあと、もし HTML のタグが解決できないことを Aria 属性と JavaScript を使うことです。例えば、pop up dlg の tab order や、aria-live を使って、ユーザーに画面に何か起こったかを知らせるとか。いろいろあります。
最後に、特殊のデバイス対応する場合、特殊のことをしないといけない。例えば、auto complete など複雑な Input を機能を説明するために、aria-label などを使うとか。
それでは、後日また。
2017年1月29日日曜日
React Component の Render 関数を変更
先週、作ってる Web App が別のサイトに入れることになりました。機能としてはそのままですので、JS ファイルをロードすれば ReactDOM.render () 関数を呼び出して、CSS もロードすれば、そのまま Component が動くので、とても便利です。ただ、そのサイトの Analytics 仕組みが今まで使ってるものと違って、<a> や <button> などには data-tracker-type とか、Analytics 専用の属性を追加しなければならない。
つまり、入れる場所により、render する Component の HTML が少し違います。まぁ、一番思いついた方法はやはり、一つの <a> や、<button> を探し出して、属性を追加するだけです。ですが、これは根本的な解決方法ではありません。なぜなら、開発者にとって負担になるからです。
本来、プログラミングで解決できる問題は、力でやるのはあまり良くないのです。もう一つの方法としては、property を childContext とか、そのまま各 Component に設定して、render 関数の behaviour をその property を読んで、変更すると。
property をパスとかいろいろ面倒だから、さらに変更方法を調べてみました。そこで、render 関数を直接変更したほうがもっと簡単だろうと。具体的には、react.createClass(spec) 関数で返された instance には type という実際の Component が含まれています。
component.type.prototype.render は定義された render 関数です。
DOM に render する前にその render を変更すれば、そのタイプの Component の HTML も変わります。
後日また詳細を。それでは。
つまり、入れる場所により、render する Component の HTML が少し違います。まぁ、一番思いついた方法はやはり、一つの <a> や、<button> を探し出して、属性を追加するだけです。ですが、これは根本的な解決方法ではありません。なぜなら、開発者にとって負担になるからです。
本来、プログラミングで解決できる問題は、力でやるのはあまり良くないのです。もう一つの方法としては、property を childContext とか、そのまま各 Component に設定して、render 関数の behaviour をその property を読んで、変更すると。
property をパスとかいろいろ面倒だから、さらに変更方法を調べてみました。そこで、render 関数を直接変更したほうがもっと簡単だろうと。具体的には、react.createClass(spec) 関数で返された instance には type という実際の Component が含まれています。
component.type.prototype.render は定義された render 関数です。
DOM に render する前にその render を変更すれば、そのタイプの Component の HTML も変わります。
後日また詳細を。それでは。
2017年1月14日土曜日
React.js Component stateless から stateful に変更に伴う問題点
今週、新しい機能を実装しているうちに、ある Component を Stateless から Stateful に変更しました。その Component を使っているところはあまり変わりがないと思いました。ただ、テストすると、ちょっとだけ不具合が発見しました。
React.js は Component を更新する際に、もし _owner, key と component の type 変更がなければ、その Component を再利用して、HTML も再利用します。ここで、再利用される Component はもし State を持っている場合、その State は更新されません。もし何か State にある変数を更新したい場合、自分でやるしかないです。ここで、componentWillReceiveProps () 関数が利用して、setState を呼び出して、変数を更新します。
componentWillReceiveProps では、setState を呼び出しても、実際は一回の Render にまとまります。かなり便利な関数ですね。
ネットでは、毎回 key を変更すれば、React.js は毎回新しい Component を Mount するので、心配しないで済むとの方法もありましたが、新しい Component を作るにはまたいろいろコストがあるので、前のものを再利用したほうがいいでしょう。
React.js の中に、Component を更新する方法は setState と新しい Props を渡す、forceUpdate() を呼び出す3種類しかないし、forceUpdate() はあまりおすすめできないし、setProps もないので、setState をうまく使わないといけないです。
これでまたいつ Component は state を持つべきかとの原点に戻りました。Redux を使うと、store の中に state を置いて、その state と関係あるところは container を通じて、自動的に更新されますが、ただ、それは app 範囲の state の方です。state を持ってる component があまり向いてないようが気がしています。なぜなら、store は個別の component の state を持ってると、もし同じような component 複数ある場合、別の reference を使わないといけません。あるデータをある component のものと示すためです。
この場合、Wrapper を使ったほうがいいようなが気がしています。state に入れるものは親 Component を持っていて、前の stateless の component も残したほうがいいでしょう。これで、state がいるかどうかによって、使い分けもいいでしょう。とにかく state を持ってない component が再利用しやすいから。ネットでは presentation component という design pattern もあります。こちらは render のみ提供する component と lifecycle 関数や、state を操作する関数を別の component に入れて、container component 両方分けて、どっちでも再利用しやすくするための方法です。
それでは。
React.js は Component を更新する際に、もし _owner, key と component の type 変更がなければ、その Component を再利用して、HTML も再利用します。ここで、再利用される Component はもし State を持っている場合、その State は更新されません。もし何か State にある変数を更新したい場合、自分でやるしかないです。ここで、componentWillReceiveProps () 関数が利用して、setState を呼び出して、変数を更新します。
componentWillReceiveProps では、setState を呼び出しても、実際は一回の Render にまとまります。かなり便利な関数ですね。
ネットでは、毎回 key を変更すれば、React.js は毎回新しい Component を Mount するので、心配しないで済むとの方法もありましたが、新しい Component を作るにはまたいろいろコストがあるので、前のものを再利用したほうがいいでしょう。
React.js の中に、Component を更新する方法は setState と新しい Props を渡す、forceUpdate() を呼び出す3種類しかないし、forceUpdate() はあまりおすすめできないし、setProps もないので、setState をうまく使わないといけないです。
これでまたいつ Component は state を持つべきかとの原点に戻りました。Redux を使うと、store の中に state を置いて、その state と関係あるところは container を通じて、自動的に更新されますが、ただ、それは app 範囲の state の方です。state を持ってる component があまり向いてないようが気がしています。なぜなら、store は個別の component の state を持ってると、もし同じような component 複数ある場合、別の reference を使わないといけません。あるデータをある component のものと示すためです。
この場合、Wrapper を使ったほうがいいようなが気がしています。state に入れるものは親 Component を持っていて、前の stateless の component も残したほうがいいでしょう。これで、state がいるかどうかによって、使い分けもいいでしょう。とにかく state を持ってない component が再利用しやすいから。ネットでは presentation component という design pattern もあります。こちらは render のみ提供する component と lifecycle 関数や、state を操作する関数を別の component に入れて、container component 両方分けて、どっちでも再利用しやすくするための方法です。
それでは。
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!
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 でも。
これはアプリが一定程度に複雑になった話しです。通常であれば、属性で関数とかを子や孫に渡すべきです。
それでは。
それで色々調べて、考えました。まず解決方法として、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. :)
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. :)
登録:
投稿 (Atom)