StencilでかんたんにWeb Componentsを実装する
UI開発者 古川Stencilは、Ionic Frameworkチームが開発したWeb Componentsコンパイラです。
開発環境にTypeScript、JSX、VirtualDOM、データバインディング、非同期レンダリングなどのWeb開発技術を網羅しており、ビルド後はWeb標準に準拠したWeb Componentsのソースコードを生成してくれます。
今回はStencilの導入方法を紹介します。
Stencilのインストール
適当なディレクトリで以下のコマンドを実行しましょう。
npm init stencil
そうするとStencilが提供するスターターの選択肢がコマンドラインに表示されます(コマンドを実行するにはnpm v6以上が必要です)。
? Pick a starter » - Use arrow-keys. Return to submit.
ionic-pwa Everything you need to build fast, production ready PWAs
app Minimal starter for building a Stencil app or website
> component Collection of web components that can be used anywhere
今回はcomponent
を選択します。
component
はStencil Component Starterの環境をセットアップしてくれます。Stencil Component StarterはStencilでWeb Componentsを開発するスタンドアロン型の開発環境です。
ほかにもStencilでは、PWA Toolkitが導入済のスターターや、アプリケーション構築に必要な環境が整っているStencil App Starterを提供しています。
component
を選択すると、続いてコマンドライン上でアプリの名前を要求されます。
√ Pick a starter » component
? Project name » my-components
任意の名前を設定するとフォルダが生成されるため、生成されたディレクトリに移動しnpm start
を実行します。
cd my-components
npm install
npm start
以下のキャプチャのように、ブラウザでローカルサーバーが立ち上がったら成功です。
コンポーネントの追加
Stencil Component Starterはローカルサーバーやテストの設定ファイル、およびサンプルのコンポーネントを含む開発環境を提供します。インストールしたばかりのスターターは開発環境の設定ファイルの他に、コンポーネントなどのリソースを格納するsrc
ディレクトリが存在します。ローカルサーバーを立てたりビルドを実行すると、ドキュメントルートにwww
ディレクトリとdist
ディレクトリが生成されます。www
ディレクトリにはWebサイトでコンポーネントを表示するためのリソースが、dist
ディレクトリには再利用可能なライブラリとしてコンポーネントを利用するためのスクリプトがそれぞれ格納されます。
以下はビルド後のStencil Component Starterのファイル構成のキャプチャです。
StencilのコンポーネントはJSXとTypeScriptで作成するため、Web Componentsを追加する場合はsrc/components
ディレクトリに.tsx
ファイルを追加します。
今回はsrc/components
配下にmy-custom-button
という名前のディレクトリを作成し、my-custom-button.tsx
を格納しました。
my-custom-button.tsx
の内容は以下です。
import { Component, Prop, State, h } from '@stencil/core';
// @Component: コンポーネントの宣言
@Component({
tag: 'my-custom-button'
})
export class MyCustomButtonComponent {
// @Prop(): プロパティや属性の宣言
@Prop({ mutable: true }) text: string = 'ボタン';
// @State(): コンポーネントの内部状態の定義
@State() checked: boolean;
// @Event(): コンポーネントが発行するDOMイベント
toggleChecked() {
this.checked = !this.checked;
}
// render():
// 実行時にDOMにレンダリングされるコンポーネントを返す関数
render() {
return (
<button onClick={() => this.toggleChecked()}
class={(this.checked && "checked")}>
{this.text}
</button>
);
}
}
上記で記載したほかにも、Stencilではデコレーターやライフサイクルフックを提供しています。詳細はドキュメントを参照してください。
コンポーネントを登録したら、src/index.html
に<my-custom-button>
要素を追記します。
<my-custom-button text="ボタンテキスト"></my-custom-button>
ここまでの表示は以下のキャプチャのようになります。
スタイルを適用する
CSSを追加するには@Components
にstyleUrls
プロパティを追加し、外部ファイルとしてCSSファイルを作成します。Shadow DOMはデフォルトで有効になっていないため、利用したい場合は@Components
にshadow:true
を設定します。
@Component({
tag: 'my-custom-button',
styleUrl: 'my-custom-button.css',
shadow: true
})
今回はsrc/components/my-custom-button
ディレクトリにmy-custom-button.css
を作成し、以下のようなCSSを記載しました。
button {
background-color: skyblue;
border-radius: 4px;
cursor: pointer;
display:inline-block;
padding: 5px 10px;
text-align: center;
}
スタイルを付与した状態は以下です。
テストする
Stencilはデフォルトで単体テストとE2Eテストを実行できます。どちらのテストもJestが採用されており、E2EテストではPuppeteerが利用されています。
テストの実行にはsrc
配下にテストファイルを作成します。
今回はsrc/components/my-custom-button
配下にmy-custom-button.e2e.tsx
というファイルを作成し、作成したコンポーネントが存在するかをチェックするテストを実行してみました。
import { newE2EPage } from '@stencil/core/testing';
describe('my-custom-button', () => {
it('renders', async () => {
const page = await newE2EPage();
await page.setContent('<my-custom-button></my-custom-button>');
const element = await page.find('my-custom-button');
expect(element).not.toBeNull();
});
});
コマンドは以下のコマンドを実行します。
npm run test
実行結果は以下のキャプチャです。
ビルドする
Stencilではコンポーネントの使用方法に応じて4種類のビルド方法を設定できます。
dist
:配布用www
:ウェブサイト用docs-readme
:マークダウン形式のドキュメントファイルdocs-json
:JSON形式のドキュメントデータ
stencil.config.ts
という名前の設定ファイルがスターターのドキュメントルートにあるので、そのファイルのoutputTargets
を上記のいずれかに設定します。デフォルトではwww
です。
import { Config } from '@stencil/core';
export const config: Config = {
outputTargets: [
{
type: 'dist'
},
{
type: 'www'
}
]
};
設定を行ったら、以下のコマンドを実行します。
npm run build
今回はdocs-readme
を設定し、ビルドしてマークダウン形式のドキュメントを出力したいと思います。コマンドを実行すると、src/components/my-custom-button
配下にreadme.md
という名前のマークダウンファイルが生成されました。
内容は以下です。
# my-custom-button
<!-- Auto Generated Below -->
## Properties
| Property | Attribute | Description | Type | Default |
| -------- | --------- | ----------- | -------- | ---------- |
| `text` | `text` | | `string` | `'ボタン'` |
----------------------------------------------
*Built with [StencilJS](https://stenciljs.com/)*
まとめ
Stencilがサポートするブラウザは以下です:
- Chrome 60+
- Safari 10.1+
- Firefox 63+
- Edge 16+
- IE 11+
EdgeやIEではWeb Componentsの一部機能をポリフィルで提供しますが、モダンブラウザと呼ばれる環境で動作するため、実案件でも十分導入が可能そうです。
インストールするだけで開発からテスト、ビルドまで柔軟に対応してくれるため、Stencilは非常に便利なWeb Componentsコンパイラだと感じました。要件が合えばぜひ実案件でも取り入れたいです。