Open4

Bun

high-ghigh-g

モチベーション

参考

https://bun.sh
https://bun.sh/docs
https://zenn.dev/k41531/articles/dbedb88f06898a
https://voluntas.medium.com/なぜ-zig-の採用を検討しているのか-106f1ca2d25
https://zenn.dev/kenjimorita/scraps/c066ca54e4aeea

この人の順番よさげ
https://zenn.dev/kwst/scraps/dea945f1646fcc

Zig気になる
https://zenn.dev/tetsu_koba/articles/2da58bd66586aa

タイムリーで気になる
https://zenn.dev/yusukebe/articles/e8ff26c8507799

high-ghigh-g

Bunをざっくり知る

公式とその他資料を読んだ
https://bun.sh/docs
https://zenn.dev/k41531/articles/dbedb88f06898a
https://voluntas.medium.com/なぜ-zig-の採用を検討しているのか-106f1ca2d25
https://zenn.dev/kenjimorita/scraps/c066ca54e4aeea

特徴

  • Node.js の代替として設計された「速くて All in One な Javascript ランタイム」
  • Zig で開発されており、内部のJSエンジンで JavaScriptCore を利用
  • 起動時間とメモリ使用量が大幅に削減

現在、最も一般的なJSエンジンは、V8(Google製)とJavaScriptCore(Apple製)
JavaScriptCoreはV8より速い傾向があるよう

Bun​コマンドラインツールについて

下記が実装されている

  • スクリプトランナー
  • Node.js 互換のパッケージ マネージャー
  • テスト ランナー

ほとんど変更を必要なく、既存の Node.js プロジェクトで使用可能。
既存ツールよりも大幅に高速。

コマンド一覧

bun run start  # run the `start` script
bun install <pkg>​  # install a package
bun build ./index.tsx  # bundle a project for browsers
bun test  # run tests
bunx cowsay "Hello, world!"  # execute a package
high-ghigh-g

Bunをざっくり触る

Bun本体のインストールについて

# バージョンを指定しないならこちらでok
curl -fsSL https://bun.sh/install | bash

# バージョンを指定する場合
curl -fsSL https://bun.sh/install | bash -s "bun-v1.0.0"

source $HOME/.zshrc  

インストールok

bun -v
1.0.4

Hello World

index.ts

console.log('Hello Bun!')

bun run index.ts
※ bun run js/ts ファイル名で 実行ができる
※ ts はコンパイルしなくてもデフォルトで動作する

Hello Bun!

パッケージマネージャについて

bunもpackage.jsonを利用する
scriptsも同じで、下記に記述することで bun run ◯◯ が利用可能
startやdevなどの予約されているワードに関しては、bun start、bun devで実行可能。

  "scripts": {
    "a": "bun run index.ts",
    "start": "bun run index.ts",
    "dev": "bun run index.ts"
  },

パッケージ追加

bun add ◯◯
bun add -D ◯◯

Webサーバ用の環境作成

ディレクトリ作成 → bun init

mkdir bun_quickstart
cd bun_quickstart

bun init

初回ディレクトリこんな感じ

簡易Webサーバ(Hello Bun)

const server = Bun.serve({
  port: 3000,
  fetch(req) {
    return new Response('Hello Bun!')
  },
})

console.log(`Listening on http://localhost:${server.port} ...`)

bun start でブラウザ表示ok

パッケージ追加
figlet → 引数の文字をアスキーアートにするもの

bun add figlet
bun add -d @types/figlet # TypeScript users only

index.ts

import figlet from 'figlet'

const server = Bun.serve({
  port: 3000,
  fetch() {
    const body = figlet.textSync('Bun!')
    return new Response(body)
  },
})

console.log(`Listening on http://localhost:${server.port} ...`)

再度 bun start

high-ghigh-g

Bunの中身を知る

Bunの設計について

Bun は、今日の JavaScript エコシステムを念頭に置いてゼロから設計されている

  • スピードについて、Bun プロセスは現在 Node.js よりも 4 倍高速
  • TypeScript と JSX をデフォルトサポート
    • .jsx、.ts、ファイルを直接実行可能
    • Bunトランスパイラは、実行前にts/tsxを標準のjsに変換
  • ESM と CommonJS の互換性
    • Bun は ES モジュールを推奨
    • CommonJS もサポート
      • npm 上の何百万ものパッケージは依然として CommonJS を必要とするため
  • Web標準API
    • fetch、WebSocket、ReadableStreamなどの標準 Web API で実装されている
    • Apple製のJavaScriptCoreエンジンを利用の為、一部の API はSafariの様なURL直接使用の形をとる
  • Node.js との互換性
    • Node.js 組み込みモジュール(process、path、fs、httpなど)との完全な互換性を目指している
    • これは進行中のステータスで、まだ完了してない
    • 現在のステータスについては、互換性ページを参照

Bun は単なるランタイムではない。
長期的な目標は、パッケージマネージャー、トランスパイラー、バンドラー、スクリプトランナー、テスト ランナーなどを含む、JavaScript/TypeScript製アプリ構築の為の統合されたインフラストラクチャ ツールキットになること。

インストーラが高速な理由

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

npm installからbun installに切り替えると、インストールが最大 25 倍高速になります。

Global cache

レジストリからダウンロードされたパッケージは、 ~/.bun/install/cacheのグローバル キャッシュに保存されます。
これらは {name}@{version}のような名前のサブディレクトリに保存されるため、パッケージの複数のバージョンをキャッシュできます。

再ダウンロードを最小限に抑える

パッケージインストール時に、package.jsonで指定された範囲内のバージョンがすでに含まれている場合、
Bunはキャッシュされたパッケージを使用します。

高速コピー

パッケージがキャッシュにダウンロードされた後、それらのファイルをnode_modulesにコピーする必要があります。
Bun は、このタスクを実行するために利用可能な最速の syscall を使用します。
Linux ではハードリンクを使用します。
macOS では、clonefileを使用します。

ディスク容量の節約

Bun はハードリンクを使用してモジュールを Linux 上のプロジェクトnode_modulesディレクトリに「コピー」するため、パッケージの内容はディスク上の 1 つの場所にのみ存在し、node_modulesのディスク容量が大幅に削減されます。

この利点は、パフォーマンス上の理由からclonefileを使用する macOS には適用されません。

Lockfile

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

bun installを実行するとbun.lockbというロックファイルが作成される。
この中身は、package-lock.jsonやyarn.lockとは違い、バイナリになっている。

なぜバイナリなのか?

パフォーマンスのため。
バイナリになることで、保存とロードが高速に処理が出来る。

ロックファイルを精査するには?

bun install -y を実行すると yarn.lock が生成される。

なぜ速いのか

バイナリ化する際に1次元の配列に最適化したり、文字列重複の排除などを行う為

バンドラーが高速な理由

https://bun.sh/docs/bundler

esbuildの1.75倍、Parcel2の150倍、Rollup + Terserの180倍、Webpackの220倍の速度

Bun.build

Bunは、WebpackやViteなどのサードパーティツールに頼らずともデフォルトでbuildが可能。
また、TypeScriptのトランスパイルもNode.jsの場合はtypescriptパッケージを利用するが、Bunはそれを必要とせず、デフォルトでトランスパイルが可能。

await Bun.build({
  entrypoints: ['./index.tsx'],
  outdir: './build',
});

ローダー

デフォルトでローダーも用意されている。

https://bun.sh/docs/bundler/loaders

高速なバンドラーのesbuildから着想を得ている

https://bun.sh/docs/bundler/vs-esbuild

参考記事

https://qiita.com/rana_kualu/items/f9527125fbc08a52c409