问题
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:
- install
shelljs
package:yarn add -D shelljs
- update
postinstall
inpackage.json
to:"postinstall": "node --preserve-symlinks --preserve-symlinks-main ./postinstall-patches.js && ngcc"
- 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)
yarn install
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