こんにちは、プログラマーの衣笠です。
Web Componentsの各ブラウザでの実装がそろってきたのでそろそろ触ってみようと調べていたら、open-wcというものを見つけました。ツールを用意してくれていたので今回はこれを使って簡単なコンポーネントをひとつ作ってみたいと思います。
open-wc とは
Web Componentsを作成、共有する上での推奨事項をまとめてそれをツールとして提供することを目的とした集まりです。
推奨事項は
- Developing
- Linting
- Testing
- Building
- Demoing
- Publishing
- Automating
と章をわけてガイドを提供してくれています。 そこで推奨しているパッケージや設定を用意してくれていてツールで生成できるようになっています。
open-wcのツールで開発環境構築
ツールを使うと簡単に開発環境を用意してくれます。 npmが使えてプロジェクトのディレクトリを置きたい場所で
npm init @open-wc
とすると勝手にツールをダウンロードしてきて実行されます。
ツールが実行されると色々質問されます。作成されるものはその回答によって変わります。
今回は簡単は単一のコンポーネントのプロジェクトを作成したいと思うので以下のように回答すると
What would you like to do today? › Scaffold a new project What would you like to scaffold? › Web Component What would you like to add? › (選択なし) What is the tag name of your application/web component? … password-input Do you want to write this file structure to disk? › Yes Do you want to install dependencies? › Yes, with npm
password-input
ディレクトリを以下のような構成で作成してくれます。
. ├── LICENSE ├── README.md ├── demo │ └── index.html ├── index.js ├── package-lock.json ├── package.json ├── password-input.js └── src └── PasswordInput.js
テストやビルドの環境などをあとで追加したい場合、もう一度ツールを使って追加できます。
開発サーバー
ツールで生成されたディレクトリで npm run start
をすると開発サーバーが立ち上がってブラウザで 自動でdemo/index.html
を開きます。
開発サーバーは es-dev-server
というopen-wc お手製のパッケージが使われています。
open-wcはできるだけWeb標準に近づくことで長期投資をする方針で、開発も最新のブラウザでES Modulesを活用して進めることを推しています。なので es-dev-server
はビルドツールを使わない前提の仕様になっています。
ビルドの待ち時間がないっていうのはすごい魅力的ですね。
また、node_modules
のパッケージもいい感じに読み込んでくれます。
WebComponentの実装
今回は最近よくある入力したパスワードの内容を見えるように切り替えられるinput要素 password-input
を作ってみました。
作成したものをGlitchで埋め込んでおきます。View Appボタンでデモページに切り替えられます。
実装は src/PasswordInput.js
にしていきます。demo/index.html
はデモページです。
open-wcはLitElementとlit-htmlを使った実装を推奨していて、プロジェクト生成時点で使えるようになっています。
ここからはLitElementでの実装方法を説明していきます。
カスタム要素の定義
カスタム要素は通常HTMLElementクラスを継承したクラスを定義しますが、LitElementではLitElementクラスを継承して定義します。
タグ名とクラスの紐付けは password-input.js
で既にされているので触る必要がありません。
要素のプロパティ、属性
LitElementではゲッター properties
で返すオブジェクトで要素のプロパティを定義します。
... static get properties() { return { value: {type: String}, visibility: {type: Boolean} }; } constructor() { super(); this.value = ""; this.visibility = false; } ...
オブジェクトのプロパティに定義したいプロパティの名前、その値のオブジェクトに設定を指定します。
基本的に定義したプロパティと同じ名前の属性も一緒に定義されます。
type
を Boolean
にすると disabled
属性みたいな扱いになります。
初期値はコンストラクタで設定できます。
要素のコンテンツ
Web Componentsはカスタム要素のコンテンツをShadowDOMによって定義します。
LitElementでは render
メソッドに定義していきます。
... _toggleVisibility() { this.visibility = !this.visibility } render() { return html` <input type=${this.visibility ? 'text' : 'password'} value=${this.value} > <span class="toggle" @click=${this._toggleVisibility} > .... </span> `; } ...
render
メソッドはlit-elementが用意しているタグ付きテンプレートリテラルの html
を使ってコンテンツを定義します。
イベント名に接頭辞 @
を付けた属性にイベントハンドラをバインドできます。
要素のスタイル
要素のスタイルの定義は styles
ゲッターに定義します。LitElementが用意している css
タグ付きテンプレートリテラルを使います。
コンテンツのスタイルはShadowDOMの中に定義されてカプセル化されるので外の要素に影響しません。Vue.jsのscoped CSSと同じです。
CSSの管理が楽になるのでありがたいです。
... static get styles() { return css` :host { --icon-size: 24px; display: inline-flex; ... } ... input { line-height: 1em; ... } ... .icon { width: var(--icon-size); height: var(--icon-size); } ... `; } ...
:host
セレクタでカスタム要素のスタイルを定義します。カスタム要素のスタイルは外から変更可能です。
対してそれ以外のShadowDOMのスタイルは外から直接変更できません。
外から変更する方法のひとつにCSSカスタムプロパティを使った方法があります。
ここでは --icon-size
を定義して外からパスワードの変更を切り替えるボタンのアイコンのサイズを変更できるようにしています。
他にも Shadow Parts という part
属性と ::part()
セレクタを使った方法があります。
::part() - CSS: Cascading Style Sheets | MDN
まとめ
以上がopen-wcで簡単なWeb Componentをつくってみた内容になります。
今回はDevelopingのみを扱いましたが、簡単なものだったので紹介できていないこともあります。興味があればぜひ公式のガイドを読んでみてください。
文章では伝わらなかったと思いますがビルドの時間がないというのはすごく快適です。ES Modulesが普及してきたからこそだと思いますが、Web Componentsの開発環境だけではなく他の開発環境でもこのスタイルが広まればいいなと思いました。
open-wcも今年できたばかりで日本語の情報がほとんどありませんがこの記事がみなさんの触れるきっかけになれば幸いです。