- Web Components は React コンポーネントのブラウザ版のように見えるが、実際には 既存の HTML を中心に機能を付け足すモデル により近い
- 中核となる違いは JavaScript 実行前のレンダリング にある。空のカスタム要素にデータを渡すより、意味のある HTML をカスタム要素で包む形のほうが自然
- HTML Web Component は既存のマークアップを拡張するものであり、内容と機能を JavaScript に全面的に任せる空要素は JavaScript Web Component に近い
- React 的なコンポーネント化が置き換えに慣れているなら、Web Components はコンテンツを保ったまま機能を加える 拡張(augmentation) の発想を求める
- Web プラットフォームでは、HTML5、
fetch、TypeScript に関する流れのように、優れたアイデアは既存技術を押しのけるより 補強される形 で長く生き残る傾向がある
Web Components と React コンポーネントは性質が異なる
- “Web components” という名前は、Web プラットフォームにおける React コンポーネントの対応物のように聞こえるかもしれない
- React の JSX は
<MyComponent> という形を使い、Web Components は <my-component> という形を使える
- しかし React コンポーネントを作るように Web Components を作ると、簡単に行き詰まることがある
- 両者は 設計で優先される機能と使い方 が異なる
- 片方をもう片方のように使おうとすると、それぞれの技術の自然な方向性と衝突する
HTML Web Components は置き換えより拡張に向いている
- 一般的な React コンポーネントは、空のコンポーネントに属性でデータを渡し、JavaScript が全内容をレンダリングする形になりうる
<UserAvatar
src="https://example.com/path/to/img.jpg"
alt="..."
/>
- Web Components も見た目だけなら同じ書き方ができる
<user-avatar
src="https://example.com/path/to/img.jpg"
alt="..."
></user-avatar>
- しかし Web Components 固有の力は、JavaScript より前にレンダリング できる点にある
- React コンポーネントはこの方法では動作できない
- そのため、空の「シェルコンポーネント」よりも、中核コンテンツを HTML で構成してからカスタム要素で包み、機能を加える構成のほうが適している
<user-avatar>
<img src="https://example.com/path/to/img.jpg" alt="..." />
</user-avatar>
- Jeremy の “HTML web components” という区分は、カスタム要素が既存マークアップを拡張するかどうかに焦点を当てている
- カスタム要素が空であれば、HTML Web Component ではない
- 既存マークアップを包んで拡張するなら、HTML Web Component に近い
- “JavaScript web component” は、空要素の内容と機能が JavaScript に全面的に依存する形を指す
<user-avatar
src="https://example.com/path/to/img.jpg"
alt="..."
></user-avatar>
- この形は JavaScript がなければ最終ユーザーにとって意味を持たない
- それに対して HTML Web Component は、JavaScript がなくても 意味とコンテンツ が残り、JavaScript があればその上に機能が補強される
<user-avatar>
<img src="https://example.com/path/to/img.jpg" alt="..." />
</user-avatar>
Web では拡張型のアプローチが長く生き残る
- Web で拡張的アプローチが適している理由は、Web の性質が 回復力のある段階的強化 を促し、Web のような大きな対象を繰り返し変えていくのに向いているから
- Web 周辺のフレームワークやライブラリの優れたアイデアは、プラットフォームに吸収されるとしても、既存技術を丸ごと置き換えるより補強する形で入ることが多い
- XHTML は HTML4 を置き換えようとしたが、HTML5 は HTML4 を補強しようとし、HTML5 が勝った
- ネットワーキングライブラリは
XMLHttpRequest を置き換えようとし、優れたアイデアは最終的に fetch 標準へ移された
fetch は現在、ブラウザ外のさまざまな環境にも存在する
- Sass や jQuery の優れたアイデアもブラウザへ移された
- TypeScript の優れたアイデア も、既存技術を置き換えるのではなく補強する形でブラウザに取り込まれつつある
- Web Components も、React のコンポーネントモデルがブラウザへ移っていく流れのように見えるかもしれないが、Web がすでに動いている方法を置き換えるのではなく 補強 する側に近い
- 長く持続する技術アプローチを望むなら、置き換えより 拡張と改善 を選ぶほうが Web の方向性に合っている
1件のコメント
Hacker News の意見
この記事では
user-avatarが実際に何をしてくれるのか、あるいは何を提供するのか説明してくれると期待していたが、結局出てこなかった単にスタイルが入っているだけなら、なぜ普通に CSS クラスを使ってはいけないのか分からないし、
user-avatarが毎回内部にimgタグを入れさせるより、src属性を受け取るほうがずっと自然に見えるVue/React/Angular が HTML を「置き換え」ようとしているというよりは、HTML/CSS/JS の上に積み上げている側に近く、キャンバスですべてをレンダリングするような形だったなら、その主張にはもっと説得力があったと思う
Web Components は最初に発表されたとき期待していたが、標準搭載の機能があまりに不足していて、フレームワークのように Web アプリを作るうえで実質的に助けになるという感覚が弱い
大規模フレームワークの代替、特に htmlx のようなものは jQuery 系に少し構文糖を載せた程度に見えるので、Web アプリ構築には大きな後退のように感じる
「Web アプリ」が Google Sheets のようなものを指すなら同意するが、この反 React の流れは、そうした事例よりも、デフォルトのようにフレームワークを敷いて最初から作る慣行を批判しているように見える
実際に必要なのが「上に少し載せるインタラクション」だけという Web サイトも多い
核心的な利点はプログレッシブエンハンスメントで、
imgタグには基本動作があるので、基本レンダリングに頼り、必要な部分だけ Web Components で「補強」すればよいdetails-utilsコンポーネントは組み込み HTML のdetailコンポーネントの動作を補強する何らかの理由で JavaScript が無効になっていても
detailコンポーネントは本来どおり動作し、JavaScript が有効だったりダウンロードが完了したりすると、外側をクリックしたときに折りたたまれる機能のような強化された動作を得られるこの方式で再利用可能な部分が、まさにそうした動作の補強である
11ty 作者によるこの Web Component を見て記事の要旨が理解できたし、最初に Web Components を見たとき「結局 JavaScript が必要で、なければ動かないじゃないか」と感じた部分は、Rich Harris の記事でも同じ論点として出ていた: https://dev.to/richharris/why-i-don-t-use-web-components-2ci...
htmx は主に、JavaScript の記述を避けながら、サーバーレンダリング HTML のパラダイムをページ全体のリロードではなく部分的なページ更新へ拡張する方式である
「HTML Web Components」というアイデアをもっと見るなら、この記事たちも読む価値がある
https://meyerweb.com/eric/thoughts/2023/11/01/blinded-by-the... - “So there you have it: a few thousand words on my journey through coming to understand and work with these fully-Light-DOM web components, otherwise known as custom elements. Now all they need is a catchy name, so we can draw more people to the Light Side of the Web.”
https://adactio.com/journal/20618 ではそれらしい名前を提案している
書くのが面倒なので、結局 Lit のような組み込みフレームワーク上の軽量フレームワークが必要になるが、Lit は Preact よりも大きい
そのうえ状態管理やルーティングのような実際の問題は解決しないので、さらに持ち込む必要が出てくる可能性が高い
再利用コンポーネントは得られるかもしれないが、React を使っている場所で内部的に Vue を使う Web Component を持ってきて使うのかと考えると、あまり筋が通らない
Web の美しさと優雅さは宣言的な構造から来ており、そのおかげで観察可能性と変更可能性が生まれた
Shadow DOM は、より高いカプセル化の壁と確実性を築こうとする企業的な欲求のように感じられ、個人的に共有する目標ではなかった
この記事は Light DOM の作業がどのように合成され得るかを示している
Web Components やカスタム要素は、内部 DOM を自ら修正し、子要素を移動し、新しいコンテンツを作れるべきだとずっと考えていた
たとえばページやフレームワークがアイコンを入れ、ユーザーアバター要素が名前や装飾要素を挿入することもできる
ただし Light DOM/HTML Web Components で一つ気になるのは、Shadow DOM が一部の性能上の利点をもたらす点である
CSS セレクタが探索すべき要素数を減らせるという点は開発者として頭に思い描けるし、その利点も何らかの形で使えるとよい
カスタム要素と Web Components をより軽量に捉えるアプローチは本当にうれしく、リンクにも感謝する
「JavaScript の前にレンダリングできる。React コンポーネントでは絶対にできない」という表現は断定しにくく、サーバーサイドレンダリングであればクライアント側 JavaScript より前にレンダリングされ得る
例は筆者の主張を示すには単純すぎると思う
状態変化を扱う Web Component のほうが比較対象として適切で、論証もより良くなったはず
Hydration の解決策はあるが、たいていはより悪く、意外なトレードオフがあり、合成可能性を損なうことが多い
imgタグをラップする例だけを見ると利点があまり伝わらず、共通要素をまとめて再利用することはできるだろうが、インタラクションを行うには依然として JavaScript が必要例の画像代替テキストも最近はローカライズのため通常は動的なので、JavaScript がないとコンテンツが欠落する可能性がある
Web Components についてようやく感覚がつかめた気がする: https://github.com/kennyfrc/cami.js
“No Build Steps, No Client-Side Router, No JSX, No Shadow DOM. We want you to build an MPA, with mainly HTML/CSS, and return HTML responses instead of JSON. Then add interactivity as needed.”
“Declarative templates with lit-html. Supports event handling, attribute binding, composability, caching, and expressions.”
個人的には、XState に着想を得たステートマシンを内蔵した、React のクラスコンポーネント風のクラスが好き
https://github.com/codewithkyle/supercomponent/blob/master/s...
方向性はかなり似て見えるし、HTMX のほうがコミュニティは大きいかもしれない
使ったことがあるなら、どの点が足りなかったのか気になる
「web components」は単一のものではなく、「a web component」を作るわけでもない
「Web Components」は 3 つを束ねた Web Components API の名前
実際に作るのはカスタム要素で、そこに Shadow DOM を使うことも、HTML テンプレートを使うこともできる
3 つの中で最も重要なのはカスタム要素
中核となる考え方は「HTML 要素をさらに作る」ということなので、どの属性や JavaScript API をサポートするかはすべて自分で決めればよい
ページに置き、やり取りし、イベントを購読する方法も他の HTML 要素とまったく同じ
「昔ながらの方法」で Web ページを書けるなら、カスタム要素の使い方はすでに知っており、宣言方法だけ学べばよい
最近、ビルド環境なしで Web Components を触り始めた
npm、bun、webpack のようなものもなく、依存関係もなく、TypeScript で書いている
IntelliJ が JavaScript に自動コンパイルしてくれ、ブラウザビューは開発中のリアルタイム更新のために小さな変更検知ハンドラーを注入する
今のところ問題はない
Web Components の足かせになっているのは HTML Modules のように見える
Web コンポーネントを取り込むために
.jsファイルではなく.htmlファイルへリンクできるとよいが、現状ではテンプレートやもう少し複雑なものを使うには.innerHtml = \...`` のような不格好な注入をしなければならない問題になると思っていたが、IDE はテンプレート文字列をかなりうまく解析してくれる
そしてそれが Web Components を妨げている唯一の理由でもない
「Reactは強化ではなく置き換えだ」という主張には、あまり納得できない
結局ReactもHTML要素をレンダリングし、JavaScriptのイベントハンドラを付ける
imgをReactコンポーネントで包んだからといってimgの機能を奪うわけではなく、その上に足すもの、つまり強化だ筆者は別のReactコードベースで働いていたのかもしれないが、私の経験上、私たちは理由がなければブラウザ組み込み機能をそのまま使う
運が良かっただけかもしれない
要点は、「HTML Web Component」という方式がReactと違い、レンダリングを開始するのにJavaScriptに依存しないことにある
Reactはブラウザのレンダリング基準では「ページ読み込み → コンポーネント読み込み」で、Web Componentは「ページ読み込み → 基本レンダリング → コンポーネント読み込み」に近い
JavaScriptをオフにしている人でもWebコンポーネントでは何かを見ることができるが、Reactでは何も見られない場合があり、JavaScriptがあればより発展したレンダリング状態へ進める
例えば
onchangeを要素に割り当てると、Reactはchangeイベントではなくinputイベントに近いものを渡す実際にはどちらでもなく、
changeよりinputに近い合成イベントを渡す本当に
changeが欲しいなら、要素参照を使い、effectの中でハンドラを直接付ける必要があるReactでサーバーからHTMLを返すなら、
imgをReactコンポーネントで包むことは既存要素を強化することだと言えるしかし全体をクライアント側でレンダリングするなら、その
imgは結局Reactコンポーネントから切り離せない経験上Reactはページ構造全体を上から下まで任せると素晴らしいが、サーバーサイドレンダリングのようなことをしながら既存構造の中に差し込もうとすると難しくなり得る
長く続く方法を探すなら、置き換えより強化と改善を選べ、という結論は私の経験にも合っている
この哲学のおかげで、私のWebプロジェクトは保守と依存関係を最小限に抑えながら長く続いてきた
Webコンポーネントは1つのことをするべきで、JavaScriptフレームワークはエコシステム全体に近い
複数の入力を受け取れる動画プレーヤーのWebコンポーネントを作ったことがあり、最も複雑な入力はTorrentファイルだった
StencilJS [0]でVue/Reactへ移植することもできたが、なくても十分に使えた
awesomePlayer.jsからエクスポートしたクラスと一緒に該当タグを置くだけで、Torrentを再生するコピー&ペースト用のHTML5動画プレーヤーができる可能なら既存のHTML要素をまねることも強く勧める
例えば
srcを使ったのはvideoがそうしているからで、そうすれば利用側はドキュメントを探し回らなくてもやり取りできる[0] https://stenciljs.com/
フロントエンドフレームワークのコンポーネントが完全に置き換え用で、合成可能ではないという点には同意しにくい
表面的にはそう見えるかもしれないが、私のコンポーネントではスロットを多用しており、実装も簡単で自然に動作する
一方でWeb Componentsはたいてい、何かエディタのようなものを作るために膨大なコードを挿入する形でデモされる
Web Componentsでスロットを使うのは苦痛で、ノードを手作業でたくさん付け、テンプレートを文字列として扱い、少し複雑なことをしようとすると
slotchangeイベントまで聞かなければならなかった本質的にはDOM APIを使っているわけで、そのAPIがひどくなかったならReactのようなフロントエンドフレームワークへ移ることもなかったはずだ
XHTMLがHTMLを強化しなかったから失敗した、という脇道の主張にも同意しない
私の考えでは、アプリケーションが完全に妥当でなければならず、その検証をクライアント/ブラウザに任せたために失敗した
本物のXHTMLを使っていたなら、マークアップの小さなミス1つでページが壊れただろうし、そのため皆が将来への備えとしてXHTMLを検証してはいたが、
pタグが1つ正しく閉じられていないという理由で事業そのものが壊れるリスクを負う企業はなかったはずだ