Deploying a y-websocket server

Hi, I’ve been struggling to have the same results when I run my server localhost and from heroku. Take the following code as an example:

const WebSocket = require("ws")
const http = require("http")
const StaticServer = require("node-static").Server
const setupWSConnection = require("y-websocket/bin/utils").setupWSConnection

const production = process.env.PRODUCTION != null
const port = process.env.PORT || 9999

const staticServer = new StaticServer("../", {
  cache: production ? 3600 : false,
  gzip: production,
})

const server = http.createServer((request, response) => {
  request
    .addListener("end", () => {
      staticServer.serve(request, response)
    })
    .resume()
})
const wss = new WebSocket.Server({ server })

wss.on("connection", (conn, req) => {
  return setupWSConnection(conn, req, {
    gc: true,
  })
})

server.listen(port)

console.log(
  `Listening to http://localhost:${port} ${production ? "(production)" : ""}`
)

If I run this server locally and I have the following code on a react site:

const ydoc = new Y.Doc();
const websocketProvider = new WebsocketProvider(
  'ws://localhost:9999',
  'test',
  ydoc,
  { connect: true }
);

export function observe(room = 'test') {
  const ymap = ydoc.getMap(room);
  return ymap;
}

export const Example = () => {
  const shared = useRef(null);

  useEffect(() => {
    shared.current = observe();
    shared.current.observe((event) => {
      console.log('NODES', shared.current.get('state'));
    });
  }, []);

  const handleClick = () => {
    shared.current.set('state', { timestamp: Date.now() });
  };

return <button onClick={handleClick}>click me</button>
}

The above code works great using different browsers or different browser users.

As soon as I deploy that code to heroku, different browsers can’t communicate. I can see the same browser with different tabs receiving the console.log on both tabs, but not across different browsers.

Why?

You have ws://localhost:9999 hardcoded in the client code. You’ll need to use the heroku-supplied HOST and PORT when deploying to heroku.

In this article, Heroku recommends location.origin.replace(/^http/, 'ws'), but I can’t confirm if that is correct with your particular hosting setup.

Hi Raine, thanks for your reply.
I left the localhost:9999 on my code because I didn’t want to share the heroku server url, I should have probably mention it. Apologies.

If you open https://yjs.dev with Chrome on a user profile, scroll back to the demos and choose Drawing, if you then open Safari and go to the same demo you see different results. So even on the yjs demo it seems like users connect to different rooms. This might be intentional, but its certainly not intentional on my demo where I explicitly provide the same Y.Doc and the same room name.

Thank you

In that case, it seems like an issue with your hosting configuration.

  • Can you confirm that websockets work on the same host in a non-YJS context?
  • Is setupConnection triggered on the server?
  • Are any messages received by the server?

Heroku spins up multiple servers. If these servers don’t communicate with each other, the content of different sessions won’t be shared.

The issue with safari is that it can’t communicate via WebRTC with other browsers (it’s super buggy).