monolithic kernel

Deno と Bun から Node に戻ってきた

個人的なコードで、ちょっとしたスクリプトでは Deno、本格的な開発では Bun というように、JS のランタイムを使い分けていたのだが、Node に戻ってきた。

きっかけは、Deno だと Dependabot が使えず、Renovate を使うのにもかなり労力が必要だったこと。cooldown したかったので結構残念に感じた。

もともと TypeScript を手軽に使いたくて Deno を触り始めたのだが、Node でも TypeScript を実行できるようになったことで、実は Deno である理由ってそんなにないんじゃないかと思った。Deno は周辺ツールがオールインワンなところもよかったりするのだが、Biome が進化してきたことで、こちらも Deno ならではの魅力としては映らなくなってきた。

加えて、pnpm に minimumReleaseAge が入ったことで、久しぶりに pnpm を触ってようと思い、Bun のコードも含めて全部 Node に揃えてしまおうと思った。

# 後で気付いたけど Bun にも minimumReleaseAge 来てたので、Bun に関してはあんまり移行する理由なかったかも。

Bun のコードは、package.json に書かずに使われていた依存があったので pnpm 化で多少の修正が必要になったものの、Astro のアプリケーション部分は何も変更せずに Node に持ってこれた。すごい。

一方、Deno に関しては Deno 固有の API を使っている部分を書き換える必要があった。現在は Deno でも Node 互換の API が整ってきているのだが、昔からのコードだと厳しい。この作業を経て、今となっては、Deno で書くにしても Node の API を使っておいたほうがよいように思った。

# シェルスクリプトの代替的な利用を便利にしてくれる dax は、dax-sh というパッケージで Node でも使えるようになっていた。素晴らしい。

依然として Deno ならではの点として残るのはパーミッションだろうか。これは普通に使い所はかなりある気がしている。Node も追従しているものの、Deno ほどのものではなさそう。ただ、実行時にならないと必要なパーミッションが分からないのがちょっとしたスクリプトには面倒で、結局 -A みたいなことになってしまう。あらかじめ使うパーミッションを宣言しておいて、それに応じて API を使えるかどうか実行前にわかるみたいなモデルがほしい。

Bun は独自の API を増やしまくっているが、先述の Deno API の話と同様で、個人的には魅力だとは感じない。Node との互換性は高いので Node とどちらでもいいと言えばいいのだが、だからこそ今回みたいなちょっとした違いでも切り替えて使えるということで、移行して試してみることにした。

pnpm の面倒なところとして、pnpm を使うための準備が面倒というのがあった。手元にしても CI にしても Node を入れるだけでは使えず、追加で一手間が生じるし、その一手間も分かりやすいとは思えない。これについては、今だと mise を使うことで楽になると気付いた。mise は言語処理系だけでなくパッケージも管理できるので、pnpm を mise でまとめて管理しておけば、mise install 一発で pnpm も含めて Node 環境を構築できる。

mise.toml
[tools]
node = "24.10.0"
"npm:pnpm" = "10.18.3"

まだとりあえずの切り替えが終わったところだが、各ランタイムが競争して進化していることが分かってよかった。今後、移行したことで何かしら困っても、また別のランタイムにすぐ移行できると分かったので、かなり身軽な気分になった。


Related articles