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

旧城冷巷雨未停 提交于 2021-02-07 11:46:33

问题


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:

  • Runtime: Angular 6
  • RxJS version: 6.2.0, 6.2.1, 6.2.2 (tested all)

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

  • The webpack loader ts-loader is used for compiling TypeScript => JavaScript
  • The websocket depedency was added to the package.json: "ws": "^6.0.0"
  • Attempting to reference the ws dependency by adding const WebSocket = require('ws'); to the uncompiled TypeScript code won't resolve the issue. It would get compiled into var WebSocket = __webpack_require__(333); in the js output file, the dependency won't be able to be resolved.
  • Manually changing var WebSocket = __webpack_require__(333); => const WebSocket = require('ws'); in the compiled js file would resolve the issue, but of course it's a hack.

So, the questions are:

  • Can I "force" webpack to compile the dependency const WebSocket = require('ws'); => const WebSocket = require('ws'); (no changes)?
  • Or, would it might be a better solution, to register this dependency in the angular universal npm package and create a pull request?

回答1:


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




回答2:


The RxJS webSocket function can receive a WebSocket Constructor as an argument. This can be used to run webSocket in a non-browser/universal environment like this.

const WebSocketConstructor = WebSocket || require('ws')

const socket: WebSocketSubject<any> = webSocket({
    url: 'wss://echo.websocket.org', 
    WebSocketCtor: WebSocketConstructor,
});



回答3:


In nodeJS apps with ES6 or similar, you must use this:

global.WebSocket = require('ws')

For example:

import { WebSocketSubject, webSocket } from 'rxjs/webSocket';

global.WebSocket = require('ws'); // <-- FIX ALL ERRORS
const subject = webSocket('ws://...');

No more errors.

My first answer!! Cheers




回答4:


I created a npm package using websockets. To provide compatibility for server side js and browser js i use this code.

(Note: it is typescript)

if (typeof global !== 'undefined') {
    (global as any).WebSocket = require('ws');
}

Like you mentioned, the browser already has a WebSocket in its global object window but node does not. Since the browser does not have global, this simple check works well.

Compiled code:

if (typeof global !== 'undefined') {
    global.WebSocket = require('ws');
}


来源:https://stackoverflow.com/questions/51532159/referenceerror-websocket-is-not-defined-when-using-rxjs-websocketsubject-and

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!