Code

2017年7月8日土曜日

Observable Lib Rx.js ってなに?

 結構前から、Microsoft が Observable という概念の元に、いろんな Lib を開発し始めました。そのあと、約 3 年前、Rx.js が出てきました。いわゆる Reactive Programming の JavaScript バージョンです。Angular 4 は基本的に Observable を使って、Data Binding を行なっています。
 Rx.js 今のバージョンは 4.0 です。Netflix のエンジニアが 5.0 を開発しています。Observer Pattern を元に、Browser の Scroll Event や、Promise、Array などのデータタイプから Observable に変更する関数がありますし、map、filter などデータの操作関数、flatMap, flatMapLatest などの関数も実装されています。
 Event Stream を操作するので、やや抽象的ですが、実際使ってみると、そんなに難しいことではないそうです。
 例えば、ajax 関数を使うと、request を送って、response が帰ってきたら、subscribe() したlistener 関数を自動的に呼び出します。一見 Promise と変わらないですが、Event になると、結構変わります。
 例として、
    obs$.debounceTime(500)
    .map(ev => ev.key)
    .distinctUntilChanged()
    .scan((acc, one) => acc + one)
    .subscribe(term => this.search(term));
debounce などの機能は簡単にできます。

 それだけではない。Observable は chain, merge, zip などの関数もあるので、複雑な操作は簡単にできます。
 例えば、Promise ではできない、ajax call キャンセルするという機能も簡単にできます。

 ただ、Rx.js Lib かなり大きいなので、使う時は、こまめに operator など import すべきです。
 それでは。

2017年6月25日日曜日

アクセシビリティよくある間違い

 先日、新入社員というか、ジュニア開発者に対して、チームレベルのアクセシビリティ研修が行われました。結構効果的でした。一番聞かれたことはどうやって Form を実装するか、Screen Reader はどう使うかと。
 その中に、ちょっと理解の間違いが気づきました。一つはアクセシビリティは Screen Reader のことを全てだと思われているそうです。アクセシビリティはそれだけではありません。キーボードのみユーザーや、目に障害ある方や、いろんな対象があります。
 実は良い HTML を書けば、自然に Screen Reader が動きます。aria の属性は通常の HTML tag や、属性が動的ではない場合、転用された場合を使うのので、メインではありません。例えば、HTML に fieldset という tag があります。それはラジオボタンなどを一つの括りとして表示する場合使います。それを使うと、 Screen Reader は自然にそれを認識して、Role - Function - current situation の順に読みます。もし div タグを使うと、通常のコンテンツとして認識しますので、同じようには読みません。ラジオボタンの選択を変更する場合、何が読まれたかをよく聞いて、すぐ区別がわかります。
 次に、全てのコンテンツが tab キーで読ませると。それは間違っています。tab キーは interactive element のみ stop します。もし、むやみにすべてのコンテンツを止まるようにしたら、それは通常と違うので、逆にわかりづらくなります。例えば、a tag など、href があれば、tab stop は起きます。順番として、top - bottom, left - right に stop すべきです。
 ユーザーは通常 Shortcut key を使って、例えば、Insert - L とか、画面にある全部の a link をリストして、画面に表示します。これは [learn more] という link が良くないことをわかるはずです。コンテキストがわからないから、learn more というのは何の more になるかわかりません。だから、ボタンなら button を使って、link なら a tag を使うべきです。
 最後に、色の Contrast Ratio も注意すべきですし、文字のサイズも対象です。それに、High Contrast モードもあるので、それを使うときのサイトも一度チェックした方がいいでしょう。
 まぁ、Screen Reader だけ対象にすべきではないです。

 ちなみに、Screen Reader を使うとき、IE を使うべきです。驚くかもしれませんが、今 JAWS とか Chrome でのサポートが IE ほど良くありません。全て一つのブラウザーでテストすべきではないです。
 それでは、また。

2017年6月10日土曜日

Angular 4 vs React.js vs Polymer and some thinking of component

 # I posted the same article on Medium, and will use Medium from now on.
https://medium.com/@newying61/angular-4-vs-react-js-vs-polymer-and-some-thinking-of-component-596085325d5

 This week, I got some time to have a look at Angular 4 and Polymer, the two frameworks for developing component based SPA. As I have used React.js for about 2 years, just wanted to write down what I feel about these two comparing with React.
 First about Angular 4. It is said to be component base, but when I saw other projects which are using it, I just feel, it's kind of like Angular 1. Component becomes controller, and all the logic are still in services. Also, it's quite confusing about directives, when and where to use it...
 I should say, Angular 4 's learning curve is too high, and if you use it, it's very easy to get effected by the former experience with Angular 1.
 For Polymer, it's quite well organised and because of it's shadow dom is a standard, it can make HTML so easy to understand. Although, it has two way bindings just like Angular, it is still a UI library, not like Angular as a framework.
 So, Polymer can easily re-organised with Redux by adding a store component and pass it anywhere by using a singleton pattern.
 Compared to React.js, I think Polymer may be a good competitor. It also batch the changes to DOM and can make some operations easier by two way binding.

 Then I started to think about what component means for SPA. React.js and Polymer let you define a component and by wrapping it with other components or using higher order components you can organise an app with good structure. Angular 4 can do the same thing, but compared the effort, I would say, React.js and Polymer are much better.
 A component should be kind of dumb, which means it should only care about itself and only work with the attributes passed in. It can has it's own state (state in React.js component and property in Polymer component) to control how it looks like.
 Also, it doesn't care about what it's children looks like. By wrapping anything, we can just create a new component with new functions.
 This can dramatically increase the usability of the components. We can use it anywhere and it should just work. :)
 Also by doing this, it can easily integrate with other libs like Redux to control model data.
 A warning is, if a state is only related to a specific component, then it should not be put in store, don's abuse Redux to store everything.

 A good example is Polymer's iron-page, by defining the selected attribute and the target attribute, it just select the right child component and add a new attribute to it.
 The same as react-router, just define the structure, and it just work.
 By the way, compared to these two, Angular 4's router is kind of ugly. It needs a json object... which is not direct at all...

2017年5月7日日曜日

How to use React-Intl to format multiple message id

 Recently, I am working on some project using React-Intl to format strings. One of the bad things about it is, the FormattedMessage component only support one id and a long message. When you want to combine several short messages together, it's kind of hard.
You have to use something like this (please refer react-intl document):

<FormattedMessage
    id="welcome"
    defaultMessage={`Hello {name}, you have {unreadCount, number} {unreadCount, plural,
    one {message}
    other {messages}
    }`}
    values={{name: <b>{name}</b>, unreadCount}}
/>

When you want to do something like format aria-label for a button, you have to wrap a function:

<FormattedMessage id="aria-label-id" defaultMessage="label">
    { (label) =>
          <button
            type="button"
            className="test"
            aria-expanded={expanded}
            aria-label={label} />
    }
</FormattedMessage>

In fact it's quite hard to use, also the format makes it difficult to read if you have a lot of buttons to render.

An easy way to avoid this is to use it's injectIntl function to wrap your component, like this:

import {injectIntl, intlShape} from 'react-intl';

const ButtonComponent = ({className, intl}) => (
    <button className={className} aria-label={intl.formatMessage({id: "aria-label", defaultMessage="test"})}>
        <span>Button Icon</span>
    </button>
);

ButtonComponent = {
    date: PropTypes.any.isRequired,
    intl: intlShape.isRequired,
};

export default injectIntl(ButtonComponent);

 injectIntl will create a wrapper component for the ButtonComponent, which will inject a childContext with locale and message information. Also it inject the intl prop for using.
By this intl prop, you can use the APIs like formatMessage (which is used inside the FormattedMessage component).

 When you want to use multiple messages to combine together to be a string, currently, there is no good way to do it, as far as I read the documents and looking into the examples.
So I created something to do it:

class Formatter extends React.Component {
    static defaultProps = {
        as: 'span'
    };

    constructor(props) {
        super(props);
        this.getFormattedMsg = this.getFormattedMsg.bind(this);
        this.formatMessage = this.formatMessage.bind(this);
    }

    getFormattedMsgWithValue(match, p1) {
        const { intl, defaultMessage } = this.props;
        return intl.formatMessage({ id: p1, defaultMessage });
    }

    formatMessage(msg) {
        return msg.replace(/@{([\w]+)}/g, this.getFormattedMsg);
    }

    render() {
        const { intl, as, ariaLabel, children, ...others } = this.props;

        if (children) {
            if (typeof children === 'string') {
                others.childre = this.formatMessage(children);
            } else {
                others.children = children;
            }
        }

        if (ariaLabel) {
            others['aria-label'] = this.formatMessage(ariaLabel);
        }

        return React.createElement(as, others);
    }
}

export default injectIntl(Formatter);
 
Then you can use this Formatter function like this:

<Formatter as="button" className="btn" aria-expanded={expanded}>
    {`@{label-id} ${otherParams} @{another-label-id} ${others}`}
<Formatter>

Or you can just wrap some children like this:

<Formatter as="button" className="btn" aria-label={`{@{aria-label-id} others`}>
    <span className="btn-icon arrow"></span>
<Formatter>

If you want to format with values, just change getFormmatedMsg like the following:

    getFormattedMsgWithValue(match, p1) {
        const { intl, defaultMessage, values } = this.props;
        const targetValue = (values && values[p1]) || {};
        return intl.formatMessage({ id: p1, defaultMessage }, targetValue);
    }

Will raise a pull request for the FormmattedMessage component in react-intl later, when I got enough time to make it properly.

2017年4月22日土曜日

Server Side Rendering の注意点

 いろいろ契約上の問題で、今のプロジェクトは Server Side Rendering 使ってないですが、個人趣味でいろいろやってました。React.js は JSX を使って、DOM を作ってるので、AngularJSに比べて、Server Side Rendering に向いています。
 まず参考として、下記の記事があります。
 もし ReactRouter 使ってない場合、これはさらに簡単になります。React には renderToString, renderToMarkup などの関数があります。それを使って、props などを設定すれば、自然に HTML string が出来上がります。こちらは注意すべきところは ajax を使って、データを lazy load する場合です。
 Server Side Rendering を使ってる場合、componentDidMount が呼び出されないので、この中に使ってる ajax は当然呼び出されません。解決方法としてはまず isomorphic-fetch を使って、データを取得します。その promise then 関数の中に、React.js Component を render します。また、componentWillMount が呼び出されるので、その中で ajax call してもいいような気がしています。ただし、fetch してから react component を render するほうがよいと思います。
 また、一つ注意すべきところは、data の取得はできるだけ store と関係あるところでやりましょう。なぜなら、Server Side Rendering するとき、window.__data__ に初期 data を client side に渡す必要があるため、componentDidMount が呼び出されないので、自分で data の取得をいちいち洗い出して、自分で呼び出す必要があります。もし、service layer を作って、例えば、config data を取得する際に、いつも service.loadConfig 関数を読んで、その中に dispatch をすれば、store を返して、アプリの更新ができますし、Service Side Rendering の時も、通常通り、その関数を読んで、store 中の値をそのまま保存すれば、いいので、便利です。
 Node と Express を使ってる場合、require('react'); は react 直接ロードできますので、かなり便利です。だから、Node Express を使って、thin layer を作って、Web の Edge Layer として使ったほうがいいような気がしています。これで、API layer とも、Client Side ともスムーズに連携できるようになります。
 また Redux は pure javascript なので、普通に使えますし、サーバーサイドで実行する場合も当然 Client サイドと同じです。あまり気をつける必要がなさそうです。

 最近、React.js は結構流行ってます。preact とか、twitter lite とか面白そうなものが出てきました。次は Progressive Web App の時代かと。Safari は早くサポートしないとな。。。

 それでは。また。

2017年4月7日金曜日

Webpack 2 を使ってみた

 最近、なかなか時間が取れなくて、困ってます。プロジェクトも色々大変な事になって。。。
 唯一いいことは 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 サイドのコードをそのままサーバー側に実行することができます。
 また環境ができたら、後日詳細をメモしておきます。

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 などを使うとか。
 
 それでは、後日また。