◆ どれも結構便利
◆ この組み合わせで作るのもありかなって思う

たまには普段使わないものでも使おうかと思ってタイトルのもの使ってみました
作ったのはこれです

https://gitlab.com/nexpr/preact-htm-snowpack-webcomponents-example

作りたいものがあったわけじゃなくライブラリ使ってみるのが目的なので特別使いみちはないです

テキストと x,y 座標のセットを好きな数だけ作れて ボタン押すとそのセットを使って canvas にテキストを描画します
canvas のデータは画像ファイルとして保存できます

https://nexpr.gitlab.io/preact-htm-snowpack-webcomponents-example/

p-h-s-w-ex1

Preact

lit-html とは違うもので React でいいかなと考えてたら そういえば Preact がありました
React とほぼ同じ API で軽量なものです
それでいて hooks 系もありますし 特にこっちで困るところはなさそうです
コードも短く 中でどうやってるのかなと思ったら気軽にソースを見て確認できる程度です

https://github.com/preactjs/preact
https://preactjs.com/

hooks は内部にはありますが 独立したサブパッケージになっています
preact/hooks でインポートが必要です

WebComponents

WebComponents 自体は普段から使ってるもので特に何も新しさはないです

ただ lit-html にしても (P)React にしても アプリケーションの状態から DOM を構築して自動で管理してくれるものって DOM だけで表現できる範囲なら便利ですが単純な DOM 以外で管理されてる部分が入ると扱いづらくなります
わかりやすい例を挙げると Canvas 系です
地図表示などもそうです

その辺りは WebComponents にして CustomElements のプロパティを設定するだけでいいようにしておけばいいかなということで WebComponents を使うことにしました
setter をつけておいてプロパティが設定されたら内側の部分をライブラリの関数呼び出しなどで更新します

WebComponents にしても 更新されたプロパティが配列やオブジェクトだとその中で差分を見つけてどこを更新すればいいかを見つける面倒な部分は残ります
ただ 今回の Canvas の場合だと少し楽です
Canvas に描いたものを部分的に更新や削除はできません
全体を一から再作成するしかないので どこが変わったかを意識せず新しいものを作ればいいです

ところで lit-html や hyperhtml ならともかく React くらい大きければ地図などでも有名ライブラリであればラッパーコンポーネントがあると思います
しかしそれも あくまでサードパーティ製なのでどこまでメンテされるかの不安があるのですよね

htm

これが一番使いたかったライブラリです
(P)React で JSX や createElement をつかわなくてよくしてくれます
その代わりに lit-html や hyperhtml と同じテンプレートリテラルのタグ関数を利用します

https://github.com/developit/htm

以前 私も React は良いんだけど JSX が気に入らない ということで lit-html 風なテンプレートリテラルを使って createElement を呼び出すものを作ったことがありますが htm はそれのちゃんとしたものです

html`<div onclick=${fn}>${text}</div>`
html`<input value=${value} />`
html`<${App} />`

lit-html とは多少の書き方の違いはありますが lit-html と hyperhtml の違い程度のものです
たぶんこれでいけるんじゃない?くらいの感覚で書いたら思いの外エラーなく動きました

lit-html や hyperhtml と比べて嬉しいのはタグ名(コンポーネント)を可変にできるところです
その場合は閉じタグどうするんだろうと思ったら <//> を書くようです
以前の私が作ったときは同じものを必須にしてたような記憶があります
見た目的に揃ってないとわかりづらいのですが 二回書かされる手間を考えるとこっちのほうがいいのかも

lit-html / hyperhtml と比べたデメリットもあって JSX の XML 準拠なところに合わせてるようで input タグなどを self closing にしないといけないです
HTML 感覚で忘れると開始タグ扱いになって構造が壊れます
ソースを見た感じブラウザ依存してなくて ブラウザの機能で HTML パースせずに自力でパースしてました

snowpack

snowpack は ES Modules フレンドリーなバンドルツールです
以前ブログにも書いたのですが node_modules 内で別パッケージの依存があった場合 ブラウザでそれを解決できません
ブラウザの ESModules loader は相対か絶対の URL である必要があってパッケージ名だけ指定するのは無効です
例えば lit-element では lit-html を必要としていますが lit-element をエントリポイントを import しても lit-html の import のところで失敗します

結局 バンドラーなしで ES Modules だけでは使えず どうせバンドルするなら全部込みのを webpack で作ればいいやとなってしまいます
一応 Rollup を使えばライブラリごとにバンドルした JavaScript を作れるので 作っておけば使い回せるメリットはあります
ただそれも結構面倒なのでそこまで積極的にはしてませんでした

snowpack ではこれを楽にしてくれます

https://www.snowpack.dev/
https://github.com/pikapkg/snowpack

package.json の dependencies にあるものを Rollup でそれぞれをバンドルしてくれます
バンドルしたものは web_modules フォルダに配置されます

webpack みたいに色々パッケージ入れて設定してとか考えなくても 基本は npx で実行するだけでいいくらいの手軽さです

今回作ったものでは htm と preact を snowpack でバンドルしたものを使ってます
これらも含めてすべて ESModules で import しています
snowpack はライブラリを追加したときくらいしか実行しなくて良いので webpack に比べると開発が楽です
デバッグ中もコードの場所が見つけやすいですし

snowpack のドキュメントでも書かれていますが preact で hooks を使う場合はサブパッケージになっているので設定が必要になります
package.json にこれを追加してます

  "snowpack": {
"webDependencies": [
"htm",
"preact",
"preact/hooks"
]
}

preact/hooks があるので preact/hooks フォルダもバンドルされます
出力はこうなります

└─web_modules
│ htm.js
│ import-map.json
│ preact.js

└─preact
hooks.js

ところで htm には preact を含んだ standalone もありますが せっかく snowpack を使うので今回は preact もインストールして snowpack しました