Search code examples
javascriptwebsocketsveltesapper

Websockets in Sapper


I have a readable store in Svelte that looks like this:

const state = {};
export const channels = readable(state, set => {
        let st = state;
        let socket = new WebSocket("ws://127.0.0.1:5999");
    
        socket.onmessage = function (event) {
          var datastr = event.data.split(':');
          st[datastr[0]].value = datastr[1];
          st[datastr[0]].timestamp = Date.now();
                    set(st)
        };
          return () => {
                    socket.close()
                }
    
});

When I import it to my Svelte App works. But if I put that App.svelte as my index.svelte running on Sapper, it doesnt work at first. It says error 500 websocket is not defined. Once I reload the page in the browser start to work... I have try to parse a function that creates the store instead:

export const getChannel = () => {
 // here my store
return {...store}
}

and then creating the store inside a onMount() like this:

onMount( ()=> {
    const channel = getChannel();
});

But doesnt seem to do the trick... What do I miss? Note: If a just replace the store by a simple writable, and create the websocket onMount(), it works without any problem. I just only wanted to put all the communication inside the store as a readable...


Solution

  • In Sapper, code in components (or imported into components) is executed in Node during server-side rendering unless it's put inside onMount (which doesn't run on the server, because there's no 'mounting' happening) or an if (process.browser) {...} block, or something equivalent.

    That includes things like references to $channels causing channels.subscribe(...) to be called during initialisation.

    Since there's no WebSocket global in Node, creating that subscription will fail. The simplest workaround is probably a simple feature check:

    const state = {};
    export const channels = readable(state, (set) => {
      if (typeof WebSocket === 'undefined') return;
    
      let st = state;
      let socket = new WebSocket("ws://127.0.0.1:5999");
    
      socket.onmessage = function (event) {
        var datastr = event.data.split(":");
        st[datastr[0]].value = datastr[1];
        st[datastr[0]].timestamp = Date.now();
        set(st);
      };
      return () => {
        socket.close();
      };
    });