我正在设置angular 6.x univeral project,以利用其SSR(服务器端渲染)功能。在我的应用中,我正在通过RxJ使用Websocket通信。
更具体地说,我在我的角度通用6.x项目中使用WebSocketSubject
和webSocket
,在浏览器平台上可以正常工作。但是,在运行节点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。
我正在使用的环境:
我能够更准确地解决该问题。看来,这也是一个webpack问题。 Angular Universal创建了一个js捆绑包,用于在节点服务器上运行Angular应用程序,但是Node上本身没有websocket实现。因此,必须手动将其作为依赖项添加(npm软件包)。我尝试将其添加到js服务器捆绑包中(手动const WebSocket = require('ws');
,可解决问题(即ReferenceError消失)。但是,当我将其添加到被反编译为js的TypeScript代码中时稍后打包,将不起作用。
更多详细信息
ts-loader
用于编译TypeScript => JavaScript "ws": "^6.0.0"
const WebSocket = require('ws');
添加到未编译的TypeScript代码来引用ws依赖关系将无法解决问题。它将被编译为js输出文件中的var WebSocket = __webpack_require__(333);
,该依赖关系将无法解决。var WebSocket = __webpack_require__(333);
=> const WebSocket = require('ws');
,将解决此问题,但这当然是黑客。因此,问题是:
const WebSocket = require('ws');
=> const WebSocket = require('ws');
(无变化)吗?答案 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');
}