【Rails + Bun】Rails 7.1.0.beta1でJSのビルドにBunを試してみる

Rails 7.1.0.beta1で導入された新機能の一つに、JavaScriptのビルドツールとしてBunが追加されました。

https://rubyonrails.org/2023/9/13/Rails-7-1-0-beta-1-has-been-released

Rails 7.0のオプションに関して以前別記事にてまとめましたが、今回はこのBunを選択して試してみます。
よければこちらの記事も読んでみてください。

https://qiita.com/kyntk/items/0936598a903ac74e607d

:::note warn
執筆時点でv7.1.0はまだベータ版となっています
```bash
$ rails -v
Rails 7.1.0.beta1
```
:::

## Bunについて

Bunは先日バージョン1.0がリリースされたばかりの、新しいJavaScriptランタイムです。
Node.jsやDenoと比較しても速いことを推しています。
このBunですが、JavaScriptランタイムだけでなく、bundlerやパッケージマネージャー、テストといった様々な機能を持っています。

https://bun.sh/

bunのインストール方法は以下を参考にします。

https://bun.sh/docs/installation

## Rails newをする

Rails v7.0.1.beta1をインストールし、 `rails new` のオプションを確認してみると、 `bun` が追加されていることがわかります。

```bash
$ rails new -h | grep javascript
  -j, --js,      [--javascript=JAVASCRIPT]
    # Choose JavaScript approach [options: importmap (default), bun, webpack, esbuild, rollup]
```

とにかくアプリケーションを作成します。

```bash
rails new -j bun sample_app
```

一部略
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143317/00edfb4a-d07e-e177-c1b4-d93552cf178e.png)
一部略
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143317/e654ddd1-406d-2ce6-41d6-9dbadde06429.png)

bun.config.jsが作成されました。

パッケージの管理もbunを使いたいのですが、yarn installが実行され、yarn.lockが生成されてしまったので、yarn.lock、node_modulesを一旦消して、bunを使ってインストールします。

```bash
bun install
```

また、Rails newの際にforemanのインストールも行われおり、`bin/dev` を実行すると、railsが起動し、bunによるbuildも実行されます。

```bash
bin/dev
```

## tsxを使ってみる

Bunは自分でTypeScriptをJavaScriptにトランスパイルしたりせずに、TypeScriptをそのまま実行することができます。
またJSXもサポートしており、Bun内部でJSXの構文をJavaScriptに変換して実行してくれます。

https://bun.sh/docs/runtime/typescript

https://bun.sh/docs/runtime/jsx

なので、とにかく動かしてみます。

まずはReactをインストールします。

```bash
bun add react react-dom
```

devDependenciesは `-d`をつけます。

```bash
bun add -d @types/react @types/react-dom
```

そして適当なcontroller, viewファイルを作成し

```html:app/views/home/index.html.erb
<div id="root"></div>
```

JSを実装していきます。

```jsx:app/javascript/controllers/index.js
import React from 'react'
import ReactDOM from 'react-dom/client'
import { App } from './App'

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
)
```

```tsx:app/javascript/controllers/App.tsx
import { useState } from 'react'

export const App = () => {
  const [count, setCount] = useState(0)

  return (
    <div>
      <p>Hello Bun!</p>
      <p>
        <button type='button' onClick={() => setCount((count) => count + 1)}>
          count is: {count}
        </button>
      </p>
    </div>
  )
}
```

何も設定を書き換えずに、TSXを動かすことができました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143317/1c70a6b0-fa45-12d6-be24-47fb7da85abc.png)

## おわりに

`assets:precompile`でBunを組み合わせられることがわかりました。

またRails 7.1からは、Dockerを使って手軽にRailsアプリをデプロイできるツール [Kamal](https://kamal-deploy.org/) を使ってデプロイできるように、Dockerfileをgenerateするようになっています。
このDockerfileにもbunのインストールがされるようになっていました。

個人的には、現時点ではRailsでBunを使う必要性をあまり感じていないので、使う機会はやってくるのだろうか?と感じています。

## Ref

https://rubyonrails.org/2023/9/15/this-week-in-rails

https://rubyonrails.org/2023/9/13/Rails-7-1-0-beta-1-has-been-released

https://github.com/rails/jsbundling-rails/pull/167