bun-dev-server
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseBun Development Server Setup
Bun开发服务器搭建
You are assisting with setting up a high-performance development server using Bun.serve with Hot Module Replacement (HMR) and React Fast Refresh.
本文将协助你使用Bun.serve搭建支持热模块替换(HMR)和React Fast Refresh的高性能开发服务器。
Workflow
操作流程
1. Determine Server Type
1. 确定服务器类型
Ask the user what type of development server they need:
- React/Frontend App: SPA with React Fast Refresh
- API Server: REST/GraphQL API with auto-reload
- Full-Stack App: Frontend + API combined
- Static Server: File server with live reload
询问用户所需的开发服务器类型:
- React/前端应用:支持React Fast Refresh的单页应用(SPA)
- API服务器:支持自动重载的REST/GraphQL API
- 全栈应用:前端+API组合服务器
- 静态服务器:支持实时重载的文件服务器
2. Check Prerequisites
2. 检查前置条件
bash
undefinedbash
undefinedVerify Bun installation
验证Bun安装情况
bun --version
bun --version
Check if project has package.json
检查项目是否存在package.json
ls -la package.json
If no package.json exists, suggest running `bun init` first.ls -la package.json
若不存在package.json,建议先执行`bun init`初始化项目。3. Install Dependencies
3. 安装依赖
For React Apps:
bash
bun add react react-dom
bun add -d @types/react @types/react-domFor API with Hono (recommended):
bash
bun add honoFor Full-Stack:
bash
bun add react react-dom hono
bun add -d @types/react @types/react-domReact应用所需依赖:
bash
bun add react react-dom
bun add -d @types/react @types/react-dom使用Hono的API服务器(推荐):
bash
bun add hono全栈应用所需依赖:
bash
bun add react react-dom hono
bun add -d @types/react @types/react-dom4. Create Server Configuration
4. 创建服务器配置
React Development Server
React开发服务器
Create in the project root:
server.tstypescript
import type { ServerWebSocket } from "bun";
const clients = new Set<ServerWebSocket<unknown>>();
const server = Bun.serve({
port: 3000,
async fetch(request, server) {
const url = new URL(request.url);
// WebSocket for HMR
if (url.pathname === "/_hmr") {
const upgraded = server.upgrade(request);
if (upgraded) return undefined;
return new Response("WebSocket upgrade failed", { status: 500 });
}
// Serve index.html for SPA routing
if (url.pathname === "/" || !url.pathname.includes(".")) {
return new Response(
Bun.file("public/index.html"),
{ headers: { "Content-Type": "text/html" } }
);
}
// Serve static files
const filePath = `public${url.pathname}`;
const file = Bun.file(filePath);
if (await file.exists()) {
return new Response(file);
}
return new Response("Not Found", { status: 404 });
},
websocket: {
open(ws) {
clients.add(ws);
console.log("HMR client connected");
},
close(ws) {
clients.delete(ws);
console.log("HMR client disconnected");
},
message(ws, message) {
// Handle client messages if needed
},
},
});
console.log(`🚀 Dev server running at http://localhost:${server.port}`);
// Watch for file changes
const watcher = Bun.file.watch(import.meta.dir + "/src", {
recursive: true,
});
for await (const event of watcher) {
if (event.kind === "change" && event.path.endsWith(".tsx")) {
console.log(`📝 File changed: ${event.path}`);
// Notify all connected clients to reload
for (const client of clients) {
client.send(JSON.stringify({ type: "reload" }));
}
}
}Create :
public/index.htmlhtml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bun + React App</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
<!-- HMR Client -->
<script>
const ws = new WebSocket('ws://localhost:3000/_hmr');
ws.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.type === 'reload') {
console.log('🔄 Reloading...');
window.location.reload();
}
});
ws.addEventListener('close', () => {
console.log('❌ HMR connection lost. Reconnecting...');
setTimeout(() => window.location.reload(), 1000);
});
</script>
</body>
</html>Create :
src/index.tsxtypescript
import { render } from 'react-dom';
import App from './App';
const root = document.getElementById('root');
render(<App />, root);Create :
src/App.tsxtypescript
export default function App() {
return (
<div>
<h1>Welcome to Bun + React!</h1>
<p>Edit src/App.tsx to see HMR in action</p>
</div>
);
}在项目根目录创建:
server.tstypescript
import type { ServerWebSocket } from "bun";
const clients = new Set<ServerWebSocket<unknown>>();
const server = Bun.serve({
port: 3000,
async fetch(request, server) {
const url = new URL(request.url);
// 用于HMR的WebSocket
if (url.pathname === "/_hmr") {
const upgraded = server.upgrade(request);
if (upgraded) return undefined;
return new Response("WebSocket升级失败", { status: 500 });
}
// 为SPA路由提供index.html
if (url.pathname === "/" || !url.pathname.includes(".")) {
return new Response(
Bun.file("public/index.html"),
{ headers: { "Content-Type": "text/html" } }
);
}
// 提供静态文件
const filePath = `public${url.pathname}`;
const file = Bun.file(filePath);
if (await file.exists()) {
return new Response(file);
}
return new Response("未找到资源", { status: 404 });
},
websocket: {
open(ws) {
clients.add(ws);
console.log("HMR客户端已连接");
},
close(ws) {
clients.delete(ws);
console.log("HMR客户端已断开连接");
},
message(ws, message) {
// 按需处理客户端消息
},
},
});
console.log(`🚀 开发服务器运行于 http://localhost:${server.port}`);
// 监听文件变化
const watcher = Bun.file.watch(import.meta.dir + "/src", {
recursive: true,
});
for await (const event of watcher) {
if (event.kind === "change" && event.path.endsWith(".tsx")) {
console.log(`📝 文件已修改: ${event.path}`);
// 通知所有连接的客户端重载
for (const client of clients) {
client.send(JSON.stringify({ type: "reload" }));
}
}
}创建:
public/index.htmlhtml
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bun + React应用</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
<!-- HMR客户端 -->
<script>
const ws = new WebSocket('ws://localhost:3000/_hmr');
ws.addEventListener('message', (event) => {
const data = JSON.parse(event.data);
if (data.type === 'reload') {
console.log('🔄 正在重载...');
window.location.reload();
}
});
ws.addEventListener('close', () => {
console.log('❌ HMR连接已丢失,正在重新连接...');
setTimeout(() => window.location.reload(), 1000);
});
</script>
</body>
</html>创建:
src/index.tsxtypescript
import { render } from 'react-dom';
import App from './App';
const root = document.getElementById('root');
render(<App />, root);创建:
src/App.tsxtypescript
export default function App() {
return (
<div>
<h1>欢迎使用Bun + React!</h1>
<p>修改src/App.tsx即可体验HMR功能</p>
</div>
);
}API Server with Hono
基于Hono的API服务器
Create :
server.tstypescript
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
const app = new Hono();
// Middleware
app.use('*', cors());
app.use('*', logger());
// Routes
app.get('/', (c) => {
return c.json({ message: 'Welcome to Bun API' });
});
app.get('/api/health', (c) => {
return c.json({ status: 'ok', timestamp: Date.now() });
});
// Example POST endpoint
app.post('/api/users', async (c) => {
const body = await c.req.json();
return c.json({ created: true, data: body }, 201);
});
// Start server
const server = Bun.serve({
port: process.env.PORT || 3000,
fetch: app.fetch,
});
console.log(`🚀 API server running at http://localhost:${server.port}`);创建:
server.tstypescript
import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { logger } from 'hono/logger';
const app = new Hono();
// 中间件
app.use('*', cors());
app.use('*', logger());
// 路由
app.get('/', (c) => {
return c.json({ message: '欢迎使用Bun API' });
});
app.get('/api/health', (c) => {
return c.json({ status: 'ok', timestamp: Date.now() });
});
// 示例POST接口
app.post('/api/users', async (c) => {
const body = await c.req.json();
return c.json({ created: true, data: body }, 201);
});
// 启动服务器
const server = Bun.serve({
port: process.env.PORT || 3000,
fetch: app.fetch,
});
console.log(`🚀 API服务器运行于 http://localhost:${server.port}`);Full-Stack Server
全栈服务器
Create :
server.tstypescript
import { Hono } from 'hono';
import { serveStatic } from 'hono/bun';
const app = new Hono();
// API routes
const api = new Hono();
api.get('/health', (c) => c.json({ status: 'ok' }));
api.get('/users', (c) => c.json({ users: [] }));
app.route('/api', api);
// Serve static files
app.use('/*', serveStatic({ root: './public' }));
// SPA fallback
app.get('*', (c) => c.html(Bun.file('public/index.html')));
const server = Bun.serve({
port: 3000,
fetch: app.fetch,
});
console.log(`🚀 Full-stack server at http://localhost:${server.port}`);创建:
server.tstypescript
import { Hono } from 'hono';
import { serveStatic } from 'hono/bun';
const app = new Hono();
// API路由
const api = new Hono();
api.get('/health', (c) => c.json({ status: 'ok' }));
api.get('/users', (c) => c.json({ users: [] }));
app.route('/api', api);
// 提供静态文件
app.use('/*', serveStatic({ root: './public' }));
// SPA fallback
app.get('*', (c) => c.html(Bun.file('public/index.html')));
const server = Bun.serve({
port: 3000,
fetch: app.fetch,
});
console.log(`🚀 全栈服务器运行于 http://localhost:${server.port}`);5. Configure React Fast Refresh (Advanced)
5. 配置React Fast Refresh(进阶)
For true React Fast Refresh, create :
hmr-runtime.tstypescript
// React Fast Refresh runtime
let timeout: Timer | null = null;
export function refresh() {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
// Re-import the App component
import('./App.tsx?t=' + Date.now()).then((module) => {
const { render } = require('react-dom');
const root = document.getElementById('root');
render(module.default(), root);
});
}, 100);
}
// Listen for HMR events
if (import.meta.hot) {
import.meta.hot.accept(() => {
refresh();
});
}如需实现真正的React Fast Refresh,创建:
hmr-runtime.tstypescript
// React Fast Refresh运行时
let timeout: Timer | null = null;
export function refresh() {
if (timeout) clearTimeout(timeout);
timeout = setTimeout(() => {
// 重新导入App组件
import('./App.tsx?t=' + Date.now()).then((module) => {
const { render } = require('react-dom');
const root = document.getElementById('root');
render(module.default(), root);
});
}, 100);
}
// 监听HMR事件
if (import.meta.hot) {
import.meta.hot.accept(() => {
refresh();
});
}6. Environment Configuration
6. 环境配置
Create :
.env.developmentbash
undefined创建:
.env.developmentbash
undefinedServer
服务器配置
PORT=3000
NODE_ENV=development
PORT=3000
NODE_ENV=development
API
API配置
API_URL=http://localhost:3000/api
API_URL=http://localhost:3000/api
Features
功能开关
ENABLE_HMR=true
Create `.env.production`:
```bashENABLE_HMR=true
创建`.env.production`:
```bashServer
服务器配置
PORT=8080
NODE_ENV=production
PORT=8080
NODE_ENV=production
API
API配置
API_URL=https://api.example.com
API_URL=https://api.example.com
Features
功能开关
ENABLE_HMR=false
Load environment in `server.ts`:
```typescript
// Environment is loaded automatically by Bun
const isDev = process.env.NODE_ENV === 'development';
const port = process.env.PORT || 3000;ENABLE_HMR=false
在`server.ts`中加载环境变量:
```typescript
// Bun会自动加载环境变量
const isDev = process.env.NODE_ENV === 'development';
const port = process.env.PORT || 3000;7. Update package.json Scripts
7. 更新package.json脚本
Add development scripts:
json
{
"scripts": {
"dev": "bun run --hot server.ts",
"dev:watch": "bun run --watch server.ts",
"start": "NODE_ENV=production bun run server.ts",
"build": "bun build src/index.tsx --outdir=dist --minify",
"clean": "rm -rf dist"
}
}Script explanations:
- : Run with hot reload (restarts on file changes)
dev - : Watch mode (faster, but doesn't reload on crash)
dev:watch - : Production mode
start - : Build frontend for production
build
添加开发相关脚本:
json
{
"scripts": {
"dev": "bun run --hot server.ts",
"dev:watch": "bun run --watch server.ts",
"start": "NODE_ENV=production bun run server.ts",
"build": "bun build src/index.tsx --outdir=dist --minify",
"clean": "rm -rf dist"
}
}脚本说明:
- : 启用热重载运行服务器(文件变化时重启)
dev - : 监听模式运行(速度更快,但崩溃后不会自动重启)
dev:watch - : 生产模式运行
start - : 构建生产环境前端代码
build
8. Configure TypeScript
8. 配置TypeScript
Update :
tsconfig.jsonjson
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"types": ["bun-types"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"allowImportingTsExtensions": true,
"noEmit": true,
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src/**/*", "server.ts"]
}更新:
tsconfig.jsonjson
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"types": ["bun-types"],
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"allowImportingTsExtensions": true,
"noEmit": true,
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src/**/*", "server.ts"]
}9. Create Project Structure
9. 创建项目结构
Generate complete project structure:
project/
├── server.ts # Development server
├── src/
│ ├── index.tsx # App entry point
│ ├── App.tsx # Main component
│ ├── components/ # React components
│ └── styles/ # CSS files
├── public/
│ ├── index.html # HTML template
│ └── assets/ # Static assets
├── .env.development
├── .env.production
├── package.json
├── tsconfig.json
└── README.md生成完整的项目结构:
project/
├── server.ts # 开发服务器文件
├── src/
│ ├── index.tsx # 应用入口
│ ├── App.tsx # 主组件
│ ├── components/ # React组件目录
│ └── styles/ # CSS文件目录
├── public/
│ ├── index.html # HTML模板
│ └── assets/ # 静态资源目录
├── .env.development
├── .env.production
├── package.json
├── tsconfig.json
└── README.md10. Advanced: HTTPS for Local Development
10. 进阶:本地开发启用HTTPS
For HTTPS support (needed for some browser APIs):
typescript
import { readFileSync } from 'fs';
const server = Bun.serve({
port: 3000,
tls: {
cert: readFileSync('./localhost.pem'),
key: readFileSync('./localhost-key.pem'),
},
fetch: app.fetch,
});
console.log(`🔒 HTTPS server at https://localhost:${server.port}`);Generate certificates with:
bash
undefined如需HTTPS支持(部分浏览器API需要):
typescript
import { readFileSync } from 'fs';
const server = Bun.serve({
port: 3000,
tls: {
cert: readFileSync('./localhost.pem'),
key: readFileSync('./localhost-key.pem'),
},
fetch: app.fetch,
});
console.log(`🔒 HTTPS服务器运行于 https://localhost:${server.port}`);使用以下命令生成证书:
bash
undefinedInstall mkcert first: brew install mkcert
先安装mkcert: brew install mkcert
mkcert -install
mkcert localhost 127.0.0.1 ::1
undefinedmkcert -install
mkcert localhost 127.0.0.1 ::1
undefined11. Proxy Configuration (for existing backends)
11. 代理配置(适用于已有后端服务)
If user needs to proxy API requests to another server:
typescript
const app = new Hono();
// Proxy /api requests to backend
app.all('/api/*', async (c) => {
const url = new URL(c.req.url);
const backendUrl = `http://localhost:8080${url.pathname}${url.search}`;
const response = await fetch(backendUrl, {
method: c.req.method,
headers: c.req.raw.headers,
body: c.req.method !== 'GET' ? await c.req.raw.text() : undefined,
});
return new Response(response.body, {
status: response.status,
headers: response.headers,
});
});若用户需要将API请求代理到其他服务器:
typescript
const app = new Hono();
// 将/api请求代理到后端
app.all('/api/*', async (c) => {
const url = new URL(c.req.url);
const backendUrl = `http://localhost:8080${url.pathname}${url.search}`;
const response = await fetch(backendUrl, {
method: c.req.method,
headers: c.req.raw.headers,
body: c.req.method !== 'GET' ? await c.req.raw.text() : undefined,
});
return new Response(response.body, {
status: response.status,
headers: response.headers,
});
});Testing the Setup
测试搭建结果
After creation, guide user to test:
bash
undefined搭建完成后,引导用户进行测试:
bash
undefined1. Start dev server
1. 启动开发服务器
bun run dev
bun run dev
2. Open browser
2. 打开浏览器
3. Make a change to src/App.tsx
3. 修改src/App.tsx文件
4. Verify HMR reloads the page
4. 验证HMR是否触发页面重载
5. Test API endpoints
5. 测试API接口
undefinedundefinedTroubleshooting
问题排查
HMR not working
HMR无法正常工作
typescript
// Check if WebSocket connection is established
// Open browser console and look for:
// "HMR client connected"
// If not, verify:
// 1. Port is correct
// 2. No firewall blocking WebSocket
// 3. Server is running with --hot flagtypescript
undefinedPort already in use
检查WebSocket连接是否建立
—
打开浏览器控制台,查看是否有如下日志:
—
"HMR客户端已连接"
—
若未连接,验证以下内容:
—
1. 端口配置正确
—
2. 防火墙未拦截WebSocket
—
3. 服务器使用--hot参数启动
bash
undefinedundefinedFind process using port 3000
端口已被占用
lsof -ti:3000
bash
undefinedKill the process
查找占用3000端口的进程
kill -9 $(lsof -ti:3000)
lsof -ti:3000
Or use a different port
终止该进程
PORT=3001 bun run dev
undefinedkill -9 $(lsof -ti:3000)
CORS issues
或使用其他端口
Add CORS headers to server:
typescript
app.use('*', cors({
origin: 'http://localhost:3000',
credentials: true,
}));PORT=3001 bun run dev
undefinedPerformance Tips
CORS问题
- Use --hot for development: Faster than --watch for most cases
- Minimize file watcher scope: Watch only src/ directory
- Use HTTP/2: Enable for faster parallel loading
- Cache static assets: Add Cache-Control headers
typescript
app.use('/assets/*', async (c, next) => {
await next();
c.header('Cache-Control', 'public, max-age=31536000');
});在服务器中添加CORS头:
typescript
app.use('*', cors({
origin: 'http://localhost:3000',
credentials: true,
}));Completion Checklist
性能优化建议
- ✅ Development server created
- ✅ HMR configured and tested
- ✅ Environment variables set up
- ✅ Package.json scripts added
- ✅ Project structure organized
- ✅ TypeScript configured
- ✅ Browser successfully connects
- ✅ File changes trigger reload
- 开发环境使用--hot参数:大多数情况下比--watch速度更快
- 缩小文件监听范围:仅监听src/目录
- 启用HTTP/2:提升并行加载速度
- 缓存静态资源:添加Cache-Control头
typescript
app.use('/assets/*', async (c, next) => {
await next();
c.header('Cache-Control', 'public, max-age=31536000');
});Next Steps
完成检查清单
Suggest to the user:
- Add error boundaries for better error handling
- Set up ESLint and Prettier
- Configure path aliases in tsconfig.json
- Add development vs production builds
- Consider adding bun-test for testing
- ✅ 已创建开发服务器
- ✅ 已配置并测试HMR
- ✅ 已设置环境变量
- ✅ 已添加package.json脚本
- ✅ 已整理项目结构
- ✅ 已配置TypeScript
- ✅ 浏览器已成功连接
- ✅ 文件变化可触发重载
—
后续步骤
—
向用户建议:
- 添加错误边界以优化错误处理
- 配置ESLint和Prettier
- 在tsconfig.json中设置路径别名
- 区分开发与生产构建
- 考虑添加bun-test进行测试