⛩️

WakuをNode非依存にするのは大変だった話

2023/12/13に公開

https://zenn.dev/dai_shi/articles/d6f5264e838b36

で、しれっとNode依存からの脱却と書きましたが、とても大変でした。

https://twitter.com/yusukebe/status/1734465245194903730

にあるように、Honoへの移行は重要だったのですが、Honoに移行した時点ではまだNodeに依存してました。Hono移行に着手してからおよそ1ヶ月、

https://twitter.com/dai_shi/status/1733470466416037960

この辛さは誰にもわかってもらえないと思って、あえて書きませんでしたが、まあ、それはそれは大変でした。ざっと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