💣

マインスイーパーのWeb Compornentを作った

2023/01/16に公開

「Webサイトのこの部分にマインスイーパーを配置したいな」
というニーズに答えるため、マインスイーパーのWeb Compornentを作った。

こういうのを埋め込める。

MineSweeper

使い方

HTMLにこれを埋め込む。これだけ。

<script type="module">
    import { mine_sweeper } from 'https://unpkg.com/mine-sweeper-tag@latest/dist/mine-sweeper.es.js';
    customElements.define('mine-sweeper', mine_sweeper)
</script>
<mine-sweeper cols="10" bomb="10" beep />

技術解説

Web Compornents

こんな感じの独自タグを定義できる技術。
フレームワークを問わず利用できるので、たいへんポータビリティが高い。

<mine-sweeper cols="10" bomb="10" beep />

colsが盤面のサイズで、bombが爆弾の数、beepがクリア時のファンファーレを鳴らすかどうか。

Vue3

今回のマインスイーパーはVue3で作った。
以前Reactでマインスイーパーで作っていたのだけど、Vueは標準でWebCompornents出力に対応しているので移植した。

Composition APIとscript setupの記法はReactと考え方が似ているので移植は割りと簡単にできた。

Web Compornents化も以下の手順でできる。

  1. ***.ce.vueというファイル名でVueコンポーネントを定義する
    通常のVueコンポーネントとWebCompornentsで別々に作成するのは面倒で、通常のVueコンポーネントを作ってWebCompornentsでくるむ、というやり方をした。
  2. ***.ce.vueで定義したコンポーネントをdefineCustomElementして、それをexport

苦労した点

  • Web Compornentsに渡されるパラメータはTypeScriptの型チェックをすり抜ける
    TypeScriptの型チェックはあくまでコンパイル時のチェックだけなので、数字の属性を持つWebCompornentsに文字列を渡してもエラーにならない。これにハマってしまった。数字同士の足し算をしていたつもりが文字列同士の足し算として解釈され、微妙に座標がずれるなんとも分かりづらいバグが発生した。
  • 子コンポーネントのCSSが反映されない
    WebCompornentsが子供としてVueコンポーネントを持つ場合、子コンポーネントの中のCSSが反映されない。工夫してコードを書けば反映されるらしいが、これフレームワーク側でなんとかして欲しいよなぁ。

おわりに

マインスイーパーってひさしぶりに遊ぶと面白いですよね。

npmでも配布しています。

https://www.npmjs.com/package/mine-sweeper-tag

Discussion