🥟

Bun がフロントエンド開発でかなり便利になりそう

2025/02/06に公開
5

皆さんご存知の JavaScript ランタイム兼開発ツールの Bun が、v1.2.3 でフロントエンド開発のための便利な機能が使えるようになったので取り急ぎ。

現時点(2025/02/06)では Canary build なので試す方は以下のコマンドを実行してください。

bun upgrade --canary

Bun でビルドした実際に動作する React + Tailwind CSS の SPA の URL を貼っておきます。

https://harumaxy.github.io/bun-as-bundler
(repo: https://github.com/harumaxy/bun-as-bundler)

開発サーバー機能

bun コマンドで引数に HTML ファイルを指定すると、開発サーバーが立ち上がります。

touch index.html
index.html
<html>
  <body>
    Hello world
  </body>
</html>
bun index.html
# ➜ http://localhost:3000/

バンドラー

CSS, JavaScript などのモジュールを HTML ファイルにバンドルすることが出来ます。

Tailwind CSS を使う

まず Tailwind CSS を試してみます。
package.json を初期化して、 bun-plugin-tailwind をインストールします。

bun init -y
bun add -D bun-plugin-tailwind

# 必要なファイルを作成
touch bunfig.toml style.css

bunfig.toml にプラグインを使う設定を書き、Tailwind をインポートした CSS を用意して head タグ内でロードします。

bunfig.toml
[serve.static]
plugins = ["bun-plugin-tailwind"]
style.css
@import "tailwindcss";
index.html
...
+ <head>
+   <link rel="stylesheet" type="text/css" href="./style.css" />
+ </head>

+ <body class="bg-slate-600 flex items-center justify-center">
+   <div class="text-3xl font-bold text-lime-400">
+     This is tailwind styled text
    </div>
  </body>
...

そして、開発サーバーを立ててページを開くと Tailwind CSS のスタイルが適用されています。

UIフレームワークを使う (React)

まずは NPM パッケージをインストール。

bun add react react-dom
bun add -D @types/react @types/react-dom

簡単な React コンポーネントを src/index.tsx ファイルに書きます。

index.tsx
import * as React from "react";
import { createRoot } from "react-dom/client";

function App() {
  const [spin, setSpin] = React.useState(false);
  return (
    <div>
      <h1 className={`${spin ? "animate-spin" : ""} text-rose-400`}>
        Hello from React
      </h1>
      <button
        className="bg-indigo-400 text-white rounded-md p-2"
        onClick={() => setSpin(!spin)}>
          Toggle Spin
      </button>
    </div>
  );
}

createRoot(document.getElementById("app")!).render(<App />);

そして、 HTML ファイルの <script> タグで相対パス指定するだけで読み込む事ができます。

index.html
...
  <body class="bg-slate-600 flex items-center justify-center">
    <div class="text-3xl font-bold text-lime-400">
      This is tailwind styled text
+     <div id="app"></div>
    </div>

+   <script src="./src/index.tsx"></script>
  </body>
...

React を簡単に使用することが出来ました!
(他のライブラリ・フレームワークも同様に可能)

SPA をビルドする

とりあえず React + Tailwind を使った Single Page Application を開発するボイラープレートが出来たので、これらを静的な HTML+CSS+JavaScript にバンドルしてみます。

通常は bun build index.html でもできるのですが、 Tailwind を使用しているため、ビルドスクリプトを書くことでプラグインを適用しつつバンドルします。

touch build.ts
build.ts
import BunPluginTailwind from "bun-plugin-tailwind"

await Bun.build({
  entrypoints: ["index.html"],
  outdir: "dist",
  plugins: [BunPluginTailwind]
})
bun run build.ts

# HTMLファイルを serve して確認 -> http://localhost:3000
bunx serve dist 

余談: MPA ビルド

最近は React Router とかで SPA でも疑似 Multi Page Application ができるためあまり需要はないかもしれませんが、 bun <entrypoints...> の引数に複数のファイルを渡すことで MPA 開発もできます。

bun index.html about.html blog.html

# ➜ http://localhost:3000/
Routes:
  ├── / → index.html
  ├── /about → about.html
  └── /blog → blog.html

ビルドも同様に、 entrypoints として HTML ファイルを複数渡せます。

bun build index.html about.html blog.html --outdir dist

Web サーバーから配信する (+ バックエンドAPI実装)

Bun では HTML ファイルをモジュールとしてインポート可能です。
Bun.serve() API の static ルートとして設定することで、バンドルした HTML ファイルを Web サーバーから配信することが出来ます。(詳しくはここ

また、 Web 標準の fetch メソッド(Request を引数にして Response を返す)で HTTP リクエストを処理することも出来ます。

Hono など、Bun と同様に Web 標準に準拠した fetch メソッドを提供するサーバーフレームワークを組み込むことも可能です。

src/server.ts
import index from "../index.html";  // HTML インポートが可能
import about from "../about.html";
import { Hono } from "hono";

const honoApp = new Hono();

honoApp.get("/hono", (c) => c.text("This is Hono response"));

Bun.serve({
  development: true,  // リクエストのたびにリビルドするなど。開発時に便利。
  static: {  // バンドルした静的 HTML ページを配信する
    "/": index,
    "/about": about,
  },
  async fetch(req) {
    const url = new URL(req.url);

    // Hono アプリでリクエストをハンドル
    if (url.pathname === "/hono") {
      return honoApp.fetch(req);
    }

    // Web 標準的の Response オブジェクトを返すことも可能
    return new Response("This is default response");
  },
});

console.log("Server is running on http://localhost:3000");

フロントエンドとバックエンドを同時に開発できて、一挙両得ですね。

Bun のフロントエンド開発機能で足りないもの

  • ホットリロード
  • プラグインの不足
  • CORS やヘッダーの設定
    • etc...

これらの機能はまだ work in progress らしいです。将来的には提供されると思います。
将来的には Vite などを置き換える選択肢となって、Bun 以外の依存を必要とせずフロントエンド開発ができるようになるかもしれません。

参考

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

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

https://www.youtube.com/watch?app=desktop&v=NvitRPQqaSs

GitHubで編集を提案

Discussion

ピン留めされたアイテム
Naoki IwataNaoki Iwata

Canary build なら下記のコマンドでないと v1.2.3にアップデートできないです。

bun upgrade --canary
submaxsubmax

追記させていただきました。
うっかり、書き忘れてました...

ご指摘ありがとうございます!

ryoppippiryoppippi

bunfig.tomlにプラグインを指定することで bun build index.htmlでもビルドできると思います!

submaxsubmax

試したけど、駄目でした...
現状、bunfig の項目でプラグイン指定できそうなのが [serve.static].plugins だけですね。

ビルド時にプラグインを適用するには、今のところは Bun.build() API をスクリプトで呼び出すしかなさそうです(自分が他の方法を知らないだけかもですが)

ryoppippiryoppippi

本当ですね!手元でpreload.tsを作って読み込ませたりしたのですが動きませんね
これはissueにするべきかもしれません。教えていただきありがとうございます。