Bazel + Angular + SocketIO Causes: Uncaught TypeError: XMLHttpRequest is not a constructor

旧时模样 提交于 2021-01-02 05:10:54

问题


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


回答1:


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.



来源:https://stackoverflow.com/questions/61423031/bazel-angular-socketio-causes-uncaught-typeerror-xmlhttprequest-is-not-a-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!