Bun.serve: Is Bun the New Vite for Web Development?

In the fast-paced world of web development, new tools and frameworks are constantly emerging, promising to improve developer experience and performance. One such tool that has been generating significant buzz is Bun. Known for its speed and comprehensive toolkit, Bun now introduces Bun.serve, a feature that has developers wondering: Is Bun the new Vite?

In this blog post, we'll dive into Bun.serve and explore its capabilities by recreating the examples demonstrated in the video. We'll see how Bun handles serving static HTML, CSS, integrates with Tailwind CSS, supports React, and even allows for creating API endpoints, all within a single, efficient runtime.

Serving Basic HTML with Bun

Let's start with the simplest scenario: serving a basic HTML file. Bun makes this incredibly straightforward. First, create an index.html file with the following content:

<!DOCTYPE html>
<html>
<head>
    <style>
        body { background: black; color: white; }
    </style>
</head>
<body>
    <h1>Hello World!</h1>
</body>
</html>

This is a standard HTML file with inline CSS to render white text on a black background with a "Hello World!" heading. To serve this with Bun, simply run the following command in your terminal within the same directory:

bun index.html

Bun instantly spins up a server and makes your index.html accessible in your browser at http://localhost:3000. It's incredibly fast and requires no configuration!

Serving External CSS Files

Modern web development often involves external stylesheets for better organization and maintainability. Let's see how Bun handles this. Create an index.css file with the following CSS:

body {
  background: black;
  color: white;
}

Now, link this CSS file to your index.html:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="index.css">
</head>
<body>
    <h1>Hello World!</h1>
</body>
</html>

Run bun index.html again, and Bun seamlessly serves your HTML with the external CSS applied. This demonstrates Bun's ability to handle static assets effortlessly.

Integrating Tailwind CSS

Tailwind CSS is a popular utility-first CSS framework that significantly speeds up styling. Bun also makes it easy to integrate Tailwind. First, you'll need to add the bun-plugin-tailwind plugin. Create a bunfig.toml file in your project root:

[serve.static]
plugins = ["bun-plugin-tailwind"]

Next, modify your index.css to import Tailwind directives:

@import "tailwindcss/css";

Finally, update your index.html to use Tailwind utility classes:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="index.css">
</head>
<body class="p-5 bg-black text-white text-2xl">
    <h1 class="text-3xl font-bold">Hello World!</h1>
</body>
</html>

Run bun index.html once more, and you'll see Tailwind CSS styles applied. Bun handles the processing and serving of Tailwind CSS without any complex setup.

React Integration with Bun

For dynamic web applications, frameworks like React are essential. Bun is designed to work seamlessly with React. Let's create a simple React component. First, create a src folder and inside it, create index.tsx with the following React code:

import { createRoot } from 'react-dom/client';
 
function App() {
  return (
    <div >
      <h1 className="text-3xl font-bold">Hello World From React!</h1>
    </div>
  );
}
 
createRoot(document.getElementById('root')!).render(<App />);

This is a basic React component that renders "Hello World From React!". Now, update your index.html to include a root element and load the React component:

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="index.css">
</head>
<body class="p-5 bg-black text-white text-2xl">
    <div id="root"></div>
    <script type="module" src="./src/index.tsx"></script>
</body>
</html>

Running bun index.html will now render your React application. Bun handles JSX compilation and module bundling behind the scenes, making React development with Bun incredibly easy.

Creating API Endpoints with Bun.serve

One area where Bun truly shines compared to static site servers like Vite is its ability to create and serve API endpoints directly. Let's demonstrate this. Create a server.ts file with the following server code:

import index from "./index.html";
 
const server = Bun.serve({
  static: {
    "/": index,
  },
  async fetch(req) {
    const path = new URL(req.url).pathname;
    if (path === "/api/names") {
      return Response.json(["Jack", "Jill", "John"]);
    }
    return new Response("hello world");
  },
  port: 3000,
});
 
console.log(`Listening on http://${server.hostname}:${server.port}`);
 
export default server;

This code imports our index.html to serve as static content. It then defines a fetch function within Bun.serve. This function intercepts requests and checks the pathname. If the path is /api/names, it returns a JSON response with a list of names. Otherwise, it defaults to serving "hello world".

Run this server with:

bun server.ts

Now, if you navigate to http://localhost:3000/api/names in your browser, you'll see the JSON response:

["Jack", "Jill", "John"]

This demonstrates Bun's capability to function as a full-fledged web server, serving both static assets and dynamic API endpoints.

To make our React application utilize this API, update src/index.tsx to fetch and display the names:

import { createRoot, useEffect, useState, Suspense, cache, use } from 'react-dom/client';
 
const fetchNames = cache(() => fetch("/api/names").then(res => res.json()));
 
function Names({ namesPromise } : { namesPromise: Promise<string[]> } ) {
  const names = use(namesPromise);
  return (
    <ul>
      {names.map((name) => (
        <li key={name}>{name}</li>
      ))}
    </ul>
  );
}
 
 
function App() {
  return (
    <div >
      <h1 className="text-3xl font-bold">Names</h1>
      <Suspense fallback={<div>Loading...</div>}>
        <Names namesPromise={fetchNames()} />
      </Suspense>
    </div>
  );
}
 
createRoot(document.getElementById('root')!).render(<App />);

Run bun server.ts again, and now your React app will fetch and display the names from the /api/names endpoint. This showcases a complete front-end and back-end setup powered by Bun.

Bun vs. Vite: A New Contender?

While Vite is excellent for frontend development and excels at fast builds and hot reloading, it primarily focuses on serving static assets. Bun, with Bun.serve, offers a more comprehensive solution. It can handle everything Vite does, but crucially, it also integrates backend functionalities like API endpoints directly into the runtime.

This makes Bun a compelling option for developers who want a unified toolchain for both frontend and backend development, especially for smaller projects or prototypes where setting up a separate backend might feel like overkill.

Key Takeaways:

  • Simplicity and Speed: Bun's Bun.serve is incredibly easy to use and fast.
  • Static and Dynamic: Bun seamlessly serves static HTML, CSS, and JavaScript, while also enabling dynamic API endpoint creation.
  • React and Tailwind Ready: Bun offers excellent integration with popular frontend technologies like React and Tailwind CSS.
  • Unified Toolchain: Bun has the potential to simplify web development by providing a single runtime for both frontend and backend tasks.

Is Bun the new Vite? It's still early days, but Bun's Bun.serve is definitely a powerful feature that positions it as a strong contender in the web development landscape. For projects that benefit from a simplified, all-in-one toolchain, Bun is certainly worth exploring.

Let us know in the comments below what you think about Bun and Bun.serve! Will it become your new go-to tool for web development?