Web Components

**Web Components**（ウェブコンポーネンツ）はHTML要素をコンポーネント化する技術群の総称、またそれらを用いて作成されたコンポーネントである。

従来用いられていた「1つの巨大HTML、全体に適用されるCSS」を「再利用可能なコンポーネント群の組み合わせ」で実現するため、カスタム要素・Template要素・ShadowDOMを主要な技術要素として開発された。Web標準であり、すべての主要ブラウザでサポートされている。

## 背景
従来のHTMLは1つのHTMLファイルで構成され、スタイルを提供するCSSはHTML全体へ適用されていた。このHTMLは別のHTMLでは再利用できず、また巨大なHTMLに対するCSSはコーディングを難しくしていた。ゆえに、プログラミング言語における関数やクラスのように、再利用可能なまとまり（**コンポーネント**）を実現する仕組みが求められていた。

## 技術
上記の問題を解決するために、3つの主要なWeb Components技術が用いられる。

* カスタム要素: 再利用可能なまとまり（コンポーネント）としてカスタムHTML要素を定義可能にする
* ShadowDOM: CSSの適用範囲・JavaScriptのアクセス範囲を限定し独立したコンポーネント化を可能にする
* HTMLテンプレート: HTML要素群のテンプレート化を可能にし（template要素）インスタンスへの要素注入を可能にする（slot要素）

HTMLテンプレートによってHTML要素のまとまりを作り出し、ShadowDOMによってCSS・JavaScriptを含めてまとまりを隔離し、それらがHTML内で再利用可能なようにカスタムHTML要素化する。このコンポーネントを利用する際にslot要素へ適切な要素を挿入（注入）することで、引数を用いた関数呼び出し・classインスタンス化のように、コンポーネントの振る舞いを変えることができる。

### attribute-propertyリフレクション
HTMLの要素において、attributes（content attributes）とproperty（IDL attributes）は必ずしも値がリンクしない（）。Web Componentsにおいていわゆる**reflection**を可能にするには、そのための仕組みが必要になる。attributesはすべて文字列と定義されており、またpropertyは暗示的に静的型を持つため、propertyの型を事前に定義しattributesへのアクセス時に適切な型変換（文字列化、定義された型へのparse）をおこなうのが基本的な仕組みになる。

## 特徴

### カスタム要素
カスタム要素（Custom Elements）は、自律カスタム要素（autonomous custom elements）とカスタマイズされた組み込み要素（customized built-in elements）の2つのパートに分けられる。自律カスタム要素は、ネイティブのHTML要素とは完全に分離されたHTML要素であり、本質的にはCustom Elements APIを用いてボトムアップで構築される。カスタマイズされた組み込み要素は、ネイティブのHTML要素の上に構築され、元の機能を再利用できる。

### Shadow DOM

Shadow DOMは、ウェブブラウザがDOM要素をメインのdocument DOMツリーに追加せずにレンダリングできるようにする機能である。これにより、開発者とブラウザが到達できる範囲にバリアを作ることができる。開発者はネストされた要素と同じようにはShadowDOMにアクセスできなくなる一方、ブラウザはネストされた要素と同じ方法でレンダリングとコードの修正が可能になる。CSSを特定の要素のShadow DOM内にスコープすることでHTML要素をカプセル化でき、CSSスタイルがリークして意図しない影響を他の要素に与える恐れがなくなる。これらの要素はHTMLとCSSに関してカプセル化されているが、依然としてdocument内の他の要素が受け取るイベントを発火できる。

要素内のスコープされたサブツリーはshadow treeと呼ばれる。shadow treeがアタッチされた要素はshadow hostと呼ばれる。

Shadow DOMは、リテラル要素としてアタッチするか、またはscriptを使用して、常に既存の要素と接続されていなければならない。JavaScriptでは、Shadow DOMを`Element.attachShadow()`を使用してアタッチする。HTMLとCSSをスコープする機能は、カスタム要素の作成に不可欠である。仮にshadow DOMが存在しなければ、別の外部のカスタム要素が望まない方法で相互作用する可能性をなくすことはできない。

### HTMLテンプレート
HTMLテンプレート（HTML template）は、封印されるHTMLのチャンクを自由に挿入する手段である。HTMLテンプレートの構文は次ようになる。
```html
<html>
    <template>
        <h1><slot name="title"></slot></h1>
        <p><slot name="description"></slot></p>
    </template>
</html>
```
Scriptは実行されず、テンプレート内にあるリソースは、テンプレートがスタンプアウトされるまではフェッチされない。

## 実装
上記のWeb Components技術はすべてWeb標準であり、すべての主要ブラウザでサポートされている。ユーティリティライブラリを含め様々な実装方法がある。

* カスタム要素
** `customElements.define(elemName, elemClass)` :GlobalのcustomElementsに登録する。第2引数はHTMLElementを継承すること
*** `@customElement(elemName)` :LitElementライブラリのTypeScript Decorator。`customElements.define()`の糖衣構文
* ShadowDOM
** `Element.attachShadow()` :返り値のshadow rootにぶら下がる要素を追加していく。
*** LitElement class: 暗示的にshadowDOMをrootとする
* template要素
**  : HTML内でtemplate要素を宣言し、template要素の子要素にテンプレートを記述する
* slot要素
**`<slot>` : カスタム要素の子要素を受け入れることで要素のコンポジション（合成）をカスタム要素でも可能にする

上記の方法で作成されたWeb Componentsは最終的に以下のように利用される。
```html
<body>
    <my-element>
        <h2 slot="slot1">Hello, Web Components!!</h2>
        <span slot="slot2">This will be injected.</span>
    </my-element>
</body>
```


## ブラウザのサポート
Web Componentsは、すべての主要なブラウザでサポートされている。

古いブラウザの後方互換性は、JavaScriptベースのによって実装されている。

## コミュニティ
Webコンポーネントエコシステムには多くのコミュニティの取り組みがある。WebComponents.orgは既存のWeb Componentsを検索するインターフェイスを提供している。Custom Elements Everywhereは、有名なフロントエンドフレームワークがWeb Components標準と互換性があり使用できるようになっていることを検証し、修正街のバグと利用できるワークアラウンドを提供している。さらに、Vaadin Tutorialsは、これらのワークアラウンドを効果的に使用する方法をデモアプリの例と同様の関連トピックを用いて示している。

## 歴史
Web ComponentsはAlex RussellがFronteers Conference 2011で初めて発表した。

Polymerは、Web Componentsをベースにしたライブラリで、Googleが2013年に公開した。

Firefox 63はWeb Componentsのサポートをデフォルトで有効にし、2018年に開発者ツールがWeb Componentsをサポートするように更新した。

## 脚注



## 外部リンク

* Webcomponents.org
* Open Web Components
* Web Components | MDN
* Can I Use? - Browser Support for Custom Elements
* Custom Elements Everywhere - Framework Support for Custom Elements
* Web Components specifications
* What are Web Components?
* twoBirds
* slim.js library
* Polymer-Project
* SmartJS
* Salesforce Lightning Web Components
* DataFormsJS