“ReferenceError:WebSocket 未定义"使用 RxJs WebSocketSubject 和 Angular Universal 时

“ReferenceError:WebSocket 未定义

问题描述:

我正在建立一个 angular 6.x 通用项目以利用其 SSR (服务器端渲染)功能.在我的应用中,我使用 RxJs 进行 websocket 通信.

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.

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

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 未定义

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 的东西并运行快速 Web 服务器.要重现错误,必须先运行构建:

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'

我还建立了一个复制仓库.

我使用的环境:

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

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

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.

更多详情

  • webpack loader ts-loader 用于编译 TypeScript => JavaScript
  • websocket 依赖被添加到 package.json:"ws": "^6.0.0"
  • 尝试通过将 const WebSocket = require('ws'); 添加到 未编译的 TypeScript 代码来引用 ws 依赖项无法解决问题.它会被编译成 var WebSocket = __webpack_require__(333); 在 js 输出文件中,依赖将无法解析.
  • 手动在编译的js中改变var WebSocket = __webpack_require__(333); => const WebSocket = require('ws');文件将解决问题,但当然这是一个黑客.
  • 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.

所以,问题是:

  • 我可以强制"webpack 编译依赖吗 const WebSocket = require('ws'); => const WebSocket = require('ws'); (没有变化)?
  • 或者,在 angular 通用 npm 包中注册此依赖项并创建拉取请求可能是更好的解决方案吗?
  • 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?

只需要:

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

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

And of course, we need the ws dependency as well in the package.json:

npm i ws -s