Polymer.importでWeb Componentsをlazy loadする


この記事はPolymer Advent Calendar 23日目の記事です。

前回の記事で紹介したvulcanize編では初期ロード時に必要なcomponentsを一つにまとめてしまおうというツールの紹介でした。

今回の記事は、同じくPolyermerのパフォーマンスアップのためのTips紹介ですが、少し話題は変わってWeb Componentsをlazy load(遅延ロード)する話です。

もし初期化時に必要がないweb componentsがある場合は、Polymer.importを使って、必要な時にweb componentsを動的にロードすることで初期ロード時のパフォーマンスを高めることができます。初期表示に必要ないUI部品を多く含むアプリケーション(例えば、モーダルをたくさん持つ大きなアプリケーションなど)の場合、lazy loadによる恩恵は多いと思います。

Polymer.import

Polymer.import(urls, callback)
https://www.polymer-project.org/docs/polymer/helpers.html

非同期にコンポーネントをロードして、readyになったタイミングでcallbackが呼び出されます。(RequireJSなどAMDに似てる)

Polymer.importを使ってみる

単純にボタンを押したらcomponentをロードするという簡単な例ですが、自作コンポーネントで試してみました。(この自作コンポーネント自体に関しては以前の記事をご参照ください。)
(※Polymerのバージョンはv0.5.2です)

初期表示時にコンポーネントを表示する場合の、元々のHTMLの定義は以下のようになっています。

<!doctype html>
<html>
<head>
    <title>Polymer example: left-swipe-action</title>
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
    <script src="bower_components/webcomponentsjs/webcomponents.js"></script>
    <link rel="import" href="bower_components/polymer/polymer.html">
    <link rel="import" href="left-swipe-action.html">
    <style>
        html, body {
            height: 100%;
            margin: 0;
            background-color: #E5E5E5;
        }
    </style>
</head>
<body unresolved>
    <div>
        <left-swipe-action>
            <div style="height: 120px;">
                <div>Title</div>
                <div>Description</div>
            </div>
            <left-swipe-action-button style="background-color: #E81D62;" onclick="alert('delete')">Delete</left-swipe-action-button>
            <left-swipe-action-button style="background-color: #9F499B; color: #fff;" onclick="alert('favorite')">Favorite</left-swipe-action-button>
        </left-swipe-action>
    </div>
</body>
</html>

デモ(swipeできます)

(元のページはこちら)

このweb componentsを今度はボタンを押した時にimportを行うように変更してみます。

lazy loadのデモ(importボタンを押してみてください)

(元のページはこちら)

lazy loadのデモのコードは以下のようになりました。

<!doctype html>
<html>
<head>
    <title>Polymer example: left-swipe-action</title>
    <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
    <script src="bower_components/webcomponentsjs/webcomponents.js"></script>
    <link rel="import" href="bower_components/polymer/polymer.html">
    <style>
        html, body {
            height: 100%;
            margin: 0;
            background-color: #E5E5E5;
        }
    </style>
</head>
<body>
    <div>
        <button>Import</button>
        <left-swipe-action style="display: none;">
            <div style="height: 120px;">
                <div>Title</div>
                <div>Description</div>
            </div>
            <left-swipe-action-button style="background-color: #E81D62;" onclick="alert('delete')">Delete</left-swipe-action-button>
            <left-swipe-action-button style="background-color: #9F499B; color: #fff;" onclick="alert('favorite')">Favorite</left-swipe-action-button>
        </left-swipe-action>
    </div>
    <script>
        // web components dynamic load
        var button = document.querySelector('button');
        button.addEventListener('click', function() {
            Polymer.import(['left-swipe-action.html'], function(){
                document.querySelector('left-swipe-action').style.display = 'block';
            });
        });
    </script>
</body>
</html>

今回のコードの変更点は3つほど。

  • 自作コンポーネント(left-swipe-action)のimportのlinkタグを消す
  • import用のbuttonの設置
  • 自作コンポーネントをdynamicにロードするコードの追加

Polymer.importの第一引数でコンポーネントのファイル名、第二引数ではロード完了時のcallbackを指定しています。

今回の例では自作コンポーネントの内側にノードをlight DOMとして受け取っているため、外側のleft-swipe-actionタグ自体はブラウザにunknownなタグとして解釈されて何も無いものと扱われるだけなのですが、その内側のdivなどの要素はPolymer.importを実行する前から表示されてしまいます。なので、今回はPolymer.importを呼ぶ前にはdisplay: noneをセットしておき、callbackでdisplay: blockに変更するという処理を入れました。

ということで、デモを見て分かるように、unknownだったweb componentsがPolymer.importのタイミングでカスタムエレメントとして動作をするように変化するようになりました。

以上、今回はPolymerのweb componentsのlazy loadを実現するPolymer.importについて紹介でした。