"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 项目中使用 WebSocketSubject
和 webSocket
,它在浏览器平台上运行良好。但是,当 运行 连接节点 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。
我使用的环境:
- 运行时间:Angular 6
- RxJS 版本:6.2.0、6.2.1、6.2.2(全部测试)
编辑 2018-08-02
我能够更准确地解决问题。看来,这也是一个 webpack 问题。 Angular Universal 为 运行 在节点服务器上安装 angular 应用程序创建了一个 js 包,但在节点上本机没有 websocket 实现。因此,它必须作为依赖项(npm 包)手动添加。我尝试将它添加到 js 服务器包(const WebSocket = require('ws');
手动, 解决了问题(即 ReferenceError 消失)。但是,当我将它添加到 TypeScript 代码时,它被转换稍后进入js包,它不会工作。
更多详情
- 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');
会解决问题,但是当然是 hack。
所以,问题是:
- 我可以"force" webpack编译依赖
const WebSocket = require('ws');
=> const WebSocket = require('ws');
(没有变化)吗?
- 或者,在 angular 通用 npm 包中注册此依赖项并创建拉取请求,这可能是更好的解决方案吗?
只需要这样:
// 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://...');
没有更多错误。
我的第一个回答!!干杯
我正在设置 angular 6.x univeral project 以利用其 SSR(服务器端渲染)功能。在我的应用程序中,我使用 RxJs 使用 websocket 通信。
更具体地说,我在我的 angular 通用 6.x 项目中使用 WebSocketSubject
和 webSocket
,它在浏览器平台上运行良好。但是,当 运行 连接节点 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。
我使用的环境:
- 运行时间:Angular 6
- RxJS 版本:6.2.0、6.2.1、6.2.2(全部测试)
编辑 2018-08-02
我能够更准确地解决问题。看来,这也是一个 webpack 问题。 Angular Universal 为 运行 在节点服务器上安装 angular 应用程序创建了一个 js 包,但在节点上本机没有 websocket 实现。因此,它必须作为依赖项(npm 包)手动添加。我尝试将它添加到 js 服务器包(const WebSocket = require('ws');
手动, 解决了问题(即 ReferenceError 消失)。但是,当我将它添加到 TypeScript 代码时,它被转换稍后进入js包,它不会工作。
更多详情
- 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');
会解决问题,但是当然是 hack。
所以,问题是:
- 我可以"force" webpack编译依赖
const WebSocket = require('ws');
=>const WebSocket = require('ws');
(没有变化)吗? - 或者,在 angular 通用 npm 包中注册此依赖项并创建拉取请求,这可能是更好的解决方案吗?
只需要这样:
// 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://...');
没有更多错误。
我的第一个回答!!干杯