Polymer 1.0の挙動変更の影響

Polymerの1.0がリリースされました。今回は、AndroidとAndroid Ware、IoTの比重が大きく、ブラウザ関連の発表が少ないGoogle I/Oでしたが、Polymer 1.0はその中の貴重な発表の1つでした。

# Polymerとは何か？

Polymerはフレームワークではなく、さまざまな他のフレームワークの「下」で使える拡張可能なHTMLのレイヤーです。コンポーネントという言葉やコンポーネント的なものはMithril.jsやReact、Angular.jsさまざまなWebMVCで登場しますが、コンポーネント同士の互換性はありません。WebComponentsはコンテナ船のコンテナ的な、どこでも使えるコンポーネントを提供します(コンテナ船のメタファーはGoogle I/Oの説明から)。

1.0は0.5とくらべて、Chrome上で3倍、Safari上で4倍になっているとのこと。またファイルサイズもgzipした状態で19-42kbで30-60%小型化しています。

0.5ではcore-elements(共通部品)とpaper-elements(GUI要素)という2種類のカテゴリ分けだったのが、[一気に7種類に](https://elements.polymer-project.org/)。core-elementsはiron-elementsと名前を変え、共通部品の中に紛れてたGUI要素はpaper-elementsに引っ越しし、サービスワーカのplatinum-elements、アニメーションのneon-elementsなどが追加されました。

# 0.5とは互換性がない

その一方で、[移行ガイド](https://www.polymer-project.org/1.0/docs/migration.html)にある通りですが、0.5系と互換性がない部分がいくつかあります。

自分でタグを作成するための書き方もまず変わっています。

```html:before
<polymer-element name="タグ名">
  <template>
    置き換え後のタグ
  </template>
  <script>
     Polymer({
       // イベントハンドラや設定など
     });
   </script>
</polymer-element>
```
```html:after
<dom-module id="タグ名">
  <template>
    置き換え後のタグ
  </template>
</dom-module>
<script>
   Polymer({
    is: "タグ名",
    properties: {
      // イベントハンドラや設定など
    },
    valueChanged: function() { … } 
   });
 </script>
```

タグが利用可能になった後のコールバックのイベント名も変わりました。

```js:before
window.addEventListener("polymer-ready", function() {
});
```

```js:after
window.addEventListener("WebComponentsReady", function() {
});
```

内部的には、エミュレーションが難しいShadow DOMの完全なPolyfillはやめて、より軽量なShady DOMという仕組みを利用しています。

# Shady DOMの影響

0.5.5のPolymerはHTMLの状態と、インスペクタで見たタグの状態がほぼ同一でした。次のようなタグを作ったとします。

```html:source
<paper-button>hello world</paper-button>
```

0.5.5をインスペクタで見てコピペするとつぎのようなHTMLが得られます。インスペクタで見ると内部に``#shadow-root``というノードがあって、この中に色々作られていてそれがカプセル化されているのが分かります。

```html:0.5.5
<paper-button role="button" tabindex="0">hello world</paper-button>
```

1.0は次のようなタグに展開されます。``paper-ripple``は波状のクリック効果を発するタグで、``paper-material``はマテリアルデザインの紙です。枠が浮いて、ドロップシャドウを表示するアレです。デフォルトでは影は何もないのですが、``<paper-button raised>ラベル</paper-button>``と宣言すると、``<paper-button>``が継承しているbehaviorによって、elevation(持ち上がっている距離)が0より大きい数値になって、影が付きます。

```html:1.0
<paper-button role="button" tabindex="0" aria-disabled="false" class="x-scope paper-button-0">
  <paper-ripple class="style-scope paper-button">
    <div id="background" class="style-scope paper-ripple"></div>
    <div id="waves" class="style-scope paper-ripple"></div>
  </paper-ripple>
  <paper-material animated="" class="content  style-scope paper-button x-scope paper-material-0" elevation="0">
    hello world
  </paper-material>
</paper-button>
```

これはテンプレートから生成されたものなので、外部から変更を加えたときにすぐに壊れます。jQueryで試しに次のように変更したとします。

```js
$("paper-element").text("新しいラベル");
```

0.5.5の場合は、正しくボタンのラベルだけが変更されたのですが、1.0は波状効果もパネルもクリックを受け付ける機能もすべてすっ飛んで、たんなるラベルになってしまいます。

jQueryはサンプルを簡単に書くためのもので実際に使う予定はないのですが、Virtual DOMとかでちょっとパラメータを変えようとか、ラベルを変更しようとすると動かなくなってしまうので、さてどうしようかなと思案中です。

# 0.5と同じShadow DOMを使う (6/3 更新)

[Azuさんのところ](http://jser.info/2015/06/02/Angular1.4.0-Polymer1.0/)経由で知った[ハブろぐさんのところ](http://havelog.ayumusato.com/develop/webcomponents/e672-polymer_050to100_changelog.html)の0.5→1.0の変更点メモに解決策が書いてありました。

```html
<script>
    window.Polymer = window.Polymer || {};
    window.Polymer.dom = 'shadow';
</script>
```

これを追加したら、Virtual DOM経由でうまくPolymerが動作しました。インスペクタで見た内部も0.5.5と同じっぽいです。実際、デフォルトのShady DOMじゃないバックエンドを選ぶわけで、どれだけ動作するのかはヒトバシラーになる覚悟は必要そうな気がしますが、0.5.5でとどまらなくても先に行けそうなのはうれしいです。

## ChromeとOpera以外は動きませんでした (6/8 更新)

``window.Polymer.dom = 'shadow';`` はShadow DOMを使うものの、ネイティブ対応していないブラウザ(試したのはFirefox, Safari)ではやはりソースのHTMLと違う構造のタグになってしまいます。Electronみたいにブラウザの種類が現的できるならありですが、それ以外の環境で仮想DOMとPolymerを組み合わせるのはまだ難しそうです。

現状で対応しているのは、Chromeファミリー(ChromeとOperaとAndroid Browser, Chrome for Android)だけですね。

http://caniuse.com/#feat=shadowdom

Polymerも、仮想DOMは想定していないで作られていて(内部で激しくDOM操作する)、仮想DOMもWebComponents polyfillを想定して作られていなくて、お互いに未知との遭遇を果たしたというのが2015年5月の出来事なので、これから改善されていくことを期待したいです。