You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js集成YSocketIo、Tiptap与hocuspocus/server时日志无输出问题

问题描述

我在Next.js中搭建YSocketIo、Tiptap与hocuspocus/server的集成环境,协作功能能正常运行,但添加Socket路由后没有任何响应。连接成功后看不到User connected...的日志输出,也没有报错信息,请问问题出在哪?

服务器代码
import express from "express";
import { Server } from "@hocuspocus/server";
import { createServer } from "http";
import { Server as SocketServer } from "socket.io";
import { YSocketIO } from 'y-socket.io/dist/server'

const host = "localhost"
const port = "1234"

const app = express();

const httpServer = createServer(app);

const io = new SocketServer(httpServer);

const collaborationServer = Server.configure({
  onConnect: (context) => {
    console.log("User connected", context.user);
  }
});

const ysocketio = new YSocketIO(io)
ysocketio.initialize()

// Listen for Socket.IO connections
io.on("connection", (socket) => {
  console.log("Socket.IO connection established");
  socket.on("disconnect", () => {
    console.log("Socket.IO connection disconnected");
  });

  socket.on("test", () => {
    console.log("test");
  });

  collaborationServer.handleConnection(socket, null, context);
});


httpServer.listen(port, host, undefined, () => console.log(`Server running on port ${port}`))
Next.js页面代码
import Collaboration from "@tiptap/extension-collaboration";

import StarterKit from "@tiptap/starter-kit";
import { EditorContent, useEditor } from "@tiptap/react";
import React, { useEffect } from "react";
import { HocuspocusProvider } from "@hocuspocus/provider";
import CollaborationCursor from "@tiptap/extension-collaboration-cursor";
import Paragraph from "@tiptap/extension-paragraph";

import Document from "@tiptap/extension-document";
import Placeholder from "@tiptap/extension-placeholder";
import Text from "@tiptap/extension-text";
import * as Y from "yjs";


import { SocketIOProvider } from 'y-socket.io';

const doc = new Y.Doc()
const provider = new SocketIOProvider('http://localhost:1234', 'room-name', doc, {
    autoConnect: true,
    resyncInterval: 5000,
    disableBc: false
});


const TipTapEditor = () => {

    const editor = useEditor({
        extensions: [
            StarterKit.configure({
                history: false,
            }),
            // Register the document with Tiptap
            Collaboration.configure({
                document: doc,
                
            }),
            CollaborationCursor.configure({
                provider,
                user: {
                    name: "Cyndi",
                    color: "#f783ac",
                },
            }),
            Placeholder.configure({
                placeholder:
                    "Write something … Itll be shared with everyone else looking at this example.",
            }),
        ],
    });

    const handleEmit = () => {
        console.log('emitting test');

        provider.emit('test', []);
    }

    return (
        <>
            <button onClick={handleEmit}>
                Test Emit
            </button>
            <EditorContent editor={editor} />
        </>
        
    );
};

export default TipTapEditor;
问题分析与解决

核心问题1:context变量未定义

服务器代码的io.on("connection")回调中,调用collaborationServer.handleConnection(socket, null, context)时,context变量未声明,会导致代码静默报错,直接跳过后续逻辑,因此Hocuspocus的onConnect回调无法触发,看不到对应的日志。

核心问题2:Hocuspocus与YSocketIO的功能冲突

你同时初始化了YSocketIO和Hocuspocus的协作服务,两者都是基于Socket.IO处理Yjs文档同步的工具,会抢占Socket连接的控制权。当前协作功能正常是因为YSocketIO在工作,但Hocuspocus的连接逻辑被完全覆盖,所以它的onConnect不会执行。

修复方案(二选一)

方案1:统一使用Hocuspocus服务

移除YSocketIO相关代码,让Hocuspocus接管所有协作逻辑:

修复后的服务器代码

import express from "express";
import { Server } from "@hocuspocus/server";
import { createServer } from "http";
import { Server as SocketServer } from "socket.io";

const host = "localhost"
const port = "1234"

const app = express();
const httpServer = createServer(app);
const io = new SocketServer(httpServer);

const collaborationServer = Server.configure({
  onConnect: (context) => {
    console.log("User connected", context.user);
  },
});

io.on("connection", (socket) => {
  console.log("Socket.IO connection established");
  
  // 初始化上下文,可根据需求添加用户信息
  const context = {
    user: { id: socket.id, name: "Anonymous" }
  };

  // 交给Hocuspocus处理连接
  collaborationServer.handleConnection(socket, { path: "/hocuspocus" }, context);

  socket.on("disconnect", () => {
    console.log("Socket.IO connection disconnected");
  });

  socket.on("test", () => {
    console.log("test");
  });
});

httpServer.listen(port, host, undefined, () => console.log(`Server running on port ${port}`))

修复后的客户端代码

import Collaboration from "@tiptap/extension-collaboration";
import StarterKit from "@tiptap/starter-kit";
import { EditorContent, useEditor } from "@tiptap/react";
import React from "react";
import { HocuspocusProvider } from "@hocuspocus/provider";
import CollaborationCursor from "@tiptap/extension-collaboration-cursor";
import Placeholder from "@tiptap/extension-placeholder";
import * as Y from "yjs";

const TipTapEditor = () => {
    const doc = new Y.Doc();
    const provider = new HocuspocusProvider({
      url: "ws://localhost:1234/hocuspocus",
      name: "room-name",
      document: doc,
    });

    const editor = useEditor({
        extensions: [
            StarterKit.configure({
                history: false,
            }),
            Collaboration.configure({
                document: doc,
            }),
            CollaborationCursor.configure({
                provider,
                user: {
                    name: "Cyndi",
                    color: "#f783ac",
                },
            }),
            Placeholder.configure({
                placeholder:
                    "Write something … It'll be shared with everyone else looking at this example.",
            }),
        ],
    });

    const handleEmit = () => {
        console.log('emitting test');
        // Hocuspocus Provider用send方法发送自定义消息
        provider.connection.send(JSON.stringify({ type: "test" }));
    }

    return (
        <>
            <button onClick={handleEmit}>
                Test Emit
            </button>
            <EditorContent editor={editor} />
        </>
    );
};

export default TipTapEditor;

方案2:保留YSocketIO,添加自定义Socket命名空间

如果要同时使用YSocketIO和自定义事件,用命名空间区分两者的连接:

// 服务器代码:给YSocketIO指定独立命名空间
const ysocketio = new YSocketIO(io.of('/yjs'))
ysocketio.initialize()

// 自定义事件用默认命名空间
io.on("connection", (socket) => {
  console.log("Socket.IO connection established");
  socket.on("test", () => {
    console.log("test");
  });
});

// 客户端代码:连接对应命名空间
const provider = new SocketIOProvider('http://localhost:1234/yjs', 'room-name', doc, {
    autoConnect: true,
});

内容的提问来源于stack exchange,提问作者Naclin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 16:13:18