nextjs-ws-server
v0.3.2
Published
A WebSocket server for Next.js with support for both ESM and CommonJS,update type errors.
Maintainers
Readme
Next.js WebSocket Server
这个库提供了在Next.js应用中集成WebSocket服务器的简单方法,可以运行在同一端口上。同时支持ES模块和CommonJS项目。
特点
- 🔄 WebSocket与Next.js运行在同一端口
- 🌟 完全类型化的API (TypeScript)
- 🔌 简单的接口和API
- 🌐 支持自定义消息处理程序
- 📡 全局广播功能
- 🚀 同时支持ES模块和CommonJS
- 🔄 在Next.js应用中集成WebSocket功能
- 🌟 提供独立的WebSocket服务器实现
- 🌐 支持自定义路由和处理程序
安装
npm install nextjs-ws-server
# 或者
yarn add nextjs-ws-server基本用法
ES模块方式
// server.ts
// 1. 类型导入
import type { Request, Response } from 'express';
import type { WebSocket } from 'ws';
// 2. 值导入
import express from 'express';
import { createServerWithWebSocket } from 'nextjs-ws-server';
// 创建Express应用
const app = express();
// 定义路由
app.get('/api/hello', (req: Request, res: Response) => {
res.json({ message: 'Hello from WebSocket Server!' });
});
// 创建并启动服务器
async function main() {
const server = await createServerWithWebSocket({
port: 3000,
customRoutes: app,
// 连接处理
onConnection: (ws: WebSocket) => {
console.log('Client connected');
},
// 消息处理
onMessage: (ws: WebSocket, message: string) => {
console.log('Received:', message);
ws.send(`Echo: ${message}`);
}
});
await server.start();
console.log('Server started!');
}
main().catch(console.error);CommonJS方式
// server.js
const express = require('express');
const wsServer = require('nextjs-ws-server');
// 创建Express应用
const app = express();
// 定义路由
app.get('/api/hello', (req, res) => {
res.json({ message: 'Hello from WebSocket Server!' });
});
// 创建并启动服务器
async function main() {
const server = await wsServer.createServerWithWebSocket({
port: 3000,
customRoutes: app,
// 连接处理
onConnection: (ws) => {
console.log('Client connected');
},
// 消息处理
onMessage: (ws, message) => {
console.log('Received:', message);
ws.send(`Echo: ${message}`);
}
});
await server.start();
console.log('Server started!');
}
main().catch(console.error);在Express中接管Next.js路由
您可以使用Express接管Next.js的路由处理,这样可以更灵活地管理HTTP和WebSocket请求:
// server.ts (ES Module)
import type { Request, Response } from 'express';
import type { WebSocket } from 'ws';
import express from 'express';
import { createServer } from 'http';
import next from 'next';
// 导入库提供的工具函数
import { createServerWithWebSocket } from 'nextjs-ws-server';
// 创建Next.js应用实例
const dev = process.env.NODE_ENV !== 'production';
const nextApp = next({ dev });
const nextHandler = nextApp.getRequestHandler();
const port = 3000;
async function main() {
// 准备Next.js应用
await nextApp.prepare();
// 创建Express应用
const app = express();
// 自定义API路由(优先处理)
app.get('/api/hello', (req: Request, res: Response) => {
res.json({ message: 'Hello from custom API!' });
});
// 所有其他请求交给Next.js处理 (确保这在最后)
app.all('*', (req: Request, res: Response) => {
return nextHandler(req, res);
});
// 使用createServerWithWebSocket创建集成的服务器
// 它会内部创建HTTP服务器并附加WebSocket服务器
const serverInstance = createServerWithWebSocket({
port,
customRoutes: app, // 将配置好的Express应用(包含Next.js处理器)传入
wsPath: '/ws', // 指定WebSocket路径
onConnection: (ws: WebSocket, req) => { // req 是 IncomingMessage
console.log('Client connected');
const ip = req.socket.remoteAddress || '未知IP';
ws.send(`欢迎连接, ${ip}!`);
},
onMessage: (ws: WebSocket, message: string) => {
console.log('Received:', message);
ws.send(`Echo: ${message}`);
// 使用返回实例的 broadcast 方法
serverInstance.broadcast(`广播: ${message}`);
},
onClose: (ws: WebSocket) => {
console.log('客户端连接已关闭');
},
onError: (ws: WebSocket, err: Error) => {
console.error('WebSocket错误:', err.message);
}
});
// 启动服务器 (由createServerWithWebSocket返回的实例控制)
await serverInstance.start();
console.log(`> 服务器已启动于 http://localhost:${port}`);
console.log(`> WebSocket 服务可在 ws://localhost:${port}/ws 访问`);
// 广播消息的示例 - 使用返回实例的broadcast方法
setInterval(() => {
serverInstance.broadcast('服务器时间: ' + new Date().toISOString());
}, 10000);
}
main().catch(console.error);该实现方式的优点:
- Express处理API路由和WebSocket连接
- Next.js处理页面渲染和客户端路由
- 可以轻松添加自定义中间件(如认证、日志等)
- 所有服务运行在同一端口,简化部署
执行步骤
- 将上述代码保存为项目根目录下的
server.ts文件(或server.js如果是CommonJS项目) - 确保项目中已安装所需依赖:
npm install express next ws nextjs-ws-server npm install --save-dev typescript @types/express @types/ws - 使用TypeScript编译并执行服务器:
# 对于ES模块项目 npx tsc server.ts node server.js # 对于CommonJS项目 node server.js
预期运行结果
服务器启动后,你会看到以下输出:
> Next.js应用已准备就绪
> 服务器运行在 http://localhost:3000
> WebSocket服务可在 ws://localhost:3000/ws 访问此时:
- 访问
http://localhost:3000将显示你的Next.js应用主页 - 访问
http://localhost:3000/api/hello将返回自定义API响应:{"message":"Hello from custom API!"} - 连接到
ws://localhost:3000/ws的WebSocket客户端将收到消息回显和定期的服务器时间广播
在Next.js页面中使用WebSocket
在Next.js页面组件中添加WebSocket客户端:
// pages/index.js
import { useState, useEffect, useRef } from 'react'
export default function Home() {
const [messages, setMessages] = useState([]);
const [inputValue, setInputValue] = useState('');
const socketRef = useRef(null);
useEffect(() => {
// 客户端环境下创建WebSocket连接
if (typeof window !== 'undefined') {
const socket = new WebSocket(`ws://${window.location.host}/ws`);
socket.onopen = () => {
console.log('WebSocket连接已建立');
setMessages(prev => [...prev, { type: 'system', text: '已连接到服务器' }]);
};
socket.onmessage = (event) => {
console.log('收到消息:', event.data);
setMessages(prev => [...prev, { type: 'received', text: event.data }]);
};
socket.onclose = () => {
console.log('WebSocket连接已关闭');
setMessages(prev => [...prev, { type: 'system', text: '与服务器断开连接' }]);
};
socketRef.current = socket;
// 组件卸载时关闭连接
return () => {
socket.close();
};
}
}, []);
const sendMessage = () => {
if (socketRef.current && inputValue) {
socketRef.current.send(inputValue);
setMessages(prev => [...prev, { type: 'sent', text: inputValue }]);
setInputValue('');
}
};
return (
<div className="container">
<h1>Next.js WebSocket 示例</h1>
<div className="message-container">
{messages.map((msg, i) => (
<div key={i} className={`message ${msg.type}`}>
{msg.text}
</div>
))}
</div>
<div className="input-container">
<input
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && sendMessage()}
placeholder="输入消息..."
/>
<button onClick={sendMessage}>发送</button>
</div>
<style jsx>{`
.container {
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.message-container {
height: 300px;
border: 1px solid #ccc;
margin-bottom: 20px;
padding: 10px;
overflow-y: auto;
}
.message {
margin-bottom: 10px;
padding: 8px;
border-radius: 4px;
}
.system { background: #f0f0f0; }
.sent { background: #e3f2fd; text-align: right; }
.received { background: #f1f8e9; }
.input-container {
display: flex;
}
input {
flex: 1;
padding: 8px;
margin-right: 10px;
}
button {
padding: 8px 16px;
background: #1976d2;
color: white;
border: none;
cursor: pointer;
}
`}</style>
</div>
)
}现在你拥有了一个完整的应用,将Next.js、Express和WebSocket集成在同一服务器上,同时保持了各自的功能和优势。
使用独立WebSocket服务器
ES模块方式
// 类型导入
import type { WebSocket } from 'ws';
import type { Server } from 'http';
// 值导入
import { createServer } from 'http';
import { StandaloneWebSocketServer } from 'nextjs-ws-server';
const server = createServer();
const wss = StandaloneWebSocketServer.getInstance({
server,
path: '/ws',
onMessage: (ws: WebSocket, message: string) => {
console.log('Received:', message);
ws.send(`Echo: ${message}`);
}
});
server.listen(8080, () => {
console.log('WebSocket server running on port 8080');
});CommonJS方式
// 值导入
const http = require('http');
const wsServer = require('nextjs-ws-server/websocket-server');
const server = http.createServer();
// 由于CommonJS包装,所有导出都是异步的
wsServer.StandaloneWebSocketServer().then(WebSocketServer => {
WebSocketServer.getInstance({
server,
path: '/ws',
onMessage: (ws, message) => {
console.log('Received:', message);
ws.send(`Echo: ${message}`);
}
});
server.listen(8080, () => {
console.log('WebSocket server running on port 8080');
});
});客户端用法
// 连接WebSocket服务器
const socket = new WebSocket('ws://localhost:3000/ws');
// 接收消息
socket.onmessage = (event) => {
console.log('Message from server:', event.data);
};
// 发送消息
socket.send('Hello Server!');ESM和CommonJS模块差异说明
本库同时支持ES模块 (ESM) 和CommonJS (CJS) 项目,采用两种完全独立的实现方式:
- ES模块项目:使用原生TypeScript/ES模块实现,通过
import语法导入 - CommonJS项目:使用完全独立的CommonJS原生实现,通过
require()函数导入
两种实现保持完全相同的API和功能,但在内部使用不同的代码路径,确保最大的兼容性。
ES模块导入示例
import { createServerWithWebSocket } from 'nextjs-ws-server';
import { StandaloneWebSocketServer } from 'nextjs-ws-server/websocket-server';CommonJS导入示例
const { createServerWithWebSocket } = require('nextjs-ws-server');
const { StandaloneWebSocketServer } = require('nextjs-ws-server/websocket-server');
// 直接使用,无需处理Promise
const server = createServerWithWebSocket(options);
server.start().then(() => {
console.log('服务器已启动');
});版本 0.3.0 更新内容
添加真正的CommonJS支持:
- 采用完全独立的CommonJS实现,不再尝试桥接ESM模块
- 解决Node.js 14+的CommonJS环境中的兼容性问题
- 移除对top-level await和动态import的依赖
- 改进类型定义和导出配置
- 降低最低Node.js版本要求至14.17.0
版本 0.1.6 更新内容
改进ES模块兼容性:
- 更新了TypeScript配置,使用NodeNext模块解析
- 提供了纯ES模块导入方式示例
- 更新了构建流程,确保ES模块导出正确
- 要求Node.js 16.14.0+以支持更好的ES模块特性
文档
完整的API文档和示例请参考examples目录:
- examples/basic - 基本用法示例
- examples/next-ts - TypeScript版本的Next.js集成示例
- examples/next-express-integration.ts - Express接管Next.js路由的完整示例
- examples/esm-server.ts - 纯ES模块方式的服务器示例
- examples/cjs-server.js - CommonJS版本的服务器示例
- examples/ESM_PURE.md - ES模块导入最佳实践指南
ES模块导入指南
对于导入CommonJS模块(如express),建议使用类型导入方式:
// 类型导入(不会生成运行时代码)
import type { Request, Response } from 'express';
// 值导入
import express from 'express';详细指南请参考 examples/ESM_PURE.md。
许可证
MIT
