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

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

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

更具体地说,我在我的 angular 通用 6.x 项目中使用 WebSocketSubjectwebSocket,它在浏览器平台上运行良好。但是,当 运行 连接节点 Web 服务器(包含 SSR 内容(服务器端渲染))时,会抛出一个错误:

ReferenceError: WebSocket is not defined

示例代码:

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

我使用的环境:

编辑 2018-08-02

我能够更准确地解决问题。看来,这也是一个 webpack 问题。 Angular Universal 为 运行 在节点服务器上安装 angular 应用程序创建了一个 js 包,但在节点上本机没有 websocket 实现。因此,它必须作为依赖项(npm 包)手动添加。我尝试将它添加到 js 服务器包(const WebSocket = require('ws'); 手动, 解决了问题(即 ReferenceError 消失)。但是,当我将它添加到 TypeScript 代码时,它被转换稍后进入js包,它不会工作。

更多详情

所以,问题是:

只需要这样:

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

当然,我们在 package.json:

中也需要 ws 依赖

npm i ws -s

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

(注意:是打字稿)

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

正如您提到的,浏览器的全局对象中已经有一个 WebSocket window,但节点没有。 由于浏览器没有global,这个简单的检查效果很好。

编译代码:

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

RxJS webSocket 函数可以接收一个 WebSocket 构造函数作为参数。这可以用于 运行 在 non-browser/universal 环境中的 webSocket。

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

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

在 ES6 或类似的 nodeJS 应用中,你必须使用这个:

global.WebSocket = require('ws')

例如:

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

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

没有更多错误。

我的第一个回答!!干杯