WakuをNode非依存にするのは大変だった話
で、しれっとNode依存からの脱却と書きましたが、とても大変でした。
にあるように、Honoへの移行は重要だったのですが、Honoに移行した時点ではまだNodeに依存してました。Hono移行に着手してからおよそ1ヶ月、
この辛さは誰にもわかってもらえないと思って、あえて書きませんでしたが、まあ、それはそれは大変でした。ざっとPRの数を数えたら25くらいでした。
書かないと伝わらないと思い、頑張って書いてみます。
Node StreamからWeb Streamへの変更
当然、Node Streamは使えませんので。
ちなみに、最初にExpressからHonoに移行した時点では、Node Stream -> Web Stream -> Node Streamという余計な変換をすることになってました。理解が正しければ、最後の変換はHono内です。今の時点でも、Hono+Nodeを使う場合には、Web Stream -> Node Streamの変換があるため、Nodeを使う場合にはパフォーマンスは落ちるかもしれません。Hono次第。
node:path
の排除
path.join
を多用していたので、自作しました。
ついでに、node:fs
のレイヤーも抽象化して、windows対応をスムーズにしました。
なんと、ファイルパスは3種類もあるのです。
/foo/bar
c:\foo\bar
c:/foo/bar
file:///foo/bar
-
file://c:/foo/bar
いや、5種類でした。普段、ファイルシステムを意識したコーディングをしていなかったので、新鮮な課題でした。
react-server conditionの排除
Reactライブラリが提供しているnode-loaderが"use client";
などの処理をしてくれるのですが、Node非依存にするには、それは使えません。どうやるのかと思ったら、コンパイル時に変換すればいいことがわかりました。しかし、そんな仕組みは用意されていないので、自作。ひとまずはハック。そのうち書き直します。コンパイラーを。
cwdの排除
そもそもViteにrootの概念があるので、それにならっていたのですが、process.cwd()
とか使えないので、外から与えることにしました。DEV用のコードとPRD用のコードが分離し始めたところです。
Workerの排除
node-loaderとreact-server conditionを使うためにWorkerを使用していましたが、これもNode依存(execArgs)なので、使えません。DEVだけにWorkerを残しました。
index.htmlファイル
index.htmlファイルはランタイムでfs.readFile
していたので、これを文字列に変えました。なんかもっといい方法があるような気もしますが、後回しで。
htmlファイルの拡張子追加
ここに来て、Honoのstatic serverが拡張子なしでは動かないことに気づき、全部のHTMLをindex.html化しました。Content-Typeを指定しなくて良くなったので、シンプルになりました。
ここまでの変更で、確かDenoで動くようになりました。
パスの概念を排除
Cloudflareで動かそうとしたら、cwdという概念がないことに気づきました。これまでで、ファイルシステムの排除は完了していると思っていたのですが、import.meta.url
にはまだ依存していました。これが、undefined
になるのですね。また、dynamic importも多用していたのですが、それも動かず。仕方ないので、ビルド時にインデックスを作ることにしました。
DEVとPRDのAPIを完全分離
これが影響範囲が広かったかもしれません。ランタイムをNode非依存にするために、関数を切り出してリファクタリング、package.jsonのエントリーポイントも分けました。開発時とビルド時はViteを使うこともありNodeに依存しています。
esbuild対応
Cloudflareのためのビルドでesbuildが使われているようで、dynamic importで上記のDEV/PRDの分離をしていたところが、エラーになりました。catch()
をつければesbuildが無視してくれるそうで、追加。これは他人が見たら理解不能なコードになっているのではないでしょうか。
ここまでやったところで、Cloudflareで動くようになりました。ファイルシステムから完全に脱却したので、DenoでもBunでもそのまま動きました。まだ、glue codeが必要なので、今度どうしていくかは別途考えます。あ、HonoがWakuをサポートすればいいんだ。 😁
Discussion