使用RxJs WebSocketSubject和Angular Universal时出现“ ReferenceError:WebSocket未定义”

时间:2018-07-26 06:17:45

标签: node.js angular webpack angular-universal

我正在设置angular 6.x univeral project,以利用其SSR(服务器端渲染)功能。在我的应用中,我正在通过RxJ使用Websocket通信。

更具体地说,我在我的角度通用6.x项目中使用WebSocketSubjectwebSocket,在浏览器平台上可以正常工作。但是,在运行节点Web服务器(包含SSR内容(服务器端渲染))时,将引发错误:

  

ReferenceError:未定义WebSocket

示例代码:

// 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));

请注意,该应用程序的浏览器版本上不会发生该错误(即ng serve不会引发该错误),只有在编译了SSR内容并运行Express Web服务器。要重现该错误,必须首先运行构建:

# 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'

我还设置了一个reproduction repo

我正在使用的环境:

  • 运行时:Angular 6
  • RxJS版本:6.2.0、6.2.1、6.2.2(全部测试)

编辑2018-08-02

我能够更准确地解决该问题。看来,这也是一个webpack问题。 Angular Universal创建了一个js捆绑包,用于在节点服务器上运行Angular应用程序,但是Node上本身没有websocket实现。因此,必须手动将其作为依赖项添加(npm软件包)。我尝试将其添加到js服务器捆绑包中(手动const WebSocket = require('ws');可解决问题(即ReferenceError消失)。但是,当我将其添加到被反编译为js的TypeScript代码中时稍后打包,将不起作用。

更多详细信息

  • webpack加载器ts-loader用于编译TypeScript => JavaScript
  • 已将websocket特权添加到package.json:"ws": "^6.0.0"
  • 尝试通过将const WebSocket = require('ws');添加到未编译的TypeScript代码来引用ws依赖关系将无法解决问题。它将被编译为js输出文件中的var WebSocket = __webpack_require__(333);,该依赖关系将无法解决。
  • 手动在已编译的js文件中更改var WebSocket = __webpack_require__(333); => const WebSocket = require('ws');,将解决此问题,但这当然是黑客。

因此,问题是:

  • 我可以“强制” webpack编译依赖项const WebSocket = require('ws'); => const WebSocket = require('ws');(无变化)吗?
  • 或者,将这种依赖关系注册到angular通用npm包中并创建拉取请求,可能是更好的解决方案吗?

4 个答案:

答案 0 :(得分:3)

所要做的就是这个:

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

当然,我们在package.json中也需要ws依赖项:

npm i ws -s

答案 1 :(得分:3)

RxJS webSocket函数可以接收WebSocket构造函数作为参数。这样可以用于在非浏览器/通用环境中运行webSocket。

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

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

答案 2 :(得分:0)

在具有ES6或类似版本的nodeJS应用中,您必须使用以下代码:

global.WebSocket = require('ws')

例如:

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

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

没有更多错误。

我的第一个答案!!干杯

答案 3 :(得分:-1)

我使用websockets创建了一个npm包。 为了提供服务器端js和浏览器js的兼容性,我使用此代码。

(注意:它是打字稿)

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

就像您提到的那样,浏览器的全局对象window中已经有一个WebSocket,但是节点没有。 由于浏览器没有global,因此这种简单的检查效果很好。

已编译的代码:

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