Compilation stuck at 'Files successfully emitted, waiting for typecheck results...' caused by race condition in TypeScript + web workers context
See original GitHub issueDescribe the bug
This is a more specific version of bug #8707 with an attempt to provide a minimal reproducing example and a first cause analysis. Edit: Just found another existing issue for that https://github.com/facebook/create-react-app/issues/10315
When working with loaders for web workers there seems to be a race condition in handling the TypeScript compilation, which can cause the compilation to get stuck at: “Files successfully emitted, waiting for typecheck results…”.
Did you try recovering your dependencies?
This has nothing to do with a corrupt dependency tree.
Environment
Environment Info:
current version of create-react-app: 4.0.3
running from /home/fabian/.npm/_npx/c67e74de0542c87c/node_modules/create-react-app
System:
OS: Linux 4.15 Ubuntu 18.04.4 LTS (Bionic Beaver)
CPU: (4) x64 Intel(R) Core(TM) i5-4670 CPU @ 3.40GHz
Binaries:
Node: 14.16.0 - ~/.nvm/versions/node/v14.16.0/bin/node
Yarn: Not Found
npm: 7.6.3 - ~/.nvm/versions/node/v14.16.0/bin/npm
Browsers:
Chrome: 80.0.3987.162
Firefox: 87.0
npmPackages:
react: ^17.0.2 => 17.0.2
react-dom: ^17.0.2 => 17.0.2
react-scripts: 4.0.3 => 4.0.3
npmGlobalPackages:
create-react-app: Not Found
Steps to reproduce
I have setup a reproducing example here. Since the problem involves a race condition, there is no 100% reproduction. In the reproduction example it is roughly 10%, in our real production code it is more like 80%.
The general pattern causing the problem involves loaders for web workers. In my example I’m using comlink-loader
, but issue #8707 shows cases involving other loaders like workerize-loader
.
index.tsx
:
import React from "react";
import ReactDOM from "react-dom";
// No double compilation without these two lines:
import Worker from "./worker";
const worker = new Worker();
ReactDOM.render(
<React.StrictMode>
<div>Hello World</div>
</React.StrictMode>,
document.getElementById("root")
);
// The following code merely exists to slow down the TS compilation
// of this file (it slows it down a lot, several seconds on my machine!).
// To trigger a recompilation change the number suffix (it looks like
// simply re-saving / touching the file isn't sufficient to cause a
// recompilation).
export function complexGeneric1234(name: keyof JSX.IntrinsicElements) {
const wrapped: React.FC<JSX.IntrinsicElements[typeof name]> = (props) =>
React.createElement(name, { ...props }, props.children);
return wrapped;
}
worker/index.ts
:
// eslint-disable-next-line
import Worker from "comlink-loader!./worker";
export default Worker;
worker/worker.ts
:
export function compute(): number {
return 42;
}
worker/custom.d.ts
:
declare module "comlink-loader!*" {
class WebpackWorker extends Worker {
constructor();
compute(): Promise<number>;
}
export = WebpackWorker;
}
Expected behavior
Compilation not stuck.
Actual behavior
Compilation is randomly stuck at WebpackDevServerUtils.js#L187
Files successfully emitted, waiting for typecheck results...
because the promise in WebpackDevServerUtils.js#L192 never completes.
The cause of the problem seems to be a race condition between the callbacks "beforeCompile"
(WebpackDevServerUtils.js#L143-L147) and "afterTypeScriptCheck"
(WebpackDevServerUtils.js#L149-L163). Due to the web worker loader, there are multiple calls to these callbacks, in contrast to just a single call in normal projects.
I have placed console.log
’s in the callbacks, and enforcing a non-interactive execution via npm start | cat
reveals this order in case the compilation gets stuck:
Compiling...
beforeCompile
afterTypeScriptCheck
beforeCompile
Files successfully emitted, waiting for typecheck results...
Note that beforeCompile
gets called a second time after the promise has been completed. This resets the promise to “pending” state, and therefore the compilation gets stuck.
For comparison, this is an execution which did not trigger the problem:
Compiling...
beforeCompile
beforeCompile
Files successfully emitted, waiting for typecheck results...
afterTypeScriptCheck
Compiled with warnings.
Note that this time the second beforeCompile
occurred early enough to not reset the promise. Therefore it looks like it is a race condition between these callbacks.
Reproducible demo
https://github.com/bluenote10/js-debug-projects/tree/master/cra_webworker
Issue Analytics
- State:
- Created 2 years ago
- Reactions:20
- Comments:8
Top GitHub Comments
Sure!
A clean approach would probably require to install the
react-dev-utils
from a local clone using the feature branch.As a quick-and-dirty work-around you basically just need to apply the change in the PR to your local
node_modules/react-dev-utils/WebpackDevServerUtils.js
file. Of course the fix will be reverted e.g. by updating the dependencies.@AlanJereb I have opened PR #10874 that would fix the problem almost two months ago, and since then I’m hoping / begging for a review. I guess the best contribution at that point would be an independent review.
On the other hand, I must admit that it is quite frustrating having sacrificed a weekend investigating the bug and working on a fix, and then there aren’t sufficient maintenance resources available to even get any comment/review 😕
For what it’s worth: We are using the provided fix locally for almost two months now, and it works fine for us.