npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nextjs-ws-server

v0.3.2

Published

A WebSocket server for Next.js with support for both ESM and CommonJS,update type errors.

Readme

Next.js WebSocket Server

npm version License: MIT

这个库提供了在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处理页面渲染和客户端路由
  • 可以轻松添加自定义中间件(如认证、日志等)
  • 所有服务运行在同一端口,简化部署

执行步骤

  1. 将上述代码保存为项目根目录下的server.ts文件(或server.js如果是CommonJS项目)
  2. 确保项目中已安装所需依赖:
    npm install express next ws nextjs-ws-server
    npm install --save-dev typescript @types/express @types/ws
  3. 使用TypeScript编译并执行服务器:
    # 对于ES模块项目
    npx tsc server.ts
    node server.js
       
    # 对于CommonJS项目
    node server.js

预期运行结果

服务器启动后,你会看到以下输出:

> Next.js应用已准备就绪
> 服务器运行在 http://localhost:3000
> WebSocket服务可在 ws://localhost:3000/ws 访问

此时:

  1. 访问http://localhost:3000将显示你的Next.js应用主页
  2. 访问http://localhost:3000/api/hello将返回自定义API响应:{"message":"Hello from custom API!"}
  3. 连接到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