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

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

# 題材

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

![https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_124296_d81ec72e-226b-fc18-cc07-ddbd0c7264dd.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124296/f83535d0-e8c0-a7f3-1363-8aa457ca3267.png)

# 扱う技術

## WebComponents

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

## LitElement

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

## TypeScript と Webpack

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

| ![スクリーンショット 2020-01-14 21.50.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124296/6ea2449d-c79e-138f-086b-74e4838becb7.png) | ![スクリーンショット 2020-01-14 21.51.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124296/1baa0ec0-3c56-dffe-9319-6bb0372a26db.png) |
|:-----:|:-----:|

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

# 実装

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

````js: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` で指定した文字列がタグ名となる。

````js
@customElement('simple-greeting')
```

````html
<simple-greeting name="Everyone"></simple-greeting>
````

# ビルド環境

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

````js:webpack.config.js
module: {
  rules: [
    {
      test: /\.tsx?$/,
      use: [
        {
          loader: 'ts-loader',
          options: {
            configFile: 'tsconfig.json'
          }
        }
      ],
      exclude: /node_modules/
    }
  ]
}
````

````js: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"
    }
  ]
}
````

# 結果

```html
<cc-monte-carlo></cc-monte-carlo>
```

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

![ScreenRecorderProject30 2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/124296/40923a9a-8e56-e52a-d14e-701155ca8f3b.gif)

リポジトリ： 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

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

https://github.com/abenz1267/LitElement-TypeScript-and-Webpack-Example

## lit-element-form-example

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

https://github.com/marcushellberg/lit-element-form-example

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

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

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