LitElement x TypeScript x WebpackでWebComponentsベースのアプリを作る


先日公開された Web Developer Roadmap 2020 で新たに追加された WebComponents の勉強も兼ねて
LitElement x TypeScript x Webpack で WebComponentsベースのアプリを作ることにした。

題材

どうせなら使えるものがよいと思い、
モンテカルロ法(ルーレットの必勝法みたいなやつ)の計算をしてくれるアプリを題材にした。

扱う技術

WebComponents

簡単に言うとオリジナルのHTMLタグを作るための技術の総称。
まだ賛否はあるものの、非常に再利用性の高いコンポーネントを作れること
Web標準の技術であることが特徴。

LitElement

Webコンポーネントを簡単に作るためのライブラリ。
Googleが推進しているPolymer Projectの一つ。

TypeScript と Webpack

静的型付き言語とバンドルツール。
いずれもWeb Developer Roadmapでは学習を推奨されている。

引用:https://github.com/kamranahmedse/developer-roadmap

実装

基本的にはTypeScriptの記法で、LitElementを継承したクラスを作れば良い。

simple-greeting.ts
import { LitElement, html, property, customElement } from 'lit-element';

@customElement('simple-greeting')
export class SimpleGreeting extends LitElement {
  @property() name = 'World';

  render() {
    return html`<p>Hello, ${this.name}!</p>`;
  }
}

customElement で指定した文字列がタグ名となる。

@customElement('simple-greeting')
<simple-greeting name="Everyone"></simple-greeting>

ビルド環境

素直に ts-loader を通せばコンパイルすることもできた。
ただしLitElementはES5用ビルドがされていないため(後述)
class構文などに対応していない IE11 などに対応するには
ここからさらにbabelを通す必要があると思われる。

webpack.config.js
module: {
  rules: [
    {
      test: /\.tsx?$/,
      use: [
        {
          loader: 'ts-loader',
          options: {
            configFile: 'tsconfig.json'
          }
        }
      ],
      exclude: /node_modules/
    }
  ]
}
tsconfig.json
{
  "compilerOptions": {
    "module": "es6",
    "target": "es6",
    "sourceMap": true,
    "experimentalDecorators": true,
    "moduleResolution": "node"
  },
  "exclude": ["node_modules"],
  "plugins": [
    {
      "name": "typescript-tslint-plugin",
      "alwaysShowRuleFailuresAsWarnings": true,
      "configFile": "./tslint.json"
    },
    {
      "name": "typescript-lit-html-plugin"
    }
  ]
}

結果

<cc-monte-carlo></cc-monte-carlo>

というタグを設置すると
モンテカルロ法の計算ができるアプリが起動されるようになった。

リポジトリ: https://github.com/cc822jp/montecarlo-simulator

特徴

WebComponentsならでは特徴を述べると、
Shadow DOMになっているので外からの影響を全く受けることがない
(iframeタグを埋め込んでいるのと同じイメージ)

つまり外から document.querySelector でDOM操作される心配もないし
クラス名の衝突で不要なスタイルが当たることもない。

「いいねボタン」など、あらゆるWebサイトで使われる(再利用性が求められる)コンポーネントは
WebComponentsで作ることで安全にHTMLとJavaScript, CSSが一体となったタグを提供することができる。

参考にしたもの

参考になった LitElement x TypeScript x Webpack のボイラーテンプレートがいくつかあった。

LitElement-TypeScript-and-Webpack-Example

検索すると最初に出てきたもの。

lit-element-form-example

Vaadinのコミッターが作ったもの。
いま思えばこっちを主に参考にすればよかった..。

余談: LitElementはES5用のビルドをしていない

LitElementはES5用にビルドされていない。(普通のライブラリはしている)
issueを追ってみると、ES5用にビルドするとパフォーマンスが大幅に低下するし
肥大化、バグの温床にもなるという説明があった。

最後は大御所コミッターが進撃のcloseで終了していた。
https://github.com/Polymer/lit-element/issues/302