EagleLand

2014.08.30

Web ComponentsをHTML Importsでロードする必要性

慣例的に<link rel='import' href='x-element.html'>な感じでロードされているけど、前提として、 HTMLImportsである必要はない 。何故ならば、Web Componentsを構成する4つの仕様はそれぞれ独立しているからである。だから、インポートを使わなくてもdocument.registerElement()でカスタム要素の定義は出来るし、HTMLのひな形を使いたい場合に<template>タグを使っても良い。

HTMLを部品として含む場合

HTMLやCSSを部品として含む場合は、<template>タグや、ShadowDOMを駆使しながらパーツを構成していくので、HTMLファイルに書かざるを得ない。もちろん、JavaScriptだけで書けないこともないんだけど、本質ではない。

先日画像をスクロール同期的にロードする要素、 1000ch/lazyload-image を作ったけど、こちらはHTMLファイルではなく、単一のJSファイル。GitHubが作っている github/time-elements なんかも、time-elements.jsだけで構成されているけど、こういう場合は<link rel='import' href='x-element.html'>ではなく、<script src='x-element.js'></script>で事が足りる。

他のWeb Componentsに依存している場合

<x-element><y-element>に依存している場合は以下のように、x-element.html内でy-element.htmlをインポートする。

<link rel='import' href='y-element'>
<template id="tmpl">
  <div>This is x-element!</div>
</template>
<script>
  var XElementPrototype = Object.create(HTMLElement.prototype);
  XElementPrototype.createdCallback = function () {
    console.log(document.querySelector('#tmpl'));
  };
  window.XElement = document.registerElement('x-element', {
    prototype: XElementPrototype
  });
</script>

そのコンポーネントからの相対パスを得たい

これは @hokaccha 氏が詳しく書いているが、Web Componentsとして配布するときに、画像等のサブリソースを含む場合は一工夫が必要になる。

例えば<x-element>というカスタムエレメントが以下のように、imgフォルダの配下にfoo.pngbar.pngを含んだ構成とする。

bowerなんかでインストールされればx-elementというフォルダごとダウンロードされて、いざインポートするときには<link rel='import' href='bower_components/x-element/x-element.html'>のようになる。

このとき、foo.pngbar.pngを含むフォルダはbower_components/x-element/imgというパスになるけど、x-element.html側で素直にimg/foo.pngと参照していると、インポート元のドキュメントルートからそのパスを辿ることになるので、上手く参照出来ない。

だからdocument.baseURIを使って相対パスを得たいということになるが、この場合に、HTMLファイルでないとdocument.currentScript.ownerDocument.baseURIと、x-element.htmlからみたベースのURLを辿れない。URLオブジェクトと組み合わせるとアレコレするときに幾分スマートかも。

<script>
  var doc = document.currentScript.ownerDocument;
  var imgRoot = new URL('img', doc.baseURI);

  console.log(imgRoot.href);
  // => bower_components/x-element/img
</script>

ネタに走った感あるけど、 https://github.com/1000ch/x-zangief は上記のようなパス解決をしている。