Open fluky opened 5 years ago
This is an interesting one. So, what's happening here is that something in your bundle attempts to perform a synchronous XHR. jsdom
implements this by using child_process.spawnSync
. This will spawn a node process running xhr-sync-worker.js
, which in turn will request the subject.
This request is usually handled by Karma's server. In this case however, Node is blocking in spawnSync and won't respond to the request. In other words, there's a deadlock going on here.
There's unfortunately not much for karma-jsdom-launcher
to do here. An option would be for it to spawn its own process. This would however prohibit users of passing all possible options to jsdom, as they would have to be serialized somehow. In a proper language one would simply fork (syscall), but we don't have the luxury of that in Node.
I don't have time to dig further into Angular og Webpack for you, but if you can find a way for it to not perform synchronous XHR, then this will hopefully work.
Leaving it open for a while, any tips as to how make Webpack cooperate are welcome.
I couldn't let this one go and did some more digging. It turns out that the synchronous requests are made by source-map-support.
There's an issue in angular-cli that prevents me from disabling it, which I've tried to outline below.
Even though I specify "sourceMap": false
in angular.json
Config is normalized
sourceMap
option is further normalized
Normalization of sourceMap
always ends up with an object
source-map-support
is conditionally included, but the condition is always true
I suspect that https://github.com/angular/angular-cli/pull/13062 introduced this behavior.
The good news is that source-map-support
will ignore any errors thrown by XMLHttpRequest. Hence, as a temporary measure, you can apply the following patch to unclog your setup.
--- node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js
+++ node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js
@@ -425,6 +425,9 @@
}
open(method, uri, asynchronous, user, password) {
+ if (typeof asynchronous !== "undefined" && !asynchronous) {
+ throw new Error("Synchronous request prohibited.");
+ }
if (!this._ownerDocument) {
throw new DOMException("The object is in an invalid state.", "InvalidStateError");
}
Sidenote: Having a proper way of patching 3rd party libraries is convenient when you can't be bothered to submit a patch yourself, either because you can't wait for it or because your request is too obscure. I've never been on a real project without ever having needed this. One approach I've found to work is having a postinstall script in package.json and a directory containing patches as that shown above.
// package.json
"scripts": {
"postinstall": "patches/apply.sh"
}
// patches/apply.sh
#!/usr/bin/env bash
for f in patches/*.patch
do
patch --reverse --dry-run --force --strip 0 < $f &>/dev/null
if [ $? -ne 0 ]; then
patch --forward --force --strip 0 < $f
fi
done
// patches/01-jsdom-prohibit-synchronous-requests.patch
--- node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js
+++ node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js
@@ -425,6 +425,9 @@
}
open(method, uri, asynchronous, user, password) {
+ if (typeof asynchronous !== "undefined" && !asynchronous) {
+ throw new Error("Synchronous request prohibited.");
+ }
if (!this._ownerDocument) {
throw new DOMException("The object is in an invalid state.", "InvalidStateError");
}
Brilliant! Thanks for the help. Glad you couldn't let it go 😄 .
As a suggestion you may want to add this to your README.md given the popularity of the platform.
@badeball regarding the patching of libs, just wanted to mention that https://github.com/ds300/patch-package helps with that problem as well. Exactly same concept though. It just sorta manages the patches and is cross platform.
I've tried creating a fresh Angular project and configured "sourceMap": false
in angular.json
(in the test
part). It now seems to run fine. @fluky, can you update your dependencies and confirm that it now works?
Edit: To specify further - it seems like the fix was published with v7.3.1, as shown by git tag --contains acc31ba
.
I will furthermore see if I can warn users of synchronous requests to the Karma server, as it will never really work.
I was having issues with coverage reports with source maps set to false in an angular repo. Thanks @badeball for your workaround. I also had to increase NODE_OPTIONS=--max-old-space-size=8192
but it all works.
I'm trying to add jsdom to an Angular CLI project and when I switch the browser to jsdom it just hangs indefinitely after building.
Steps to reproduce:
At this point the project will compile and then go to a blank screen where it sits until killed with Ctrl+C.