Web Componentsは問題ない
(nolanlawson.com)- Web Componentsをめぐる議論は、最高性能とプラットフォーム標準のどちらか一方を選ぶ問題ではなく、すべてのJavaScriptフレームワークを置き換えるべきだという前提からして行き過ぎている
- Custom ElementsはDOMをインターフェースとして使うためオーバーヘッドがあるが、実際のプロダクトでは性能だけでなく保守性・セキュリティ・使いやすさ・アクセシビリティもあわせて判断すべき
- フレームワークのWeb Components対応コストは、一部の単純なチェックで吸収できる可能性があり、標準機能だからといってすべてのフレームワークが必ず採用すべきというわけではない
- Web Componentsにはサーバーサイドレンダリング(SSR)、アクセシビリティ、一部の相互運用性に弱点があり、React・Solid・Svelteのほうが適している状況は残っている
- Salesforceのように、クライアントレンダリングアプリ、コンポーネントマーケットプレイス、長期的な後方互換性が重要な環境では、Web Componentsが現実的な選択肢になり得る
議論の出発点と筆者の立場
- 最近の議論は、Ryan Carniatoの「Web Components Are Not the Future」とCory LaViskaの「Web Components Are Not the Future — They’re the Present」から続いている
- 争点は相手陣営を攻撃することではなく、異なる制約を持つ開発者たちが共通点を見つけられるかに近い
- Ryan Carniatoは、Solidと
js-framework-benchmarkに表れる性能およびフレームワーク設計の取り組みで高く評価されている - Web Componentsにも、フレームワーク実装、コンポーネント制作、Web Components Community Group、Accessibility Object Modelグループ、shadow DOM・custom elements・アクセシビリティ作業につながる実際の利用領域がある
性能:DOMコストは事実だが、それがすべてではない
- Web Componentsの基本的な弱点は、Custom Elementsベースである点
- すべてのインターフェースがDOMを経由する必要があるため、性能オーバーヘッドが発生する
- 絶対的に最速のフレームワークを目指すならDOMノードをできるだけ減らすべきであり、この基準ではWeb Componentsは不利になる
- ただし性能はソフトウェア開発における唯一の基準ではない
- 保守性、セキュリティ、使いやすさ、アクセシビリティもあわせて考慮すべき
aria-*属性をレンダリングしなければDOMレンダリングは少し速くなるかもしれないが、アクセシブルなインターフェースには必要な場合があるforループが.forEach()より速い、あるいはvarがconst/letより速いといったマイクロ最適化は、通常は受け入れる価値が大きくない
- DOMノードの最小化はvirtualizationの中核的なアイデア
- 最速の選択でなくても、より単純なアプローチだけで十分な場合がある
components as elementsも最適ではないが、常に最適であることを目標にする必要はない
- 異なるフレームワークで作られたcustom elementsを一緒に使う方法も、実務では意味がある
- Framework AからFramework Bへ段階的に移行する必要がある場合がある
- 複数のマイクロフロントエンドを組み合わせる必要がある場合もある
- 最速のインターフェースではないが、必要なトレードオフになり得る
- 実際のWeb性能では、layout thrashing、ネットワークwaterfall、不要な再レンダリングのような低コストで改善できる点のほうが一般的
js-framework-benchmarkのような競争はフレームワーク作者にとって興味深いが、一般的なプロダクト状況で常に決定的とは限らない- リソースが限られた環境で1ミリ秒単位が重要なら、Web Componentsを捨てる選択も妥当
フレームワーク対応コストと選択肢
- Web Components対応がフレームワーク作者にとって過度に大きなコストだという主張には同意しない
- propsとattributesの検出は
prop in elementチェックで処理できる - Web Componentsを出力することは苦痛になり得るが、すべてのフレームワークが必ず行うべき作業ではない
- Vue 2は別のweb component wrapper libraryを使っており、RemountはReactチームからの入力なしに存在している
- propsとattributesの検出は
- フレームワークは、2011年以降にWebプラットフォームへ追加された機能を無視しても、優れたものにできる
- jQuery v1はいまも多くのWebサイトで動作している
- ブラウザ性能チームが過去のWeb開発者のパターンを最適化することで、古いコードが新しいブラウザでより速くなることもある
- 最新のWebプラットフォーム機能を取り入れる選択には、新たな考慮事項が伴う
Symbol、Proxy、Promisesのような機能も同じ範疇にある- Webの後方互換性のおかげで、書いたコードは10年後も動き続ける可能性がある
- Web Componentsに関心がない、または対応したくないフレームワークも十分にあり得る
- UI全体をWeb Componentsで作ることもできる
- HTML web componentsを一部だけ混ぜることもできる
- まったく使わない選択も可能
- 「no web components」フレームワークもファンを獲得できる
標準は基準点であって義務ではない
- ある機能が標準になると、開発者はそれを基本的な比較対象として意識するようになる
- コンポーネント作者は、自分の
<slot>がネイティブの<slot>のように振る舞うべきかを決める必要がある IntersectionObserverや<img loading="lazy">を使うのか、独自の抽象化を作るのかも選ぶ必要がある
- コンポーネント作者は、自分の
- 標準は共通の参照点と共有語彙を提供する
- 異なるアプローチを比較・対照するための基準が生まれる
- しかし標準だからという理由だけで必ず使うべきというわけではない
- Webには使わなくてもよい機能と古いAPIが共存して残っている
document.domain、with、<frame>のようなdeprecated APIも依然としてサポートされている- Webプラットフォームの機能は、選んで使うことも捨てることもできる
Web Componentsが合う場所と合わない場所
- Web Componentsは多くのことをうまくこなすが、すべてのJavaScriptフレームワークを置き換える道具ではない
- 弱点としてはサーバーサイドレンダリング(SSR)、アクセシビリティ、一部の相互運用性がある
- React、Solid、Svelteのようなフレームワークのほうが輝く状況も、依然として多い
- 「Web Componentsは未来ではない」という言葉は、特定の開発者やプロジェクトには当てはまる場合がある
- 議論の根本には、異なる人々が異なる制約の下で異なるものを作っているという事実がある
Salesforceの事例と実務的判断
- Salesforceは、Web Componentsがうまく合う可能性のある環境を示している
- クライアントレンダリングアプリを作っている
- 独自のコンポーネントマーケットプレイスがある
- 厳格な後方互換性の保証が必要
- サポート期間は数年、場合によっては数十年単位で測られる
- こうした条件でなければ、UI全体をWeb Components、shadow DOM、関連する全構成で作る必要はないかもしれない
- Webプラットフォームには、WebGL、Wasm、Service Workersのような多様な機能で作られたゲーム、アートプロジェクト、エンタープライズSaaSアプリが共存している
- プラットフォームに新機能が追加されると、創造性が制限されるというより、以前は想像できなかった方法で表現する機会が増える
- あわせて読む記事として、Lea Verouの記事とBaldur Bjarnasonの記事もある
1件のコメント
Hacker Newsの意見
参照されていた記事「Web Components Are Not the Future」を理解しようとしたが、あまり説得力のある根拠はなかった
今のフロントエンドフレームワークの状態はひどく、複雑なフレームワークやドキュメントを読む前提でしか理解できない魔法(
useState、createSignalなど)は学びたくないWeb Components から始めると直感的に感じられるし、Shadow DOM の分離のような他にはない能力もある
React 時代から残すべきものは JSX だけだと考えていて、Web Components を JSX と一緒に使うライブラリを作った: https://webjsx.org
フレームワーク自体を学びたくないのか、学ぶ必要がないほど魔法のように感じられるものを望んでいるのか、ドキュメントを読みたいのか読みたくないのかが曖昧
主に Vue を使ってきたが、SPA エコシステムは複雑である一方、複雑な状態を持つクライアントアプリを管理するために他にどんな仕組みがあり得るのかもよく分からない
jQuery の基本パターンは要素を選んで変更する副作用中心のもので、React や Vue.js は UI の状態がデータによって決まるコンポーネントを作れるようにしてくれる
データが変わると最小限の DOM 変更で更新され、このやり方は UI ウィジェットを場所ごとにずっと読みやすく保守しやすいものにする
今日の Web サイトや Web ベースのデスクトップアプリは 20 年前よりはるかに複雑なので、単純な UI だけを作るのでなければ、状態管理という観点での革新が重要になる
useStateが内部でどう動くかを知る必要はなく、使い方はかなり直感的逆に提示されているライブラリは、出発点からしてより複雑なメンタルモデルを要求しているように見える
フレームワークの詳細を深く理解するのが理想ではあるが、React は内部モデルをほとんど知らなくてもかなり洗練されたアプリを作れるようにしてきたという点で成功していた
C# ベータ時代から、HTML/JS/CSS の初期からやってきた開発者だからという面もあるが、すぐに理解できた
古くて複雑な中核インフラ管理ポータルを置き換えるときに Angular を選び、安定していて高速で見た目も良く、みんな満足していた
「学習曲線が急だ」という話は、JavaScript と少しの React だけを知って業界に入ってきた開発者から主に出てくるようで、経験がもっとあればすぐ習得できる
useStateの内部が気になる開発者なら、数秒で論理的で正しい答えにたどり着けるはず複雑でも魔法でもなく、React フック風の最小実装なら数百行で可能
基本的な
useStateとrunFunctionComponentの実装は、大学の計算機科学 3 学期目の課題の大半より簡単これが魔法の基準なら、周囲は朝食中にも新しい Eldritch Invocation を生み出すレベル 20 の Warlock だらけということになる
この論争ですれ違う理由の一つは、最適化しようとしている対象が違うからだと思う
VC 投資を受けたスタートアップで、素早く動いて継続的に保守する中核製品を作るなら、フレームワークはうまく合うかもしれない
だが学術研究室では、すでに作ったアプリを保守するための資金はあまりなく、助成金が新しいプロジェクトへ移った後も動き続けなければならない
Vue アプリをWeb Componentsに書き直す作業をほぼ終えたが、依存関係が腐って更新不能な状態だった
以前は依存関係地獄を直すのに時間を使っていたし、この先もそうなっていただろうが、Web Components を試してみたらすぐに気に入り、移行した
依存関係は約 15 個から約 1 個(d3js)に減り、後悔はない
以前のアプリ https://bam.iobio.io/、新しいアプリ https://bam2.iobio.io/
誰もフレームワークを常に最新バージョンへ上げろと強制しているわけではないので、使っていた Vue のバージョンにそのままとどまってもよかったはず
特別な理由がないなら、最後まで同じバージョンを使っても問題なかったかもしれない
そもそもその用途に Vue が不要だったとか、依存関係を減らしたのが悪い選択だという意味ではないが、Vue が気に入っているなら最新版にとどまらなければならない強制力はなさそう
Vue が追加の依存関係を必要とする理由がビルドシステム側にあるのか気になる
なので VC エコシステムがなぜフレームワークなしではやっていけないのか、よく分からない
Svelte がCustom Elements APIを通じて Web Components を生成できるようにしているのは良い
Svelte は通常の JS/HTML/CSS にコンパイルされるので、どんなフレームワークやバニラ JS でも動く再利用可能なコンポーネントを作るのに自然だ: https://svelte.dev/docs/custom-elements-api
Web Components の議論を何年も追ってきたが、フルスタック開発者として生活をより良くするために何ができるのか、いまだによく分からない
これらの例の大半は、データを HTML にテンプレートとして差し込む程度のもので、それならすでに handlebars でできる
何か見落としているのだろうか
HTML を文書として使うなら、Web Components でより洗練されたリアルタイムのインタラクション機能を追加できる
WebSocket に接続するターミナルエミュレーター、日付ピッカー、カスタムフォーム要素、地図、データテーブル、タブウィジェット、昔の jquery-ui が提供していたようなカスタムコンポーネントがその例
Web Components なしでも可能だが、カスタムコンポーネントとして作れば HTML はずっと整理され、文書らしさを保てる
一貫した Web Components ライブラリがあるとよいし、HTMX と Server-Sent Events でもかなりまともなリアルタイムチャットは実現できそう
HTML、CSS、JS 全体をブラウザが特別な小細工なしに分離してくれる
Web Component を作り、JS・HTML・CSS の API を変数ベースで明確に定義したうえで、どんな環境に入れても壊れず、複雑な CSS 名前空間やフレームワーク依存の迷路を作らなくてよいのが良い
たとえばテーブルを包む Web Component でフィルタリングやドラッグ&ドロップによる並べ替えのような機能を追加でき、JS が無効でも、あるいは読み込みに失敗しても、ユーザーには基本のテーブルとコンテンツが届く
以前はフロントエンドフレームワークの白画面よりはるかに良かったが、今ではサーバーサイドレンダリングが広く可能になり、この利点はやや薄れた
スタイルのカプセル化も良いが、最近は headless UI ライブラリやフレームワークの scoped styles が一般的になり、10年前ほど切実ではなく見える
ただしスロットを使うには Shadow DOM を選ぶ必要があるため、自前の再利用コンポーネントを作るときに、ページへスタイルシートを1枚入れる方式でスタイリングできないのは面倒
デモが 手動 DOM 操作 200行を見せてきたら、Web Components が未来だとは言いにくい
それがすべてで、他の大半の目的にはかなり微妙
また、UI コンポーネントを7バージョン作らなくても、すべてのフレームワークで動く形で配布できる
Web Components と Shadow DOM の最悪な部分は、ブラウザ拡張 が正しく動かなくなったり、まったく動作できなくなったりすることがある点
ブラウザベンダーもこの状況を直そうと急いでいない
Web Components の最大の「過ち」の一つは、人々の頭の中でこれが Shadow DOM と結び付けられてしまったことだと思う
アプリ開発では live DOM を維持すれば、Web Components はとても軽量で簡単な選択肢になる
bootstrap、tailwind など好みの CSS ツールを使い続けながら、ほぼコストなしで優れた機能的カプセル化を得られ、レンダラーとして lit-html のようなものを使うと特に良い
チームはネイティブ Web Components の作業を概して新鮮だと感じ、フレームワークの世界から来た開発者も1週間ほど慣れれば、元に戻りたいとは思わなかった
シンプルなクラス属性と
set()でレンダー関数を手動で呼ぶだけで、フレームワークの煩雑さなしに リアクティブ性 の利点を得られる問題は、「簡単モード」で始める方法を示す資料があまりないこと
入門資料の大半は、アプリ開発者ではなくライブラリ作者向けの Shadow DOM や CSS parts といった痛みの大きい技術へいきなり押し込んでくる
Web Components で暮らしを楽にする「The Good Parts」のようなガイドを書くべきだと思う
代案としては、live DOM だけを使い、サーバーサイドレンダリング優先で、「jQuery のひと振り」の代替として優れた「HTML web components」がある: https://adactio.com/journal/20618
また、Shadow DOM はできるだけ少なく使い、スタイリングや合成が必要なら live DOM に置く「Shadow gristle」もある: https://glazkov.com/2023/03/02/shadow-gristle/
この技術は、使い方次第で祝福にも呪いにもなるようなので、関連資料やコメントを集めているところ
いちばん良いのは、隔週ごとに 依存地獄 に落ちなくて済むこと
相互運用性がユーザー視点では最大の利点だが、その代償として使う各コンポーネントごとに不要なランタイムが付いてくる可能性があるという性能コストを過小評価しているように思う
Web Components と一緒に Lit のようなフレームワークを使うのが推奨されるやり方で、時間が経って新しいフレームワークが生まれ、コンポーネントが古いバージョンに縛られると、このコストは蓄積していく
1つのページに重複ライブラリがいくつもある方向性は誰にも勧めたくないし、それがベストプラクティスに含まれるなら長期的によくない
Web Components 支持者たちの記事、ソーシャルメディア、動画を何年も見てきたし、自分こそ対象ユーザーであるはずだが、相互運用性税の上に主流フレームワークにはない欠点が山ほどある
各フレームワークのエコシステム内では相互運用性はうまく機能しており、開発者に相互運用性を求めさせるのと同じ力学が、少数の主流フレームワークの周辺へと集約させてもいる
Web Components は技術面で追いつけておらず、2010年代初頭の設計のために Web プラットフォームへ多くの複雑さを追加していると思う: https://x.com/Rich_Harris/status/1840116730716119356
Svelte のようなランタイムが小さいフレームワークも多く、100個を1ページに載せようという話ではないが、5〜6個程度なら問題ないと思う
理想的という意味ではないが、段階的な移行やマイクロフロントエンドには役立つかもしれない
参考までに、React 17 も同じページに複数の React バージョンを置ける機能を導入している: https://nolanlawson.com/2021/08/01/why-its-okay-for-web-components-to-use-frameworks/, https://bundlephobia.com/package/svelte@4.2.19, https://legacy.reactjs.org/blog/2020/10/20/react-v17.html
React と react-dom を合わせると 100KB を超え、Svelte と Lit は一桁 KB だ
人々が毎日何も考えずに使っている肥大化に近づくには、かなり多くのフレームワークを入れられる
これまで一貫して見てきたシグナルはよくなく、そのコミュニティは X にいて、Web Components は彼らの問題を解決できておらず、最良の状況でもうまく使われていない
説得に成功してほしいとは思うが、彼らは概して Web Components は失敗であり、全体として Web に悪かったと言う傾向がある
ほとんどのランタイムはかなり小さく、2つのランタイムが同時に動いたとしても性能オーバーヘッドは大きくない
最新の Web フレームワークはどれもリアクティブなので、応答することがなければ何もしない
ページの一部は React、別の一部は Lit、さらに別の一部は Svelte で作られていても、ユーザー体験やバッテリー消費が単一フレームワークのページより目に見えて悪くなる理由はあまり見当たらない
引用されたツイートは、Web Components が「フレームワークを作るための有用なプリミティブ」かどうかについてのもので、実際に使ったファンたちもたいていそうだとは言わないだろう
Web Components は配布メカニズムであり、代替案が React、Preact、Svelte、Solid、Vue、バニラ JS 向けに同じライブラリを7回作ることしかないなら、それはひどい
Web Components は好きだし、私たちが自分たちで作り出した現在のフロントエンド地獄から抜け出させてくれる可能性に楽観的だ
最近フロントエンドの未来について短い発表をしたが、他の人たちも脱出口を期待しているようだった
DB GUI 用のデータテーブルを作っていて、数十万行を読み込んでもスクロールはとても滑らかだ
Web Component ライブラリも近く公開する予定で、まだ早い段階で荒削りだが、もっと多くの人に見てもらえたらと思う: www.astra-ui.com
小さい画面向けのレスポンシブデザインを考慮してサイドバーを再配置し、body には width ではなく max-width を置いたほうがいい
ホームページ下部の「explore components」ボタンはどこにもつながっていないように見える
「よく構造化されアクセシブルなコンポーネント実装から学べ」とあるが、ドキュメントで実装へのリンクを見つけられなかった
「管理や更新が必要な依存関係はない」とあるが、astra-ui 自体が依存関係ではないのかと思うし、変更ログもある: https://www.astra-ui.com/changes/
「コードとスタイリングを完全に制御」できるともあるが、ライブラリが提供する実装に依存しながらどう完全な制御が可能なのか理解できない
このライブラリを公開しようと思った理由が気になる。社内ソフトウェアのオープンソース化は、会社に特定の目標があるときには有用だが、たいていは見返りのない時間消費になりやすい
コンポーネントライブラリはエコシステムでの採用をめぐって戦わなければならず、そうでなければ受け手がおらず公開する理由はあまりない
素晴らしい解決策に見える
数か月前、新しい職場で約25万行のJSコードベースを引き継いだ。
1つの巨大なクラスといくつかのサブクラスがすべてを担っており、3万行もあるファイルもあった。
フレームワークもリアクティビティもなく、ボタンをクリックするとイベントリスナーで画面上のあらゆるものを手動で更新しなければならなかった。
誰かが基本的なJavaScriptの本を1冊だけ持って修道院の独房に何年も閉じ込められ、その間に書いたようなコードだった。
少しずつ進める必要があったので、Web Componentsへのリファクタリングを始めたところ大いに役立ち、これまでに5万行削減できた。
ただ、本当の目的は書き直す前に既存コードが何をしているのかをすべて学ぶことだった。
Web Componentsで作り直すのはその目標を達成する1つの方法であり、全部捨てて最初からやり直さなかった点がよい。
ただし、ある程度進んだところで別のプロジェクトに移ると、次の人が来て自分のスタイルでまたリファクタリングを始め、3つのスタイルが混在する難解なコードベースになる危険はある。
それでも25万行を一度に全面書き直しするよりはましだ。
Web Componentsでよかった点の1つは、少なくとも理論上はJS無効状態でも動作できることだ。
プログレッシブエンハンスメントのために何度かそうしてみた。
全体としてNolanの意見には同意する。Web Componentsにはエッジの粗さが十分にあり、現状のままで世界を席巻するのは難しいが、特定のユースケースではかなり良い。
ただ、サーバーサイドレンダリングとうまく噛み合わないという話についてはよく分からず、問題なくやれている。
見た限りでは、特定のタグにテンプレートを登録するにはJavaScriptが必要に見える: https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_templates_and_slots
ReactJSではコンポーネントやテンプレートをサーバーレンダリングできるし、JSXはかなり優れたテンプレート言語だと思う。
Web Componentsには組み込みの優れたテンプレート言語がなく、自分で持ち込む必要があると理解している。
タグにひも付いたJSコンポーネント片を取り込み、JS実行なしで必要なHTMLをレンダリングする標準的な仕組みは知らない。
将来的にサーバー上で異なるWeb Componentフレームワークを3つレンダリングし、それらが相互に合成され、きれいにhydrationされるようになれば、解決したと言えるだろう: https://nolanlawson.com/2023/08/23/use-web-components-for-what-theyre-good-at/