Bunかる〜く触ってみた[Bunの実行, nodeとの比較]

こんにちは！ゆせです。
今回は、最近注目を集めているJavaScriptランタイム```Bun```が気になっていたので、興味本位でかる〜く触ってみました。最初に申し上げておきますが、本記事において、こと細かい解説はしません。ただ、

- 「Bunってざっくりどんなものなのか知りたい」
- 「聞く機会増えてきたし気になってたけど、なんだかんだ知らん」
- 「軽く手元で実行してみたい」

みたいな方には、是非読んでいただきたいものになっております！
実際に手元で動かしたことをそのまま再現しておりますので、実行してみたい方は参考にしてみてください。

言葉選びが間違ってる部分もあるかもですが、ご了承下さい。。笑

## Bunってナニ
先日,JavaScriptランタイム「Bun 1.0」正式版がリリース。
一言でよく表現されているのは、「速くてAll in OneなJavaScriptランタイム」。
とにかく「速い」。そんなイメージを持たれている方も多いと思います。Bunの代替としては、```node```や```Deno```があげられます。

![スクリーンショット 2023-10-03 1.15.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3236084/fe355914-fd76-c6ff-e94a-473943ed4858.png)

https://2022.stateofjs.com/en-US/other-tools/

上の画像からわかるように、今現在はnodeが圧倒的に使われていることがわかります。

以下に、Bunの公式Docと、「Linux では、現在利用可能な他の npm クライアントよりも約 20 倍の速さで、単純な Next.js アプリの依存関係をインストールします。」と書かれていた記事をなんとなく貼っておきます。

https://bun.sh/

https://news.ycombinator.com/item?id=31993429

### そもそも「All in OneなJavaScriptランタイム」とは？？
この見出しを入れた理由は自分自身がこの疑問を最初持ったからです。笑 
「All in OneなJavaScriptランタイム」とは、バンドル、トランスパイラ、パッケージマネージャなどが最初からbunに含まれていることを指すそうです。もう少し具体的に表現するならばnodeには、```webpack```や```npm```が備わっていますが、Bunはそれが一つで完結されているということになります。

ex: ```npm install``` ≒ ```bun install```

## さっそく触ってみる
まずは公式Docに書かれたインストールコマンドをそのままコピペでターミナルに貼り付けます。

```console
$ curl -fsSL https://bun.sh/install | bash
```

※今回バージョン1.0となったBunはLinux版とMac版が提供されているらしく、Windows版は現時点で実験的なビルドが作られており、数週間以内にさらに改善されていくとのことらしいので、Windows版で実行したい方は調べてもらうのが良さそうです。。専門外ですいません泣(もう使えてたりしないかな)

次に、ターミナル上で、以下のようなコマンドを打ちましょう

```console
$ mkdir bun-app # (自分で好きなように名前つけてください)
$ cd bun-app
```

bun-appに移動したら、以下をターミナルに貼り付けます

```console
$ bun init
package name (bun-app): bun-app
entry point (index.ts): index.ts
```

これで、プロジェクトが始まります。「bun init」は最小のプロジェクトで始めるコマンドで、適切なデフォルトを推測してくれます。パッケージ名や、エイントリーポイントを聞かれるので、上記のようにデフォルトのまま始めちゃいましょう。

ちなみに以下のコマンドでbunのバージョンを確認できます。

```console
$ bun -v
1.0.3
```

それでは、実際にvscodeを開いてコードを見てみましょう。
`index.ts`や`package.json`があることが確認できると思います。

開始するために、以下のコマンドを実行します(エントリーポイントに設定したファイル)

```console
$ bun run index.ts
```

上のコマンドを叩けば、Bunが`tsconfig.json`を生成します。(通常のjsファイルであれば、`jsconfig.json`??)

次にindex.tsを開き、Bun.serveを使用して簡単なHTTPサーバーを実装する、以下のコードスニペットをコピペします。（公式Docから引用）

```ts:index.ts
const server = Bun.serve({
  port: 3001,
  fetch(req) {
    return new Response(`Bun!`);
  },
});
console.log(`Listening on http://localhost:${server.port} ...`);
```

今回私は3000番ポートを別の開発で使っていたので、3001番にしましたが、どちらでも構いません。貼り付けたらサーバーをテストしてみましょう。

```console
$ bun index.ts
```

http://localhost:3001/ を(自分が指定したポート番号で)開いてみてください。以下のようにみることができれば成功です。
![スクリーンショット 2023-10-02 16.05.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3236084/72a88e46-cfcd-4132-bbe8-63d50fcebb35.png)

### スクリプトの実行をしてみる
`package.json`からスクリプトを実行することができます。やってみましょう。以下を`package.json`に貼り付けてください。

```json:package.json
{
  "name": "bun-app",
  "module": "index.ts",
  "type": "module",
  "devDependencies": {
    "bun-types": "latest"
  },
  "peerDependencies": {
    "typescript": "^5.0.0"
  },
  "scripts": {
    "start": "bun run index.ts"
  }
}
```

上のコードは、デフォルトのコードに、`scripts`を追加したことがわかります。
これで、以下を叩いてみます。

```console
$ bun run start
``` 

先ほどと同じく、localhostで開けたと思います。
**ちなみに、`bun run`は`npm run`より、28倍速いパフォーマンスを発揮してくれるらしいです。**

## パッケージもインストールしてみる
もう少し触ってみたいので、今回はfigletパッケージをインストールしてみます。figletについては、わかりやすそうな記事を貼っておきます。

http://blog.azumakuniyuki.org/2011/05/figlet.html

https://ja.linux-console.net/?p=14424

```console
$ bun add figlet
$ bun add -d @types/figlet # TypeScriptユーザー
```

figletを使ったindex.tsに書き換えます。

```ts:index.ts
import figlet from "figlet";
const server = Bun.serve({
  fetch() {
    const body = figlet.textSync('Bun!');
    return new Response(body);
    return new Response(`Bun!`);
  },
  port: 3001,
});
```

サーバーを再起動(`bun run start`)して、ページをリロードしてみましょう。
以下が表示されれば成功です！

![スクリーンショット 2023-10-02 16.25.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3236084/fdd07785-1b07-11a9-d20a-237419536d96.png)

## Bunのスピードを体感してみる
この記事だけ見ても、結局のところBunは速いん？って感じだと思うんで、最後nodeと速度比較して終わりにします！まずはHTTPサーバーの動作確認です。`curl -v http://localhost:3001/`を打って以下が表示されればok

```console
$ curl -v http://localhost:3001/
*   Trying 127.0.0.1:3001...
* Connected to localhost (127.0.0.1) port 3001 (#0)
> GET / HTTP/1.1
> Host: localhost:3001
> User-Agent: curl/7.86.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< content-type: text/plain;charset=utf-8
< Date: Mon, 02 Oct 2023 07:46:26 GMT
< Content-Length: 4
< 
* Connection #0 to host localhost left intact
Bun!%                                                 
```

速さを見る前に、比較対象であるnodeの環境構築もしたいと思います。
nodeも手元で試してみたい人は参考にしてみてください。

### てことでnodeの環境構築していく
まずは今いるbunを実行していたディレクトリから一個上の階層に戻って、またディレクトリを新しく作ります。

```console
$ cd ..
$ mkdir nodejs-load-test
$ cd nodejs-load-test
```

次に、Express.jsを使用して簡単なHTTPサーバーをセットアップします。
bunが速すぎてここのセットアップめちゃくちゃ遅く感じました笑

```console
$ npm install express --save
```

installが完了したら、任意のjsファイルを作って、以下を貼り付けます。

```js:server.js
const http = require("http");

const server = http.createServer((req, res) => {
  res.end("Hello World");
});

server.listen(3002);
```

貼り付けたらnode.jsサーバーを起動します。

```console
$ node server.js
```

これで比較対象の環境構築も終わりました。あとは、ポート番号を変えた同じコマンドを実行するだけです！

まずはnodeを見てみましょう。以下一行目のコマンドを叩くと、以下のようになりました。

```console
$ ab -n 5000 -c 10 http://127.0.0.1:3002/

This is ApacheBench, Version 2.3 <$Revision: 1901567 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
.
.
.
省略

Server Software:        
Server Hostname:        127.0.0.1
Server Port:            3002

Document Path:          /
Document Length:        13 bytes

Concurrency Level:      10
Time taken for tests:   0.488 seconds
Complete requests:      5000
Failed requests:        0
Total transferred:      1060000 bytes
HTML transferred:       65000 bytes
Requests per second:    10247.18 [#/sec] (mean)
Time per request:       0.976 [ms] (mean)
Time per request:       0.098 [ms] (mean, across all concurrent requests)
Transfer rate:          2121.49 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:     0    1   1.2      1      28
Waiting:        0    1   1.2      1      28
Total:          0    1   1.3      1      28

Percentage of the requests served within a certain time (ms)
  50%      1
  66%      1
  75%      1
  80%      1
  90%      1
  95%      2
  98%      2
  99%      3
 100%     28 (longest request)
```

続いて、bunのディレクトリに戻って、同じことをしてみます。

```console
$ ab -n 5000 -c 10 http://127.0.0.1:3001/
This is ApacheBench, Version 2.3 <$Revision: 1901567 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

.
.
.
省略


Server Software:        
Server Hostname:        127.0.0.1
Server Port:            3001

Document Path:          /
Document Length:        4 bytes

Concurrency Level:      10
Time taken for tests:   0.147 seconds
Complete requests:      5000
Failed requests:        0
Total transferred:      595000 bytes
HTML transferred:       20000 bytes
Requests per second:    34044.87 [#/sec] (mean)
Time per request:       0.294 [ms] (mean)
Time per request:       0.029 [ms] (mean, across all concurrent requests)
Transfer rate:          3956.39 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.1      0       1
Processing:     0    0   0.1      0       1
Waiting:        0    0   0.1      0       1
Total:          0    0   0.2      0       2

Percentage of the requests served within a certain time (ms)
  50%      0
  66%      0
  75%      0
  80%      0
  90%      0
  95%      1
  98%      1
  99%      1
 100%      2 (longest request)
``` 

実行結果の`Time taken for tests:`を見ればわかるように、bunの方が3.3倍早いことがわかります。これはあくまでも簡単なプログラムを動かした実行結果なので、実際に実務で使うときやプロジェクトを運用していく時にも全く同じ結果が得られるかはわかりませんが、とりあえずnodeより速いことがわかりました。

## 感想
今回はbunについて個人的に気になっていたので手元を動かしながら、さまざま実行してみました。この記事が誰かのお役に立てればとても嬉しいです。「npmよりbunが圧倒的に速い！」みたいな記事が山ほどありますが、実際に手元で動かしてみるとよりイメージが湧きやすいので、皆さんも是非試してみてください。
私自身、エラーは何回か起きましたが、公式Docはもちろん、いろんな記事や情報が拡散されていますので、エラーが起こらないように書いているつもりですが、もし本記事でもエラーが起こってしまった場合は、他の記事も参考にしてみてください！

## おまけ
補足的な感じにはなりますが、bunのlockファイルはバイナリであるらしく、故にgitとの相性が悪いとの記事を見かけた記憶があります。一応`git diff`する手段は以下の記事通り提供されているようですが、やはり良いことばかりではないですね。。これからのbunの進化に期待です！

https://bun.sh/docs/install/lockfile