素のReact with Bun

## まえがき
この記事は「[Nihon University Advent Calendar 2023](https://qiita.com/advent-calendar/2023/nihon-u)」の５日目の記事です。

最近「パフォーマンスが速い」と色々なところで話題のBunですが、その凄さはパフォーマンスだけではなく、色々な機能を包含しているところにもあります。

その中でも、今回はBunのバンドラーやトランスパイラーを使って、素のReact環境を構築してみようと思います😃

## 完成したもの

https://github.com/avaice/bun-min-react-sketch


## 最終的なDependencies

めちゃくちゃシンプルですね。

```json:package.json
{
  "devDependencies": {
    "@types/react": "^18.2.42",
    "@types/react-dom": "^18.2.17",
    "@types/web": "^0.0.125",
    "bun-types": "latest"
  },
  "peerDependencies": {
    "typescript": "^5.0.0"
  },
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  }
}
```

## リポジトリの初期化

### Bunの環境構築
`bun init`
今回はソースコードのエントリポイントは`src/index.tsx`としました。

### Depsのインストール
`bun add react react-dom @types/react @types/react-dom @types/web`
必要なパッケージをインストールします。たったこれだけで一応Reactが動きます。

### 名前空間の設定
`document`のようなブラウザの名前空間はBunには存在しないので、`@types/web`をインストールして、`tsconfig.json`の"types"に付け加える必要があります。

## 最低限のコードを書く

まず、以下のようにシンプルな形でスクリプトのエントリポイントを作ります。
なんのライブラリも導入せずに突然タグをぶち込んでいますが、大丈夫です。Bunのバンドラーは標準でJSXをサポートしています。

```tsx:src/index.tsx
import { StrictMode } from "react"
import { createRoot } from "react-dom/client"
import { App } from "./App"

const rootElement = document.getElementById("root")! // これが取得できなければエラーで止まるべき
const root = createRoot(rootElement)
root.render(
  <StrictMode>
    <App />
  </StrictMode>
)
```

`<App />`の中身は、なんの変哲もないただのReactコンポーネントです。
今回は適当に以下のようにしておきましょう。

```tsx:src/App.tsx
import { useState } from "react"

export const App = () => {
  const [cnt, setCnt] = useState(0)
  return (
    <div>
      <h1>bun!</h1>
      <button onClick={() => setCnt((prev) => prev + 1)}>count: {cnt}</button>
    </div>
  )
}
```

はい、素晴らしいSPAの完成です！

## 試しにビルドしてみる
早速ビルドしてみましょう。

```bash
% bun build ./src/index.tsx --outdir ./build
```

やったー！完成した！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730661/95ba097f-9b52-3f0b-e4b8-40e948da0cc0.png)

Minifyされていなかったり、Development BuildのReactが出力されていたりしますが、後で修正しましょう。

## 動作チェック

`build/index.html`を作成して、今ビルドした`index.js`をアタッチしてみます。

```html:build/index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Bun-Minimal-React</title>
  </head>
  <body>
    <div id="root"></div>
    <noscript>
      JavaScript is disabled! You need JavaScript to view this page.
    </noscript>
    <script src="index.js" defer></script>
  </body>
</html>
```

`build/index.html`をローカルサーバーなりファイルをダブルクリックなりで開いてみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2730661/43ee67fe-5180-6287-928b-0b3e02f8fcc0.png)

しっかり動いていますね。なんてお手軽！！

## Production Buildしてみよう

先ほどビルドした時の画面を見てみてください。

```bash
% bun build ./src/index.tsx --outdir ./build

  ./index.js  962.62 KB

[20ms] bundle 11 modules
```

ただのカウンター機能しか実装していないのにデカバンドルができていますね。これはいただけないので、ちっちゃいバンドルを作ります。

```bash
% NODE_ENV=production bun build ./src/index.tsx --outdir ./build --minify

  ./index.js  138.29 KB

[9ms] bundle 8 modules
```

ちっちゃくなりましたね。
ビルドもたったの9msで終わっています。速い！！

## 情報は少ないけど、ポテンシャルはあるぞ

実際に何かを作りたいとなったときは、CSSヘルパーの導入やルーティングの設定など色々やることは多いと思いますが、React自体を動作させるだけだったら、たったこれだけのコードで動きます。ビルドも高速なので、手順が確立されてきたら開発体験の向上にも繋がりそうです。

今回はBunのバンドラーやトランスパイラーを使ってみましたが、他にもSQLite3 ドライバやJest互換のテストエンジンなど、Bunにはさまざまなものが搭載されています。これらのエコシステムに乗っかれば、割となんでもできそうでワクワクしますね！！誰か記事待ってます！