You don't need Node.js
Node.jsはいらない場合がある、むしろいらない場合の方が多いかもしれない、
そしてDenoとBunを使い分けて代替する方法を説明するという記事です。
Post Node.js ランタイムの登場
Node.js のあとにできたランタイムがいくつも登場しています。
この中でも、人気であるDenoとBunを中心に考えていきます。
DenoやBunに変えるメリット
これがなければNode.jsから変える必要はないと思います。
私は、以下の3つが、2ランタイムに共通して言える大きなメリットだと思います:
- ネイティブTypeScriptサポート
- 高速
- Web標準
ネイティブTypeScriptサポート
現在、JavaScriptを記述するときは、TypeScriptを利用することが多いと思います。
Node.jsでTypeScriptを使うとき。tsc
でコンパイルしてから実行したり、ts-node
やtsx
で行っているのではないでしょうか?
これは不便だと思います。私はNode.jsよりDenoを先に使い始めていたので、Node.jsでTypeScriptを使ったとき、超不便だと思いました。
これがDenoやBunだと要らないのです。
deno run main.ts
bun main.ts
で動いちゃいます。
これは超便利です。
高速
DenoやBunは実行速度が速いです。
Bunのインストール速度
Bunの依存関係インストール速度は爆速です。npm i
の25倍早くなるようです[1]!
実行速度
次のファイル書き込みコードをNode/Deno/Bunそれぞれのランタイムで試してみます
import { writeFile } from 'node:fs/promises'
await writeFile('./a.txt', Math.random().toString())
30回平均が、以下のようになりました:
速いですね。
Bunのトップページには、Node/Deno/Bunのベンチマークが載っています。
Webサーバーの応答速度などの項目があり、NodeよりDeno/Bunが高速です。
Web標準
DenoやBunは、Node.jsよりもWeb標準に忠実です。
例えばfetch
。JavaScriptでデータを取得するのに現在ではスタンダードですよね?
これ、Node.jsではExperimentalなAPIなのです。少し前までは、node-fetch
などのPolyfillを使う必要がありました。
しかし、DenoやBunでは普通に使えちゃいます。
そのほかにも
- ⭕️ 使える
- 🔼 unstable/experimental
- 🙅♀️ 使えない
として、こんな感じです(Node.js 20, Deno 1.42, Bun 1.1):
API | Node.js[2] | Deno | Bun[3] |
---|---|---|---|
Web Crypto API (crypto ) |
🔼 | ⭕️ | ⭕️ |
Request /Response
|
🔼 | ⭕️ | ⭕️ |
FormData |
🔼 | ⭕️ | ⭕️ |
WebSocket |
🔼 | ⭕️ | ⭕️ |
ReadableStream /WriableStream
|
🔼 | ⭕️ | ⭕️ |
alert /prompt /confirm
|
🙅♀️ | ⭕️ | ⭕️ |
Web GPU | 🙅♀️ | 🔼 | 🙅♀️ |
すごいですね。DenoやBunはNode.jsよりWeb標準に忠実です。
しかし、 @oto さんからの指摘もありましたが、Deno/Bunは新興フレームワークのため、単純にDeno/Bunのstable/unstableを、Nodeのstable/unstableと同レベルで比較することは難しいと思います。
ESM
DenoおよびBun[4]は、デフォルトでESMを使用しています。
モジュールシステムとして、CommonJS ModulesよりESMを使うことが多い現在で、嬉しいですね。
Node.jsをやめたくなってきましたか?
DenoとBun
DenoとBunのメリットについて説明しました。次は、この2つの使い分けについてです。
DenoとBunを使い分けることで、Node.jsをやめることができます。
私なりの使い分け方は、1から作るならDeno、Node.jsのプロジェクトを使うならBunです。
この2つの使い分けで、Node.jsを代替することができます。
Bunの方がNode.jsプロジェクトに適している理由
DenoとBunのnpmインストール速度
これは、Bunの方が速いです。実験してみました:
まず、DenoとBunのキャッシュを削除します。
rm -rf ~/.bun/install
rm -rf ~/.cache/deno
次に、Astroをインストールしてみます。
bun add astro
deno cache astro
の速度を比較するのです。
次のようなBunコードを使います。
await Bun.$`rm -rf node_modules`
// Bun
const bunStarted = performance.now()
await Bun.$`bun add astro`
const bunResult = performance.now() - bunStarted
await Bun.$`rm -rf node_modules`
// Deno
const denoStarted = performance.now()
await Bun.$`deno cache npm:astro`
const denoResult = performance.now() - denoStarted
console.log(`Bun: ${bunResult} ms`)
console.log(`Deno: ${denoResult} ms`)
こうなりました:
npmインストール速度において、Bunは高速です。
Node.js の仕組みの問題
- Denoは、基本的に
package.json
を使いませんが[5]、Bunでは使います。 - Denoは、基本的に
node_modules
を使いませんが[6]、Bunでは使います。 - Denoは、基本的に
.ts
などの拡張子をつけてimportしますが[7]、Bunでは省略可能です。
Node.jsプロジェクト以外ならDeno
Denoは、Node.jsの互換性は意識はしていますが、Nodeとは別のところを行くランタイム、というイメージです。
ゼロコンフィグ
Denoは、設定ファイル不要です。
task.ts
を作成すると、deno run task.ts
で動きます。プロジェクトという概念なしで動かせます。
設定ファイルを作れないわけではなくて、ある程度の大きさのことをするときは作成するといいかもかもしれません。
手軽
Pythonは、気軽にプログラムを作成して実行できますが、Denoも同じ感じです。
シンプルに、CLIから計算処理、バックエンドも作れたりするランタイムです。
モジュールはグローバル
Denoのモジュールはグローバルにキャッシュされます。
また、DenoはURLでimportします。
import * as module from 'https://example.com/mod.ts'
のようなイメージです。これはグローバルにキャッシュされます。
また、npmモジュールを利用したいときは、npm:package
というURLを使えます。これもグローバルにキャッシュされます。
Pythonに似ています。
このように、DenoはもともとNode.jsの反省を踏まえて作られた、新しいランタイムを目指していたのに対し、BunはNode.jsとの互換性を意識して作られています。
そのため、Node.js用に作られたViteやNext.jsのようなフレームワークを使うときは、高速な代替であるBunを使うことがおすすめです。
一方、バックエンドやコンピュータ中心などのものを作ったりするときは、Denoがおすすめです。
Node.jsプロジェクトをBunにスイッチする
これは超簡単です。
Node.jsプロジェクト内で、npm i
の代わりにbun i
をして依存関係をインストールするだけです。
そして、node main.js
をbun --bun main.js
、npm run dev
をbun --bun run dev
にするだけです。
既存のプロジェクトでこっそりBunを使う
bun i
は、package-lock.json
およびyarn.lock
から自動で読み取ってインストールしてくれます。
bun i --no-save
をすれば、npmやyarnを使っているプロジェクトのうんざりする依存関係インストール時間を短縮できます。
Node.jsをやめられないところ
例えば、BunでViteを動かすとき、デフォルトでは、Node.jsが裏で動いたりしています。
bunx --bun vite
のように--bun
を使い、裏もBunで動かすこともできますが、SSRでは不安定だったりします。
また、DenoやBunのライブラリをnpmにpublishしたいときは、やっぱりnpm
コマンドが必要なので、Node.jsは必要です。
さらに、DenoやBunはまだまだNodeと比べたら新しいもので、安定性に欠ける可能性があります。
これらの欠点を理解して、スイッチするかどうかを決めるといいかもしれません。
まとめ
もちろん一概に言えることではないですが、Node.jsのようにプロジェクトを作ったり、Node.jsのフレームワークを使うならBunに変えられます。単純にNode.jsをバックエンドのJavaScriptランタイムとして使うならDenoに変えることができます。
そして、変えることでそれぞれのランタイムのメリットを享受できます。
みなさんも、Node.jsを、代替してみてはどうでしょうか?
Discussion
やっぱ会社だと使いにくいからなー
ドキュメントも実装も完全ではないし。
Bun.jsはようやく1.1が出て使い始めたけれど、
まずもってまだ不安定と言わざるをえない。
後は、Denoもそのままだとデプロイ先に困る。結局デプロイ後の環境に合わせた方が無難なケースは割とある。
少しずつ置き換わっていくのだろうが、Node.jsが今いらないか、と言われたら全く否
客観的にまとめれていて読みやすい文章で素晴らしいと思います。
ただ素人質問で申し訳ないのですが、Web標準の各jsのランタイム毎のstable, unstalbeについて、
nodejsのstableがdenoやbunと同格の安定性を持っていると仮定するのはちょっとおかしい気がします。
linuxでいうとarchlinuxのstableがmanjaroのunstableだったりと、会社、組織によって基準が違います。
また、ユーザー数が全然違うのでバグ報告もnodejsのほうが多いはずです。
bunやdenoの安定性の基準がnodejsより客観的に厳しいという基準があるなら別ですが、
基本的に新興勢力のほうが自己申告の安定性を低く見積もるほうが妥当じゃないかと思います。
bunやdenoのほうが安定性について厳しいという何らかの基準がありますなら、教えていただけると幸いです。
コメントありがとうございます。
確かに、安定性の問題は、古くからあるものの方が有利です。unstable/stableを一律に比較できないというのもおっしゃる通りあると思います。
基準はないですが、Bunを使って、不安定だと感じたことは何度かありました。
そのため、安定性の問題をこの記事に書き足そうと思います。ありがとうございました。