umma.dev

JSX without React with Bun

Install Bun

Bun can be installed in a number of different ways.

  • Homebrew: brew install oven-sh/bun/bun
  • NPM: npm install -g bun
  • MacOS:
curl -fsSL https://bun.sh/install | bash # for macOS, Linux, and WSL
# to install a specific version
curl -fsSL https://bun.sh/install | bash -s "bun-v1.2.9"

Directory Set Up

mkdir bun-jsx-project
cd bun-jsx-project
# create a package.json file
bun init -y

Create a bunfig.toml file:

[compiler]
jsx = "automatic"
jsxFactory = "h"       # Custom JSX factory function
jsxFragmentFactory = "Fragment"

Project Structure

β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ components/
β”‚   β”‚   └── Greeting.jsx
β”‚   β”œβ”€β”€ index.jsx
β”œβ”€β”€ public/
β”‚   └── index.html
β”œβ”€β”€ server.js
β”œβ”€β”€ bunfig.toml
└── package.json

Set Up Server and Bun Commands

Create the server.js file and add the following code:

const server = Bun.serve({
  port: 3000,
  async fetch(req) {
    const url = new URL(req.url);
    const path = url.pathname;

    // Serve static files from "public" folder
    if (path === "/") {
      return new Response(Bun.file("./public/index.html"));
    }

    // Serve transpiled JSX for development
    if (path === "/dist/index.js") {
      const buildResult = await Bun.build({
        entrypoints: ["./src/index.jsx"], // Main entry point for JSX
        target: "browser",
      });
      return new Response(buildResult.outputs[0], {
        headers: { "Content-Type": "application/javascript" },
      });
    }

    // Handle 404s for unknown paths
    return new Response("Not Found", { status: 404 });
  },
});

console.log(
  `πŸš€ Development server running at http://${server.hostname}:${server.port}`
);

Create a JSX component

Create a public folder with an index.html file inside of it.

<!DOCTYPE html>
<html>
  <head>
    <script type="module" src="/dist/index.js"></script>
  </head>
  <body></body>
</html>

You’re going to need to create a /src folder and a corresponding /src/index.jsx file for the templating.

import { Greeting } from "./components/Greeting";

// JSX-to-DOM rendering function
function h(type, props, ...children) {
  const el = document.createElement(type);
  Object.entries(props || {}).forEach(([key, val]) => {
    el[key] = val;
  });
  el.append(...children.flat());
  return el;
}

// Render component
document.body.appendChild(<Greeting name="Test" />);

Now you can create your component. Create a folder with the source folder, the path should be something like /src/components/Greeting.jsx

export function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;
}

Compile and Run

Your package.json file should look as follows:

{
  "scripts": {
    "dev": "bun run server.js",
    "build": "bun build ./src/index.jsx --outdir ./dist --target browser"
  }
}

bun run dev

Build

bun run build