Web開発
コードベースからReact.jsを削除し、UIインタラクティビティのためにHtmxを採用する
Removing React.js from the codebase and adapting Htmx for UI interactivity (misago-project.org)
要約
Misagoプロジェクトでは、DjangoテンプレートとReact.jsコンポーネントの二重管理による開発の複雑化やパフォーマンス低下といった課題に直面していました。この記事では、これらの問題を解決するため、サーバーサイドレンダリングされたHTMLでUIの一部を動的に更新できるHTMXへの移行計画について説明しています。これにより、JavaScriptへの依存を減らし、開発効率とパフォーマンスの向上が期待されます。
全文翻訳
現在のMisagoの動作は以下の通りです。ユーザーがhttps://misago-project.orgにアクセスすると、Djangoビューがスレッドリストを表示するためのデータを収集します。Djangoビューは、スレッドリストのほぼ完全なHTMLを含むテンプレートをレンダリングしますが、そのHTMLのレンダリングに使用されたのと同じデータを含むJSONも含まれます。そして、フォームが無効になっているため、インタラクティビティはありません。JavaScriptがダウンロードされます。JavaScriptが実行され、ページの本文に埋め込まれたJSONを読み込み、DjangoテンプレートからレンダリングされたHTMLの大部分をReact.jsコンポーネントのHTMLで置き換えます。これによりボタンが有効になり、UIのタイムスタンプが更新されます。
このアプローチにはいくつかの問題があります。
Misagoの多くのページは、DjangoテンプレートとReact.jsコンポーネントの2度実装されています。HTMLのカスタマイズを開始した人々は、Djangoテンプレートを編集しても、サイト上では一瞬しか変更が見えず、その後、彼らがカスタマイズする必要があることを知らなかったReact.js HTMLに置き換えられてしまうため、苦労しています。
ユーザーとゲストの両方がアクセスできる各ビューは、Djangoビューとテンプレート、そしてReact.jsルートとコンポーネントの2度実装する必要があります。また、データ取得を可能にするためのAPIとJSONシリアライザーも必要になります。React.jsアプリのためにデータを事前に準備するためのJSONシリアライゼーションは、レスポンス生成を遅くします。
翻訳メッセージの大部分が重複しており、django.poとdjangojs.poの両方のファイルに存在します。JavaScriptの翻訳ファイルは、初期ダウンロードサイズも増加させます。
大量のJavaScriptはパフォーマンスを低下させる可能性があり、特に古い低速なモバイルデバイスでは顕著です。
プラグインがページのカスタムHTMLを置き換えたり挿入したりできるようにするには、それらのプラグインがDjangoテンプレートとReact.jsコンポーネントの両方を実装する必要があります。また、Misagoはmisago-dockerの一部として、サイトビルドの一部としてJavaScriptビルドステップを実装する必要があります。プラグイン開発者は両方を理解する必要があります。
この問題に対する解決策として、私は2つの選択肢を検討しました。
Djangoビューとテンプレートを削除し、検索エンジンのボットを満足させるために最小限のバージョンのみを保持します。APIの実装に注力し、すべてのUIをReact.jsアプリにします。
DjangoをAPIに縮小し、サーバーサイドレンダリングを備えたJavaScriptフレームワーク(例: Next.jsやRemix.run)を使用します。
しかし、ここで重要なことがあります。多くのフォーラムソフトウェアは、可能な限りサーバーでレンダリングし、クライアント側でJavaScriptを使用してインタラクティビティを向上させるという古い方法を依然として採用しています。そして人々はそれで満足しています。そしてこのアプローチには、上記のどの問題もありません。
インターネットフォーラムソフトウェアは多くのインタラクティビティを備えていますが、このインタラクティビティはページの特定の場所に限定されています。モデレーションアクション、スレッドの監視、返信の作成、最新の通知の表示、投票などです。これらすべてはReact.jsなしで達成でき、私たちがフルページリロードを避けるべきだと判断する何年も前からそうでした。
では、HTMXとは何でしょうか?
HTMXは、開発者がHTMLの一部を、インタラクションによって新しいサーバーレンダリングHTMLで置き換え可能な動的な島として指定できる、非常に小さなライブラリです。例えば、実際のスレッドのリストは、そのような(大きな)島の1つです。Djangoテンプレートに少量のHTMXを含めることで、スレッドリストの現在のカテゴリを変更すると、選択したカテゴリの新しいスレッドリストのHTMLのみをDjangoから取得できますが、ナビゲーションバーの検索結果など、ページの他のHTMX部分は変更されません。
Misagoのバックエンドコードは、リクエストがHTMXから来た場合に、フルページではなく、この島のHTMLのみを返すように変更するだけで済みます。
JSONシリアライゼーションを行ったり、専用のJavaScriptやReact.jsを作成したりする必要はありません。
HTMXは、20年前にjQueryで行った$.get("url", "#outlet")を行う宣言的な方法です。またはRailsのTurbolinksです。
これを書くことになるとは信じられませんが、無限スクロールが嫌いな場合や、そうでなければシンプルに保ちたい場合、フォーラムソフトウェアにとってはこれが正しい道です。
GitHubイシュー: #1674
管理パネルをSPAに移行しないことも決定しました。現在、再利用可能なDjangoビューのセットがあり、作業の90%を処理しており、管理画面に新しいページを追加するには、適切なベースビューを選択し、空白を埋め、1つまたは複数のフォームを定義し、それらのための非常に基本的なテンプレートを作成する必要があります。残りは自動的に行われ、私はそれが気に入っています。
React.jsからHTMXへの移行には大きな労力がかかりますが、複数の小さなステップとして実行できます。例えば、あるリリースでナビゲーションバーをHTMXに移行し、次にスレッドリスト、次にスレッドページ、さらにユーザープロフィールなどを移行できます。しかし、プラグイン/権限/新しいパーサーはまだ先に完了する必要があります。そのため、HTMXへの移行は2024年後半まで待つことになります。私はそれで構いません。なぜなら、Bootstrapの最新版に移行したいとも思っており、彼らはそこで素晴らしいものを開発しているからです。
参考までに、Misago 0.39のJSサイズ:
vendor.js: 679kb, 214kb gzip圧縮済み
misago.js: 615kb, 124kb gzip圧縮済み
django-i18n.js: 102kb, 25.4kb gzip圧縮済み
Misago JSには遅延ロードされるものも含まれています:
hlj.js: 144kb, 49kb gzip圧縮済み
zxcvbn.js: 820kb, 430kb gzip圧縮済み
React.js(およびその他のJS依存関係)をMisagoから削除し始めたら、これらの数値に戻る予定です。
また、移行期間中は、Misagoの一部がReact.jsもHTMXも持たず、実質的に「マルチページアプリケーション」になる可能性があることを警告する必要があります。これは恐ろしく聞こえるかもしれませんが、ユーザーオプションページなどでリンクをクリックしたりフォームを送信したりすると、ページ全体がリロードされるだけです。しかし、フルページリロードが絶対に耐えられない場合、例えば投稿に「いいね!」をしたり、投票したりする場合には、プレースホルダーAJAX(または単にHTMX)を記述します。
「フォーラムオプション」ページは「アカウント設定」に置き換えられました。この新しいページは完全にDjangoビューで作成され、一部のページでは動的更新のためにHTMXを使用しています。
JSサイズ変更:
misago.js: 578kb, 107kb gzip圧縮済み(37kb/17kb削減)
スレッドリストは、React.jsの代わりにDjangoビューとHTMXを使用するように、ほぼゼロから書き直されました。
JSサイズ変更:
misago.js: 530kb, 99kb gzip圧縮済み(48kb/8kb削減)