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-clientsocket.io-client内部使用:

socket.io-client 被构建为由触发的UMD 模块时

     "@npm//socket.io-client:socket.io-client__umd",

BUILD.bazel中,engine.io-client/package.jsonbrowser键:

 "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 shelljspackage.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 不是构造函数的主要内容,如果未能解决你的问题,请参考以下文章

[bazel]-tulsi的使用

Bazel安装及使用入门

Bazel 编译工具 学习

#yyds干货盘点#Bazel与Gradle工具差异

版本问题---Bazel与tensorflow的对应关系

初探 Bazel