Elysia with Bun Fullstack Dev Server
Bun 1.3 introduce a Fullstack Dev Server with HMR support.
This allows us to directly use React without any bundler like Vite or Webpack.
You can use this example to quickly try it out.
Otherwise, install it manually:
- Install Elysia Static plugin
import { Elysia } from 'elysia'
import { staticPlugin } from '@elysiajs/static'
new Elysia()
.use(staticPlugin())
.listen(3000)
- Create public/index.html and index.tsx
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Elysia React App</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div id="root"></div>
<script type="module" src="./index.tsx"></script>
</body>
</html>
import { useState } from 'react'
import { createRoot } from 'react-dom/client'
function App() {
const [count, setCount] = useState(0)
const increase = () => setCount((c) => c + 1)
return (
<main>
<h2>{count}</h2>
<button onClick={increase}>
Increase
</button>
</main>
)
}
const root = createRoot(document.getElementById('root')!)
root.render(<App />)
- Navigate to
http://localhost:3000/public
and see the result.
This would allows us to develop frontend and backend in a single project without any bundler.
We have verified that Fullstack Dev Server works with HMR, Tailwind, Tanstack Query, Eden Treaty, and path alias.
Custom prefix path
We can change the default /public
prefix by passing the prefix
option to staticPlugin
.
import { Elysia } from 'elysia'
import { staticPlugin } from '@elysiajs/static'
new Elysia()
.use(
staticPlugin({
prefix: '/'
})
)
.listen(3000)
This would serve the static files at /
instead of /public
.
See static plugin for more configuration options.
Tailwind CSS
We can also use Tailwind CSS with Bun Fullstack Dev Server.
- Install dependencies
bun add tailwindcss@4
bun add -d bun-plugin-tailwind
- Create
bunfig.toml
with the following content:
[serve.static]
plugins = ["bun-plugin-tailwind"]
- Create a CSS file with Tailwind directives
@tailwind base;
- Add Tailwind to your HTML or alternatively JavaScript/TypeScript file
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Elysia React App</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="tailwindcss">
</head>
<body>
<div id="root"></div>
<script type="module" src="./index.tsx"></script>
</body>
</html>
import { useState } from 'react'
import { createRoot } from 'react-dom/client'
import './global.css'
function App() {
const [count, setCount] = useState(0)
const increase = () => setCount((c) => c + 1)
return (
<main>
<h2>{count}</h2>
<button onClick={increase}>
Increase
</button>
</main>
)
}
const root = createRoot(document.getElementById('root')!)
root.render(<App />)
Path Alias
We can also use path alias in Bun Fullstack Dev Server.
- Add
paths
intsconfig.json
{
"compilerOptions": {
"baseUrl": ".", // [!code +=]
"paths": { // [!code +=]
"@public/*": ["public/*"] // [!code +=]
} // [!code +=]
}
}
- Use the alias in your code
import { useState } from 'react'
import { createRoot } from 'react-dom/client'
import '@public/global.css'
function App() {
const [count, setCount] = useState(0)
const increase = () => setCount((c) => c + 1)
return (
<main>
<h2>{count}</h2>
<button onClick={increase}>
Increase
</button>
</main>
)
}
const root = createRoot(document.getElementById('root')!)
root.render(<App />)
This would works out of the box without any additional configuration.
Build for Production
You can build fullstack server as if it's a normal Elysia server.
bun build --compile --target bun --outfile server src/index.ts
This would create a single executable file server.
When running the server executable, make sure to include the public folder in similar to the development environment.
See Deploy to Production for more information.