Bazel + Angular + SocketIO原因:未捕获的TypeError:XMLHttpRequest不是构造函数 [英] Bazel + Angular + SocketIO Causes: Uncaught TypeError: XMLHttpRequest is not a constructor

查看:76
本文介绍了Bazel + Angular + SocketIO原因:未捕获的TypeError:XMLHttpRequest不是构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将 ngx-socket-io 添加到我的Angular应用程序中.我使用Bazel运行我的Angular开发服务器.不幸的是, ngx-socket-io 似乎无法与 ts_devserver 一起使用.我在浏览器控制台中收到此错误:

 未捕获的TypeError:XMLHttpRequest不是构造函数在ts_scripts.js?v = 1587802098203:16776在Object.23 .../transport(ts_scripts.js?v = 1587802098203:16780)在o(ts_scripts.js?v = 1587802098203:11783) 

这似乎是由 xmlhttprequest-ssl 引起的,它与 engine.io-client ,需要它ngx-socket-io .但是,仅在 ts_devserver 时才会出现此问题.生产中运行Angular应用完全正常.

最低繁殖量

您可以轻松地自己尝试: https://github.com/flolu/bazel-socketio-问题

只需运行 yarn install ,然后运行 yarn dev (它会在浏览器控制台中导致错误@ http://localhost:4200 ).并且请注意, yarn prod @ http://localhost:8080 可以正常工作!

编辑1

当前在Windows上似乎还有另一个问题.因此,只有在运行Mac或Linux的情况下,您才可以尝试示例存储库

解决方案

问题来自 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 浏览器键:

 浏览器":{"ws":否,"xmlhttprequest-ssl":"./lib/xmlhttprequest.js"}, 

似乎被忽略了.

结果, node_modules/engine.io-client/lib/transports/*.js 中的 require('xmlhttprequest-ssl')语句保留在UMD构建.由于 xmlhttprequest-ssl 用于无头Node环境,并且不能在浏览器中工作,因此会导致错误.

我找不到此行为的原因/问题,但我找到了解决方案(不应将其视为解决方法):

使用 postinstall 脚本重写 engine.io-client :

  1. 安装 shelljs 软件包: yarn add -D shelljs
  2. package.json 中的 postinstall 更新为:"postinstall":"node --preserve-symlinks --preserve-symlinks-main ./postinstall-patch.js&& ngcc"
  3. 将以下代码放入项目根目录下的 postinstall-patches.js 中:

  try {require.resolve('shelljs');}抓住(e){//我们在一个由bazel管理的外部node_modules存储库中//并且解析失败,因为节点未保留符号链接//加载脚本时.//这可以使用--preserve-symlinks-main标志修复,该标志//在节点10.2.0中引入console.warn(`在外部存储库中运行postinstall-patches.js脚本需要在节点10.2.0中引入--preserve-symlinks-main节点标志.`+`当前节点版本为$ {process.version}.用'$ {process.argv.join('')}'.`)调用的节点;process.exit(0);}const {set,cd,sed,ls} = require('shelljs');const path = require('path');const log = console.info;log('=====将要运行postinstall-patches.js脚本=====');//发生第一个错误时失败set('-e');//打印正在执行的命令set('-v');cd(__ dirname);日志('\ n#补丁引擎.io-客户端:将\'xmlhttprequest-ssl \'重写为浏览器shim');ls('node_modules/engine.io-client/lib/transports/*.js').forEach(function(file){sed('-i','\'xmlhttprequest-ssl \'','\'../xmlhttprequest \'',文件);});log('=====完成运行postinstall-patches.js脚本====='); 

(灵感: https://bazelbuild.github.io/rules_nodejs/#patching-the-npm-packages ,它链接到示例 https://github.com/angular/angular/blob/master/tools/postinstall-patches.js )

  1. 纱线安装
  2. yarn dev

我将在几分钟后向您的GitHub repro提交拉取请求.


可能替代方案,无法使它们起作用:

  • 使用 socket.io-client/dist/socket.io.js ,但附加一个"UMD垫片",因为它似乎是一个匿名UMD"模块,或者
  • 一些 npm_umd_bundle 魔术

请参阅问题每个新的npm dep都需要一种独特的方法来将其添加到ts_devserver#1055 bazelbuild/rules_nodejs 中,以获取有关这两种方式的更多信息./p>

I want to add ngx-socket-io to my Angular application. I use Bazel to run my Angular dev-server. Unfortunately ngx-socket-io doesn't seem to work with the ts_devserver out of the box. I get this error in the browser console:

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)

It seems to be caused by xmlhttprequest-ssl which is a dependency of engine.io-client and it is needed by ngx-socket-io. But this problem only occurs with the ts_devserver. Running the Angular app in production works totally fine.

Minimal Reproduction

You can easily try it yourself: https://github.com/flolu/bazel-socketio-issue

Just run yarn install and then yarn dev (it causes the error in the browser console @ http://localhost:4200). And note that yarn prod @ http://localhost:8080 works just fine!

Edit 1

Currently there seems to be another issue on Windows. So you can only try the example repo if you're running Mac or Linux

解决方案

The problem comes from engine.io-client, which is used internally by socket.io-client:

When socket.io-client gets built as UMD module triggered by

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

in BUILD.bazel, the browser key of engine.io-client/package.json:

 "browser": {
   "ws": false,
   "xmlhttprequest-ssl": "./lib/xmlhttprequest.js"
 },

is seemingly ignored.

As a consequence, the require('xmlhttprequest-ssl') statements in node_modules/engine.io-client/lib/transports/*.js remain in the UMD build. Because xmlhttprequest-ssl is intended for headless Node environments and does not work in browsers, this results in an error.

I couldn't find a reason/issue for this behavior, but I found a solution (which shouldn't be considered as a workaround):

Rewrite engine.io-client with a postinstall script:

  1. install shelljs package: yarn add -D shelljs
  2. update postinstall in package.json to: "postinstall": "node --preserve-symlinks --preserve-symlinks-main ./postinstall-patches.js && ngcc"
  3. put the following code into postinstall-patches.js at project root:

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 =====');

(Inspiration: https://bazelbuild.github.io/rules_nodejs/#patching-the-npm-packages, which links to the example https://github.com/angular/angular/blob/master/tools/postinstall-patches.js)

  1. yarn install
  2. yarn dev

I'll submit a pull request to your GitHub repro in a few minutes.


Possible alternatives, couldn't get them to work:

  • use socket.io-client/dist/socket.io.js but with an additional "UMD shim" because it seems to be an "anonymous UMD" module, OR
  • some npm_umd_bundle magic

See issue Every new npm dep needs a unique approach how to add it to ts_devserver #1055 in bazelbuild/rules_nodejs for more information about both ways.

这篇关于Bazel + Angular + SocketIO原因:未捕获的TypeError:XMLHttpRequest不是构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆