Cloudflare Pages Functionで型安全なHTMLテンプレートとしてTSXを使う
デモ
デモページを作成しました。以下のURLからアクセスできます。各ページはリクエストの都度サーバーサイドでTSXをレンダリングしています。
https://contoso-japan.pages.dev
GitHubリポジトリ
目的
Cloudflare Pagesの低いコストと運用の手軽さを生かしつつWebサイトを構築するのが目的です。さらに追加で以下の要件も満たす手段を検討しました。
- リクエストの都度サーバーサイドでHTMLをレンダリングしたい。
- Cloudflare Pages Functionに組み込まれているルーター機能を活用したい。
- UIはコンポーネント単位で作成し、再利用したい。
- 可能な限り依存ライブラリを減らしたい。
- 型の恩恵を受けたい。
実現方法
今回はNano JSXを利用してPages Function上でTSXをレンダリングするアプローチで実装しました。MPAでSSRなので、実質PHPです。
JSX / TSXはReactとセットで語られがちですが、実態はJavaScriptに展開されるテンプレートでありReactフレームワークとは独立しています。あくまでUIコンポーネントを構築するためのテンプレートとして利用しているだけなので、今回の実装とReactは無関係です。記事冒頭のデモが依存しているライブラリはNano JSXだけです。
HonoのJSXレンダラーを使えばよくない?
APIフレームワークだと思い込んでいて、気がついていませんでした。HonoにはサーバーサイドでJSXをレンダリングするミドルウェアが含まれています。さすがHono、何でも揃っていますね。
今回のアプローチはサーバーサイドで動作するJSX / TSXレンダラーさえ手に入れば実現できます。何ならフルスクラッチでレンダラーを実装しても構いません。とはいえフルスクラッチ実装は辛いのでHonoかNano JSXを選ぶのが妥当かと思います。
HTMLRewriterではダメなのか?
簡易的なテンプレートエンジンとしての側面もありますが、HTMLRewriterはRewriterの名前のとおりコンテンツの一部を書き換えるのに最も威力を発揮します。Cloudflare公式ドキュメントにあるWebサイトの翻訳機能がその一例です。
HTMLRewriterは基本的に文字列の加工を行うだけなので、意図せずUIを壊す恐れもあります。UIコンポーネントを組み合わせてページを構築する用途は想定外と思われます。
(余談)Pages Functionバンドルサイズの確認方法
Pages Functionsのバンドルサイズは以下のコマンドで確認できます。[1]
$ npx wrangler pages functions build --outdir dist
$ du -h dist
記事冒頭のデモは132 KBでした。さらにデプロイ実行時にはgzip圧縮されるので28 KBになります。無料枠の1 MBに余裕で収まっています。
容量の大きなアセット、CSSやクライアントサイドのJavaScriptなどはCloudflare R2でホストすればPages Functionのバンドルサイズが増えることはありません。大規模なWebサイトの構築には厳しいかもしれませんが、数百、数千ページ程度の小規模なWebサイトであればCloudflareスタックで構築するのはお手軽です。
Discussion