最近、Ember.js アピールが足りてないと感じたので、GitHub 上でもう少しアピールしてみることにしました。

Generated by https://github.com/tricknotes/we-love-ember
最近、Ember.js アピールが足りてないと感じたので、GitHub 上でもう少しアピールしてみることにしました。

Generated by https://github.com/tricknotes/we-love-ember
この記事は Ember.js Advent Calendar の1日目です。
やはり Ember.js は大人気のようで、 Advent Calendar もあとたった 22 枠しか空きがありません。(12/1現在)
すこしでも Ember.js に興味がある方は急いで登録されることをオススメします!
この記事では私が Ember.js に送ったのレガシー IE 対応のパッチをご紹介しつつ、IE での JavaScript の罠とその対応を紹介します。
今現在 IE と向き合っている方や、これから IE と向き合うことになる方のご参考になれば幸いです。
ちなみに、 Ember.js は 1.0.0 の時点で IE 6 ですべてのテストケースに通過しており、1.2.2 (現在の最新の安定版) でも IE6 上で動作します。
ここで、レガシーIE が何か、というのを定義しておきましょう。 本記事ではレガシーIE とは IE 6, 7, 8を指すことにします。
そして今回はレガシー IE についてのみ言及しているので、以降は単に「IE」と呼ぶことにします。
IE の JavaScript には多くの罠が存在します。
それもそのはず、 IE 9 未満は ECMA-262 ではなく JScript という JavaScript っぽい独自の言語だからです。
なので、まずは現在多くのプラットフォームで動作することが期待されている ECMA-262 3rd edition と互換性を目指すことで IE 対応を進めていきたいと思います。
ECMA-262 3rd edition で定義されている Array のメソッドの中で、 JScript では定義されていないメソッドがいくつか存在します。
Array.prototype.forEachArray.prototype.mapArray.prototype.indexOfそこで、 Ember.js にはこれらの足りないメソッドのために、互換性のある関数群が用意されています。
Ember.ArrayPolyfills.forEachEmber.ArrayPolyfills.mapEmber.ArrayPolyfills.indexOfこの関数群には、該当する Array にメソッドがすればそのメソッドが、なければ独自に定義した互換関数が格納されています。
ということで、この点についての IE 対応は比較的簡単です。
forEach や map が使われている箇所を、すべて互換関数に置き換えてしまえば対応完了です。
ホストで提供されている Function には本来 Function オブジェクトが持っているはずのメソッドである toString と apply が定義されていません。
信じられないことに、次のコードは IE では実行時例外となります。
setTimeout.toString();
//=> throw 'Object doesn't support this property or method'
toString に関しては、
String(setTimeout); //=> 'function() { [native code] }'
で回避できます。
ただし apply については一工夫必要です。
稀に、setTimeout を一時的にオーバーライドして引数をチェックした上で本来の setTimeout に渡したい、とったようなケースがあり、その際には apply をなんとかして使う必要があります。
私は Function.prototype.apply を setTimeout に apply することで対応することにしました。
var apply = Function.prototype.apply; apply.apply(setTimeout, [this, arguments]);
Object.prototype のプロパティと同名のプロパティが for in で列挙されない通常 for ~ in ループでは、オブジェクト自身が持っているプロパティを列挙することができます。
しかし IE では、Object.prototype で定義されているプロパティと同じ名前のプロパティについては列挙されません。
var object = { toString: function() { return 'hi' } }; for (var key in object) { // 一般的な JavaScript とは違い、toString が列挙されない。 }
この対応についてはかなり悩んだ結果、事前に Object.prototype のプロパティ名の配列を用意しておき、ひとつひとつプロパティをチェックするようにしました。
var keys = [ 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'valueOf', 'toLocaleString', 'toString' ]; for (var i = 0, length = keys.length; i < length; i++) { if (object.hasOwnProperty(key)) { // ここでは toString が取得できる } }
window のプロパティは別IE では 「global 変数 = window のプラパティ」というわけではありません。
greet = 'hi'; window.greet; //=> 'hi' greet; //=> 'hi' window.greet = 'bye'; window.greet; //=> 'bye' greet; //=> 'hi' // ここで一般的なブラウザは 'bye' が変える
globa 変数を使わなければ問題ないように見えますが、もとから存在する global 変数を一時的にスタブしたいといった場合には致命的な挙動となります。
なので、そういったケースであれば、常に window 付きで変数にアクセスするというのが有効です。
他にも、Object.create が不完全な状態で実装されていたり、<a> の href に必ずホスト名が含まれたり、<input type=checkbox>は focus して blur しないと change イベントが発火しなかったりといった DOM 由来の奇妙な動作がいくつかあるんですが、今回は詳しい説明は割愛します。
苦行とされるIE対応も、やってみると意外な発見がありました。
ちなみに、わたしがなぜ Ember.js の IE 対応を行なっているかというと、もちろん Ember.js 自体の価値になるというのもあるんですが、
一番の理由は過去に経験した IE 対応の案件で大変苦い思いをしたからです。
当時 IE をあまく見すぎていたために、時間・体力・精神力の大部分を持って行かれてしまいました。
案件が始まる前からちゃんと IE と向き合っていられれば、そして当時 IE に対応した Ember.js があれば、何かが違っていたかもしれません。
そこで、「過去の自分を救いに行く作業」を経験された hmsk センパイを見習うことにしたのです。
今回ご紹介したのは、実は JavaScript の IE 対応のほんの一部の Tips です。
実際に web サイト/アプリを IE 対応させようとした場合には、 JavaScript 以外にも DOM や CSS も対応させる必要がありますし、
さらにそれを統合した状態で期待通りに動くよう調整を行なう必要があります。
というわけで、IE と向き合っているみなさまにとって、本記事が少しでも手助けになれば幸いです。
では、引き続き Ember.js Advent Calendar をお楽しみくださいませ :-)
「東京Node学園際2013」に参加して「Node.js を選ぶとき 選ばないとき」というタイトルで発表してきました。
ぼくが今まで作った web アプリケーションの例を挙げつつ Node.js と Rails を比較するという内容です。
みなさまが Node.js を選択する(かどうかの)際の参考となれば幸いです。
また、開催日直前まで台風の接近で開催が危ぶまれていましたが、台風の進路変更で無事開催できることとなりました。
このあたりの事前の判断そして告知など運営のみなさまは大変な思いをされたのではないかと推察します。大変お疲れさまでした。
「はじめる Ember.js!!」というタイトルでお話してきました。
デモに使ったアプリ(+ソースコード)はこちら
Ember.js 可愛いよ Ember.js。
以前書いていたブログ記事で、致命的なセキュリティ上の不具合があったのでその訂正についてお知らせします。
どのような不具合かというと、本ブログ記事にしたがって middleman の自動ビルドを Travis に設定している場合、GitHub トークンが Travis のログに残ってしまい第三者に悪用されるという可能性があるというものでした。
該当の箇所はすでに修正してありますので、今後の設定については問題ありません。
今まで参照してくださっていたみなさま、大変申し訳ありませんでした。
今利用中の Token については expire していただいて、新しい Token を再設定していただけるとありがたいです。
不具合について連絡してくださった @azu_re さん、対応方法を連絡してくださった @hokaccha さん、大変ありがとうございましたっ!!
Sapporo.js - 2013.07.27 に参加してきました。
今回は、 @tmaeda さんが Angular.js、@iakio さんが Knockout.js について発表をしてくださいました。
簡単にですが、お二方の発表についてのぼくの感想をまとめておきます。(主に自分のメモ用)
"Angular.js はフレームワークではない! HTML の再実装だッ!(バーン"
JSON の serialize/deserialize やコミットのタイミングなど、外部 API とのやり取りは特にサポートしていないのでプログラマが自分でなんとかする必要があるとのこと。
変数名で DI を実現しているとことで、minify とは相性が悪そう -> 書き方で回避できるよ!
生の JavaScript の延長線上に存在している気がして、メソッド名を見るだけでもなんとかくどうなるかわかりやすい
"Knockout.jsはフレームワークではなくライブラ リだ(ズギャーン"
ko.computed は依存性をプログラマが明示する必要がない、っていうのはかなりすばらしいと思いました。 -> "定義時に一回実行してみる"
あまり大それたことをやっているライブラリではないので、Backbone.js を触ったことがあるひとならすぐに馴染めるのかな、という感じでした。ぼくは Knockout.js は触ったことがないですが。
ちなみに、この MV* の空気を読まずぼくは Ruby の Middleman について発表してきました。
発表資料はこちら:
当日いただいた感想:
.@tricknotes 先生が #sapporojs で Ruby の話しかしていない。JS嫌いの私としては大変癒されます。
— Tomoki MAEDA (@tmaeda) 2013, 7月 27
今回、ぼくからの発表お願いを快く引き受けてくださったお二人には感謝の気持ちでいっぱいです。
今後共よろしくお願いいたします。