🐷

HTML Drivenなフロントエンド開発について考える

2023/12/08に公開1

過日、@tonyennis氏のHTML Firstという文書を拝読しました。
少し調べているとHTML Driven Development - Valuesのように似た話について言及している記事もちらほら見つかり、興味を惹かれる内容でしたので少し深堀って考えてみた事をここに残します。

いそがしい人向け

  • HTML Firstの原則はモダンフレームワークを基盤にした開発に適用できるものではない
  • HTML Drivenな開発とはhtmxやhyperscriptのようなライブラリを活用する開発であるといえる
  • 技術スタック及びアーキテクチャを見直す
  • Locality of Behaviourを重視した設計思想
  • 課題はあるが、プロダクトの性質によっては採用の余地がありそう

HTML Firstとは何か

まず、件の文書からHTML Firstがどのようなものであるか見てみましょう。

概要

HTML First is a set of principles that aims to make building web software easier, > faster, more inclusive, and more maintainable by...
1. Leveraging the default capabilities of modern web browsers.
2. Leveraging the extreme simplicity of HTML's attribute syntax.
3. Leveraging the web's ViewSource affordance.

HTML Firstは「ウェブ・ソフトウェアの構築をより簡単に、より速く、より包括的に、より保守的にすることを目的とした原則の集合」であり、その方法は大きく3つ。

  1. 最新ブラウザのデフォルト機能を活用
  2. HTMLの極めてシンプルな属性構文の活用
  3. webのViewSourceアフォーダンスの活用

であるとしています。

目的

The main goal of HTML First is to substantially widen the pool of people who can work on web software codebases. This is good from an individual perspective because it allows a greater number of people to become web programmers, to build great web software, and increase their income. It's also good from a business perspective as it decreases the cost of building software, and decreases the amount of resources required to hire - a notoriously resource intensive process.
A second goal of HTML First is to make it more enjoyable and seamless to build web software. Most web programmers are familiar with the excitement of seeing their product come together rapidly as they transition smoothly between the text editor and the browser, with very few unexpected potholes or context switches. But today it takes several years of mastering tools and frameworks to get to that stage. HTML First principles should allow people to unlock that feeling, and level of mastery, much earlier on in their coding journey.
The way we achieve these goals is by acknowledging that HTML is very easy to understand, and thus using HTML as the bedrock of our product - not only to define content and structure, but also to set styling and behaviours.

HTML Firstの主な目的は、web開発に携わることができる人々のプールを大幅に広げることであり、これは個々人にとってもビジネスにとっても良いことである。
第2の目的は、webソフトウェアをより楽しく、シームレスに構築することである。ほとんどのwebプログラマーはプロダクトを作る楽しさを知っているはずだが、今日においてはその段階に到達するには、ツールやフレームワークを使いこなすのに数年を要する。HTML Firstの原則は、より早い段階で、その感覚と習得レベルを解き放つことを可能にするはずだ。

と述べており。これらを達成する方法は、
HTMLが非常に理解しやすいものであることを認識することであり、コンテンツや構造を定義するだけでなく、スタイルや動作を設定するためにも、HTMLを製品の基盤として使用することである。
としています。

このことから、単に「HTMLを正しく書こう」というような話では無いことが分かります。

原則

- Prefer Vanilla approaches
- Use HTML attributes for styling and behaviour
- Use libraries that leverage HTML attributes
- Avoid Build Steps
- Prefer Naked HTML
- Be View-Source Friendly

HTML Firstの中では6つの原則が挙げられています。

  • "Vanilla"なアプローチ
  • スタイリングと動作にHTML属性を使用する
  • HTML属性を活用するライブラリを使用する
  • Build stepを避ける
  • "Naked"なHTML
  • View-Sourceフレンドリーにする

本稿ではそれぞれを詳細に掘り下げませんが、原文では実際のコードを基にどのような思想であるか、どのようなメリットがあるかが記載されています。

HTML Firstの要点

1つ1つ言及していくとかなりの量になるため、要点をまとめると

  • 極力フレームワークを使用せずHTMLを中心に構築することで学習コストを軽減しシンプルなコードにする
  • buildを極力なくすことでメンテナンスや学習のコストを抑え、dev-toolなどで見れるコード(View-Source)をより活用する
  • これらの実現のためにhtmxやhyperscript、TailwindのようなHTML属性を活用したライブラリを使用する

ということです。

つまり、HTML Firstに則った実装およびこれに類するHTMLを中心に据えたフロントエンド開発を実践することはフロントエンド開発の技術スタック延いてはアーキテクチャ自体を見直すことになると言えそうです。

"buildを無くす"について

HTML Firstの原文にて言及されている"Avoid build step"について少し補足します。

ここでいうbuildはフロントエンド部分(つまりはviewを構築するためのコード)のコンパイル・トランスパイルやminify、コード分割などのステップのことです。

htmxやhyperscript、あるいはAlpine.jsのようなライブラリはpublic CDN経由で利用でき直接JavaScriptを書かずにHTML属性に文字列で指定することで様々な実装ができます。
これを利用することでプログラマーが直接書くコードはHTMLのみにすることができ、TypeScriptからJavaScriptへのコンパイル、JSXの解析、.vue.svelteファイルのコンパイル、モジュールのバンドルとcode split等々のステップが全て不要になるということです。
(ライブラリのコード以外不要になるためbundleサイズが肥大化しないというメリットもあります)

これについてはたしかにその通りであり、私もある程度同意しています。
一方で、Next.jsやNuxt.jsあるいはRemixやAstroといったフレームワークが普及してきた現在は少し事情が変わってきます。
これらのフレームワークの多くは上述したようなbuildツールを内包しほとんどzero-configでbuildのステップを完了させられるようになっています。
このあたりの話は先日行われたJSConf JP 2023のSosuke Suzuki氏による「書いたJavaScriptがそのままブラウザで動く未来へ」のお話が非常に分かりやすくなっています(スピーカーノート)。

また、public CDNを利用することの是非についても考える必要があります。
実際にTailwindはProduct環境でのCDN利用を推奨していません)し、htmxのドキュメントでも言及されています。
この理由についてはこちらの記事が参考になるでしょう。

本稿ではこのあたりについては詳しく取り上げません。

HTML駆動開発の構成

前述したとおり、HTML Drivenなフロントエンド開発を行うには技術スタックやアーキテクチャ自体の見直しが必要になりそうです。
どのようになっていくのか見ていきましょう。

これについてはhtmx and HTML Driven Developmentという記事にて少し触れられていますので、それを基に考えていきます。
この記事は冒頭のHTML Driven Development - Valuesと同じ方の記事です。

htmxとhyperscript

まずはじめに言及しなければならないことがhtmxhyperscriptの使用です。
HTML FirstでもHTML Driven Developmentにおいてもhtmxかそれと同等のライブラリの使用が前提となっており、HTML Firstで言及されている原則もhtmxの思想に則ったものです。
実質的にHTML駆動の開発とは、htmxやhyperscriptのようなライブラリを使用したフロントエンド設計思想であるといえるでしょう。

htmx・hyperscriptはHTML属性を活用したライブラリであり、インタラクションやfetch系の処理をそちらに任せることでHTMLを主軸に置いたコードベースを構築できるようになります。
同じような方向性のライブラリの候補としてAlpine.jsなどが挙げられます。

htmx・hyperscriptのライブラリはLocality of Behaviour(振る舞いの局所性)という原則に重きを置いています。

この原則は以下のように定義されています。

The behaviour of a unit of code should be as obvious as possible by looking only at that unit of code
-- あるコード単位の振る舞いは、そのコード単位だけを見ればできるだけ明らかでなければならない

webフロントエンドを構成する技術には構造を定義するHTML、見た目の装飾を定義するCSS、動作を定義するJavaScriptが有りますが、それらを別々の場所に定義するのではなくHTML属性を活用して1ヶ所にまとめよう。というのがここで語られている事です。
UIとしての意味を考えればこれは合理的であり、構造・見た目・動作が揃って初めて1つのコンポーネントの振る舞いとして意味を成します。

一方でこのLoB(Locality of Behaviour)はSeparation of concerns(関心の分離)の原則とある程度トレードオフであるとも述べています。
たしかに、関心の分離という観点で見れば「動作」と「装飾」はそれぞれ関心が異なるものですから適切に独立している方が自然に思えます。
また、DRY(Don’t Repeat Yourself)の原則とも相反します。HTML要素に対する見た目や動作をその要素の属性に記述するという事は細かな共通化が出来なくなっていきます。
これらは相反する原則ではありますが、LoBはこれらを非難している訳では無く開発者が適切に主観的にトレードオフを選択する必要がある。と述べています。
htmxやhyperscriptはあくまでLoBの思想に寄ったライブラリであるというだけの事です。

もう1つ重要なポイントとして、htmxとhyperscriptだけでUIを構築すればクライアントサイドで必要なJavaScriptはこれらのライブラリのコードだけになるためバンドルサイズを大きく削減することが出来るとともに、buildのステップを完全に消すことも可能であるとしています。
実際にはサーバーサイドのフレームワーク等にこれらのViewを載せる事になるため、アプリケーションのビルド自体は恐らく必要になると思いますが、npmパッケージの管理やそれらのbuildに関しては確かに無くしていくことは可能かもしれません。

ちなみにhtmxを使用したアプリケーションのサンプルはhtmxのドキュメント内で多数紹介されています。

コンポーネント化

リッチなwebアプリケーションを構築するためには再利用可能なコンポーネントを作成することが必要不可欠となります。
ReactやVueといったフレームワークを使用せずに実現していくにはWeb Componentsかpug等のテンプレートエンジンの利用が候補になるでしょう。

Web Componentsは外部フレームワークを使用せずにコンポーネントを構築できる良い選択肢に見えます。
しかしWeb Componentsは基本的にブラウザ上でJavaScriptを動作させてDOMの構築・更新を行うため、htmxとhyperscriptによって極力JavaScriptを書かないようにする思想とは噛み合いません。

htmx and HTML Driven Developmentに於いては、pugの様なテンプレートエンジンや、Rails・Djangoといった既存のサーバーサイドフレームワークの利用が候補に挙げられています。
pugの様なNode.js用のテンプレートエンジンの場合はExpress等を使用して動的にHTMLを生成する例も記載されています。
ここでのポイントとしては、どちらにしてもサーバサードフレームワーク上にViewを構築するモノリシックな構成が前提である点でしょう。
マイクロサービス化してデータアクセス等のバックエンドロジックを分離する場合は静的にHTMLのレンダリングを行うフレームワークを使用するか、SSRの様な動的生成を行うのであればExpress等でNode.jsサーバを立てる形になるでしょう。
Astro等の静的サイトジェネレーターに乗せるパターンもあり得そうです。
Node.jsベースになる場合はjsxの使用も検討できますね。
Honoなんかはデフォルトでjsxをサポートしています

Routing

お気づきかもしれませんが、このアーキテクチャではMPAが前提となります。
そのため、ルーティングに関しても使用するサーバーサイドのフレームワークに準拠したものになるでしょう。

SPAを実現するためには、どのようなフレームワーク・ライブラリを使用したとしてもクライアントサイドルーティングを実現するコードがクライアントバンドルに含まれます。
また、クライアントサイドルーティングではHash-BasedかURLベースかどちらを使用するか等独自の課題も付きまとうと述べられています(htmx and HTML Driven Development)。
実際にはNext.jsの様なルーティングシステムを提供しているフレームワークを使用している場合は、開発者にとってそれほど気を悩ませる問題ではなくなっています。

MPAなフレームワークでいうとAstroに代表されるIslands Architectureの様なMPAでありながらもパフォーマンスを追求したアーキテクチャも存在し、MPAであることが必ずしもパフォーマンス観点で不利であるという事は無い点は認識しておきたいところです。

とはいえこのままではSPA台頭以前のMPAにhtmxやhyperscriptを載せただけの構成になるため、パフォーマンス観点ではいささか不安が残ります。
htmx等を使用したインタラクションやAPI連携がどの程度複雑な仕様に耐えられるか、どの程度のパフォーマンスになるのかという点が重要になりそうです。

状態管理

htmxにおいてはアプリケーションの状態(state)は全てサーバーサイドに集約し、APIがJSONではなくHTMLを返すことでhtmxがそれをそのままDOMに反映するようなアプローチをとります。
このことは、クライアントサイドにロジックを持ち込まずUIが文字通りUser Interfaceとしての本来の役割である「表示とユーザーからの入力の受付」に専念できるというメリットがあります。

パフォーマンス観点で見たときには、UIの更新のために毎回formをsubmitし画面全体を再構築していた様な時代に比べればこのアプローチはあくまで部分的なDOMの更新に留まるため有利といえます。
とはいえ、毎回通信が発生しますから完全にクライアントサイドでUIの変化を制御するアプローチに比べると劣ると言わざるを得ません。
Alpine.jsであればクライアントサイドでUIの変更を完結させられますが、それはそのままクライアントサイドで状態を持つことを意味するため少し設計思想が異なってきそうです。

HTML属性やCSSによって表現できるUIの振る舞いはこのアプローチで実現出来そうですが、コンポーネントを横断したりアプリケーション全体で持つような状態(global stateの様なもの)に関してはsessionやCookieで保持する等一工夫必要になるでしょう。

htmxをメインにしてUIの状態を含めたすべての状態を完全にサーバーサイドに集約するか、通信が必要ない箇所はAlpine.jsでクライアントサイドで状態を持つか検討が必要そうです。

スタイリング

LoBの原則に沿ったCSSフレームワークとして、Tailwind CSSはhtmxやhyperscriptと非常に相性が良いです。
実際にhtmxのサンプルでも使用されていますし、HTML Firstの中でも触れられています。
ランタイムでJavaScriptを必要としないという点も重要ですね。

Tailwindの欠点としてCSS in JSのような動的な値の埋め込みが出来ないためCustom Propertyや簡単なクラス名の分岐だけで実現できないデザイン仕様に対してはやや弱い点があります。
そもそもそういったケースも稀ではありますが、このHTML Drivenなアーキテクチャにおいてはクライアントサイドでレンダリングを行わないためTailwind単体がボトルネックになることも無さそうです。

Tailwind CSSも一応public CDNがありますからhtmxとhyperscriptと合わせてCDNからロードするようにすれば、フロントエンド部分のbuildを一切行わないという事も可能ではあります。

アーキテクチャのまとめ

  • htmxやhyperscriptを使用し、これらを中心にUIや機能を構築する
  • テンプレートエンジンを使用しサーバーサイドでコンポーネントを作成する
  • MPA前提であり、ルーティングの方法は使用するサーバーサイドフレームワークに則る
  • アプリケーション状態はすべてサーバーサイドに集約する
  • スタイリングにはTailwind CSSのようなLoBの原則に沿ったライブラリやフレームワークを使用する

総評

HTMLドリブンなフロントエンド開発はhtmxやhyperscriptを中心にフロントエンド実装を行う設計思想であり、既存の開発基盤に組み込んでいけるようなものでは無く、フロントエンドアーキテクチャ自体の見直しになるため今日からすぐに実践できるようなものではありませんでした。

JavaScriptバンドルサイズの削減やbuildプロセスを簡易にする等モダンフレームワーク群がフォーカスしている課題に対して、フレームワークによる最適化では無くHTMLへの回帰という別アプローチで解決を試みる点は興味深く感じます。

htmxやhyperscriptを使用しLocality of Behaviourを重視した技術選定にについては、現状ではプロダクトに採用するのは少し厳しいのではないかというのが正直なところです。

第一に、パフォーマンス観点です。
MPA由来のルーティング体験の悪さをそのほかの部分でどうカバーできるかというところがポイントになるかと思います。
ブラウザ上でのUXに関しては実際にそれなりの規模のものを作ってみないと分からないというのが正直なところですが、bundleサイズが削減されるとはいえReactなどで作るSPAと比べて目に見えるほど良くなるようなケースは少ない気がします。
加えてプロダクトの性質によっては所謂SSRのようにサーバーサイドでon-demandでHTMLを生成する必要があるかと思いますが、streamingやprefetchなどでそのあたりの挙動を熱心に最適化しているモダンフレームワークに乗れないとなると画面遷移の鈍さがさらに顕著になることが予想できます。
今回取り上げたような技術スタックをハイパフォーマンスにとりまとめるフレームワークが登場すればかなり良い選択肢になってきそうです。

またもう一つの懸念が、htmxやhyperscriptを使用するにもそれなりに学習コストがかかる点です。
これらのライブラリは単に独自の記述方法を採用しており、実際に開発する際にはそれらがどのようなJavaScriptに置き換えられ実行されるのかを理解する必要もあります。
HTML Firstの文書では「フロントエンド開発に関わるツールやフレームワークを使いこなすのに数年を要する」ことが問題であると述べられていましたが、実際のところhtmxとhyperscriptを活用して様々なUIやインタラクション、機能を実装するにもある程度学習が必要になると思います。
特にhtmxやhyperscriptを採用しHTMLをすべての中心に据えるような実装はそれほど普及しておらず、所謂ベストプラクティスのようなものも簡単に見つからないでしょうから習熟するまでにはReactやVue等を使用してSPAを構築する術を学ぶのとそれほど変わらない学習量が必要になるのではないかと思いました。
この辺りはこれらの技術スタックが普及してくれば解決されそうです。

LoBの原則に沿った設計思想には合理性があり非常に興味深い内容でしたし、静的なサイトや小規模なサービスであれば現状でも十分採用の余地がありそうです。

結論

  • HTML Firstの原則はモダンフレームワークを基盤にした開発に適用できるものではない
  • HTML Drivenな開発とはhtmxやhyperscriptのようなライブラリを活用する開発であるといえる
  • 技術スタック及びアーキテクチャを見直す
  • Locality of Behaviourを重視した設計思想
  • 課題はあるが、プロダクトの性質によっては採用の余地がありそう

おまけ

今回取り上げた内容を実践したサンプルを作りました。
詳しい話は個人ブログの方に書き散らかしていきます。

Expressでjsxをレンダーするパターン
https://github.com/Shin-Taro/express-alpine-htmx-sample

Astroに乗せたパターン
https://github.com/Shin-Taro/astro-alpine-htmx-sample

Discussion

五所 和哉 (MonCargo CTO)五所 和哉 (MonCargo CTO)

記事ありがとうございます。
最近、社員しかアクセスできない管理画面を雑に作るのに htmx を使ってみたところ、 フロントエンドを一式作るよりかなり楽でしたので、そのような限定的な使い方は有りかもしれないと思いました。
このように整理していただけるとありがたいです!