Bazel + Angular + SocketIO 原因:未捕获的 TypeError:XMLHttpRequest 不是构造函数
Posted
技术标签:
【中文标题】Bazel + Angular + SocketIO 原因:未捕获的 TypeError:XMLHttpRequest 不是构造函数【英文标题】:Bazel + Angular + SocketIO Causes: Uncaught TypeError: XMLHttpRequest is not a constructor 【发布时间】:2020-08-08 21:24:26 【问题描述】:我想将ngx-socket-io 添加到我的 Angular 应用程序中。我使用 Bazel 来运行我的 Angular 开发服务器。
不幸的是,ngx-socket-io
似乎不适用于开箱即用的ts_devserver
。我在浏览器控制台中收到此错误:
Uncaught TypeError: XMLHttpRequest is not a constructor
at ts_scripts.js?v=1587802098203:16776
at Object.23.../transport (ts_scripts.js?v=1587802098203:16780)
at o (ts_scripts.js?v=1587802098203:11783)
它似乎是由xmlhttprequest-ssl 引起的,它是engine.io-client 的依赖项,ngx-socket-io
需要它。但是这个问题只发生在ts_devserver 上。 在production 中运行 Angular 应用程序完全正常。
最小复制
您可以自己轻松尝试:https://github.com/flolu/bazel-socketio-issue
只需运行yarn install
,然后运行yarn dev
(它会导致浏览器控制台出现错误@http://localhost:4200)。
请注意yarn prod
@http://localhost:8080 工作正常!
编辑 1
目前 Windows 上似乎还有另一个问题。因此,如果您运行的是 Mac 或 Linux,则只能尝试示例 repo
【问题讨论】:
我检查了这个存储库,yarn dev 和yarn prod 都因一些bazel 错误而失败。 imgur.com/25YnZXP 收到此错误。 该死的。这可能与Windows有关(我使用Linux并且没有收到此错误) 你能给个repo,可以在windows上运行吗? @AakashGarg 我不在任何设备上使用 Windows。所以我无法调试问题 【参考方案1】:问题来自engine.io-client
,socket.io-client
内部使用:
当socket.io-client
被构建为由触发的UMD 模块时
"@npm//socket.io-client:socket.io-client__umd",
在BUILD.bazel
中,engine.io-client/package.json
的browser
键:
"browser":
"ws": false,
"xmlhttprequest-ssl": "./lib/xmlhttprequest.js"
,
似乎被忽略了。
因此,node_modules/engine.io-client/lib/transports/*.js
中的 require('xmlhttprequest-ssl')
语句仍保留在 UMD 构建中。因为xmlhttprequest-ssl
是为无头节点环境设计的,在浏览器中不起作用,这会导致错误。
我找不到此行为的原因/问题,但我找到了解决方案(不应将其视为解决方法):
用postinstall
脚本重写engine.io-client
:
-
安装
shelljs
包:yarn add -D shelljs
将package.json
中的postinstall
更新为:"postinstall": "node --preserve-symlinks --preserve-symlinks-main ./postinstall-patches.js && ngcc"
将以下代码放入项目根目录的postinstall-patches.js
:
try
require.resolve('shelljs');
catch (e)
// We are in an bazel managed external node_modules repository
// and the resolve has failed because node did not preserve the symlink
// when loading the script.
// This can be fixed using the --preserve-symlinks-main flag which
// is introduced in node 10.2.0
console.warn(
`Running postinstall-patches.js script in an external repository requires --preserve-symlinks-main node flag introduced in node 10.2.0. ` +
`Current node version is $process.version. Node called with '$process.argv.join(' ')'.`);
process.exit(0);
const set, cd, sed, ls = require('shelljs');
const path = require('path');
const log = console.info;
log('===== about to run the postinstall-patches.js script =====');
// fail on first error
set('-e');
// print commands as being executed
set('-v');
cd(__dirname);
log('\n# patch engine.io-client: rewriting \'xmlhttprequest-ssl\' to browser shim');
ls('node_modules/engine.io-client/lib/transports/*.js').forEach(function (file)
sed('-i', '\'xmlhttprequest-ssl\'', '\'../xmlhttprequest\'', file);
);
log('===== finished running the postinstall-patches.js script =====');
(灵感:https://bazelbuild.github.io/rules_nodejs/#patching-the-npm-packages,链接到示例https://github.com/angular/angular/blob/master/tools/postinstall-patches.js)
yarn install
yarn dev
我会在几分钟后向你的 GitHub 复制提交一个拉取请求。
可能的替代方案,但无法让它们发挥作用:
使用socket.io-client/dist/socket.io.js
,但附加一个“UMD shim”,因为它似乎是一个“匿名UMD”模块,或者
一些npm_umd_bundle
魔法
有关这两种方式的更多信息,请参阅bazelbuild/rules_nodejs
中的问题Every new npm dep needs a unique approach how to add it to ts_devserver #1055。
【讨论】:
PR已提交 哇!我刚刚尝试过,效果很好!我还有两个问题:(1)你说“这不应该被视为一种解决方法”。您的意思是不应该使用它还是可以使用它? (2)engine.io-client
的修补也可以通过类似patch-package 的 .patch 文件来完成?
首先:我昨天刚开始使用 Bazel :-) 至 (1):我认为打补丁非常好,请参阅 bazelbuild.github.io/rules_nodejs> 处的“打补丁”。我还发现了人们需要解决在 NPM 上发布的预打包构建的许多问题。所以关于 Bazel 生态系统,这是一个事实,所以有这样的工具和技巧。 (2) 是的,应该工作。替代方案:请参阅链接页面上的“修补内置版本”。 postinstall-patches.js
为您提供更大的灵活性,并且对未来的升级更稳定(例如,我们在没有硬编码文件名的情况下进行修补)。
非常感谢!我会等到明天再发放赏金:) 你“检测”问题的过程是什么?我知道它与xmlhttprequest
有关,但是,您是如何将其深入到engine.io-client
的?
我知道xmlhttprequest-ssl
不适合在浏览器中使用,所以我想知道为什么在运行开发服务器时仍然需要它。最后,一个小 grep(ripgrep,更具体地说:rg -ul xmlhttprequest-ssl
)揭示了在 socket.io-client
中对 xmlhttprequest-ssl
的引用(但不在其源代码中,仅在源映射中)和 engine.io-client
。以上是关于Bazel + Angular + SocketIO 原因:未捕获的 TypeError:XMLHttpRequest 不是构造函数的主要内容,如果未能解决你的问题,请参考以下文章