关于 bun-dev-server
bun-dev-server 是使用 Bun.serve 配置开发服务器的技能,适用于 React、API、全栈应用和静态文件服务,并涵盖 HMR 与 React Fast Refresh 设置。
主要功能
- 01选择服务器类型
- 02配置 React HMR
- 03配置 Hono API 服务
- 04设置环境与脚本
- 05配置 HTTPS 和 API 代理
- 06排查常见问题
适用场景
- 01创建 React 开发服务器
- 02设置可自动重载的 API 服务
- 03在同一服务中组合前端与 API
- 04将 API 请求代理到现有后端
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ daleseo/ bun-skills --skill bun-dev-server安装后在 Claude Code 中输入/bun-dev-server确认已加载。
附带文件references/hmr-examples.md
详细介绍
Bun 开发服务器设置
你正在协助使用 Bun.serve 设置高性能开发服务器,并启用热模块替换(HMR)和 React Fast Refresh。
工作流
1. 确定服务器类型
询问用户需要哪种类型的开发服务器:
- React/前端应用:支持 React Fast Refresh 的 SPA
- API 服务器:支持自动重新加载的 REST/GraphQL API
- 全栈应用:前端与 API 合并
- 静态服务器:支持实时重新加载的文件服务器
2. 检查先决条件
# Verify Bun installation
bun --version
# Check if project has package.json
ls -la package.json
如果不存在 package.json,建议先运行 bun init。
3. 安装依赖
对于 React 应用:
bun add react react-dom
bun add -d @types/react @types/react-dom
对于使用 Hono 的 API(推荐):
bun add hono
对于全栈应用:
bun add react react-dom hono
bun add -d @types/react @types/react-dom
4. 创建服务器配置
React 开发服务器
在项目根目录创建 server.ts:
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" }));
}
}
}
创建 public/index.html:
<!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>
<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>
创建 src/index.tsx:
import { render } from 'react-dom';
import App from './App';
const root = document.getElementById('root');
render(<App />, root);
创建 src/App.tsx:
export default function App() {
return (
<div>
<h1>Welcome to Bun + React!</h1>
<p>Edit src/App.tsx to see HMR in action</p>
</div>
);
}
使用 Hono 的 API 服务器
创建 server.ts:
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.ts:
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}`);
5. 配置 React Fast Refresh(高级)
如需实现真正的 React Fast Refresh,创建 hmr-runtime.ts:
// 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();
});
}
6. 环境配置
创建 .env.development:
# Server
PORT=3000
NODE_ENV=development
# API
API_URL=http://localhost:3000/api
# Features
ENABLE_HMR=true
创建 .env.production:
# Server
PORT=8080
NODE_ENV=production
# API
API_URL=https://api.example.com
# Features
ENABLE_HMR=false
在 server.ts 中加载环境变量:
// Environment is loaded automatically by Bun
const isDev = process.env.NODE_ENV === 'development';
const port = process.env.PORT || 3000;
7. 更新 package.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. 配置 TypeScript
更新 tsconfig.json:
{
"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. 创建项目结构
生成完整的项目结构:
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
10. 高级:本地开发使用 HTTPS
如需支持 HTTPS(某些浏览器 API 需要):
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}`);
使用以下命令生成证书:
# Install mkcert first: brew install mkcert
mkcert -install
mkcert localhost 127.0.0.1 ::1
11. 代理配置(用于现有后端)
如果用户需要将 API 请求代理到另一台服务器:
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,
});
});
测试设置
创建完成后,引导用户进行测试:
# 1. Start dev server
bun run dev
# 2. Open browser
open http://localhost:3000
# 3. Make a change to src/App.tsx
# 4. Verify HMR reloads the page
# 5. Test API endpoints
curl http://localhost:3000/api/health
故障排除
HMR 无法正常工作
// 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 flag
端口已被占用
# Find process using port 3000
lsof -ti:3000
# Kill the process
kill -9 $(lsof -ti:3000)
# Or use a different port
PORT=3001 bun run dev
CORS 问题
为服务器添加 CORS 标头:
app.use('*', cors({
origin: 'http://localhost:3000',
credentials: true,
}));
性能提示
- 开发时使用 --hot:在大多数情况下比 --watch 更快
- 缩小文件监视范围:仅监视 src/ 目录
- 使用 HTTP/2:启用以加快并行加载
- 缓存静态资源:添加 Cache-Control 标头
app.use('/assets/*', async (c, next) => {
await next();
c.header('Cache-Control', 'public, max-age=31536000');
});
完成清单
- ✅ 已创建开发服务器
- ✅ 已配置并测试 HMR
- ✅ 已设置环境变量
- ✅ 已添加 Package.json 脚本
- ✅ 已整理项目结构
- ✅ 已配置 TypeScript
- ✅ 浏览器已成功连接
- ✅ 文件更改会触发重新加载
后续步骤
建议用户:
- 添加错误边界,以更好地处理错误
- 设置 ESLint 和 Prettier
- 在 tsconfig.json 中配置路径别名
- 添加开发与生产构建
- 考虑添加 bun-test 进行测试
评论
支持 Markdown