node.jsangularwebpackangular-universal

"ReferenceError: WebSocket is not defined" when using RxJs WebSocketSubject and Angular Universal


I'm setting up an angular 6.x univeral project in order to leverage its SSR (Server-Side Rendering) capabilities. In my app, I'm using websocket communication using RxJs.

More specifically, I'm, using WebSocketSubject and webSocket in my angular universal 6.x project, which works fine on the browser platform. However, when running the node web server (that contains the SSR stuff (Server-Side Rendering)), an error is thrown:

ReferenceError: WebSocket is not defined

Example code:

// not actually code from the reproduction repo
import { WebSocketSubject, webSocket } from 'rxjs/webSocket';

const socket: WebSocketSubject<any> = webSocket('wss://echo.websocket.org');
socket.subscribe(msg => doSomething(msg));

Please note, that the error doesn't occur on the browser version of the app (i.e. ng serve won't throw the error), but only after compiling the SSR stuff and running the express web server. To reproduce the error, the builds have to be run first:

# install dependencies
npm install

# build angular bundles for browser and server platforms
npm run build:client-and-server-bundles

# build the webserver
npm run webpack:server

# start the webserver
npm run serve:ssr

# the app is now being served at http://localhost:8081/
# open it in the browser and the error will occur: 'ReferenceError: WebSocket is not defined'

I've also set up a reproduction repo.

Environment I'm using:

Edit 2018-08-02

I was able to address the problem more accurately. It seems, that this is also a webpack problem. Angular Universal creates a js bundle for running the angular app on the node server, but there is natively no websocket implementation on Node. Therefore, it has to be added manually as a dependency (npm package). I tried adding it to the js server bundle (const WebSocket = require('ws'); manually, which resolves the problem (i.e. ReferenceError disappears). However, when I add it to the TypeScript code that gets transcompiled into the js bundle later on, it won't work.

Further details

So, the questions are:


Solution

  • All it takes is this:

    // set WebSocket on global object
    (global as any).WebSocket = require('ws');
    

    And of course, we need the ws dependency as well in the package.json:

    npm i ws -s