Repository: webpack/webpack (JavaScript)

Issue:
webpack compiling twice on startup when importing a file within a typescript react setup
# Bug report

**What is the current behavior?**

Working on a TypeScript React project when running webpack the compilation happens twice at startup. This happens when a file is being imported from the root react `index.tsx`.
Not sure if its similar to https://github.com/webpack/webpack/issues/13618?

**If the current behavior is a bug, please provide the steps to reproduce.**
1. https://github.com/bahtou/issues/tree/webpack-rebuild
2. follow the readme

you should be able to see two rebuilds
```
👀   1 . compilation afterEmit 2021-11-18T22:01:58.573Z
👀   1 . compilation is done 2021-11-18T22:01:58.575Z
```
```
👀   2 . compilation afterEmit 2021-11-18T22:01:58.872Z
👀   2 . compilation is done 2021-11-18T22:01:58.872Z
```

**What is the expected behavior?**

compilation should only run once

**Other relevant information:**
webpack version:  5.64.1
Node.js version: v14.18.1
Operating System: OSX
Additional tools: none



Hints:
I think this is related to https://github.com/webpack/webpack/pull/14735.

The invalidation comes from 
```
_invalidate(..., ..., Set(0) {} Set(2) {
  '/workspaces/issues/node_modules/package.json/package.json',
  '/workspaces/issues/node_modules/swc-loader.js/package.json'
}
```
This indicated that watchpack.watch is called with these invalid file entries. When encountering these paths, it then tries to adds watchers for these files, fails (because they dont exist `"initial-missing / scan (parent directory missing in initial scan)"`) and marks them as removed.
I think it has nothing with TS. My JS repo has the same issue and it compile 3 times.
I can 120% confirm 5.64.0 work fine and it only happen at 5.64.1
@wood1986 I switched to webpack v5.64.0 and I still get the double compilation. With the repo above you can test it out. Agree that it has nothing to do with TS. The webpack config is not using TS for anything. I just mentioned it since I was setting up a new project.
Yep, it is bug
@bahtou `v5.64.0` doesn't have this problem, just tested on your repo
@alexander-akait I just cloned the repo and updated the webpack package to 5.64.0.
I'm still getting double compilation  🤔 🤔 
> `rm -rf node_modules package-lock.json`
> `npm install`
> `npm start`

**UPDATE**
`"webpack": "^5.64.0",`  the caret `^` was throwing me off. Removing the `^`.

`v5.64.0` DOES NOT have the issue. 👍🏽 
Yep...

Patch:
diff --git a/lib/FileSystemInfo.js b/lib/FileSystemInfo.js
--- a/lib/FileSystemInfo.js
+++ b/lib/FileSystemInfo.js
@@ -2256,7 +2256,9 @@ class FileSystemInfo {
 		for (const path of managedItems) {
 			const cache = this._managedItems.get(path);
 			if (cache !== undefined) {
-				managedFiles.add(join(this.fs, path, "package.json"));
+				if (cache !== "missing") {
+					managedFiles.add(join(this.fs, path, "package.json"));
+				}
 				managedItemInfo.set(path, cache);
 			} else {
 				jobs++;
@@ -2269,7 +2271,9 @@ class FileSystemInfo {
 						}
 						jobError();
 					} else if (entry) {
-						managedFiles.add(join(this.fs, path, "package.json"));
+						if (entry !== "missing") {
+							managedFiles.add(join(this.fs, path, "package.json"));
+						}
 						managedItemInfo.set(path, entry);
 						jobDone();
 					} else {


Test patch:
diff --git a/test/Watch.test.js b/test/Watch.test.js
new file mode 100644
--- /dev/null
+++ b/test/Watch.test.js
@@ -0,0 +1,61 @@
+"use strict";
+
+require("./helpers/warmup-webpack");
+
+const path = require("path");
+const webpack = require("..");
+const { createFsFromVolume, Volume } = require("memfs");
+
+describe("Watch", () => {
+	jest.setTimeout(10000);
+
+	it("should only compile a single time", done => {
+		let counterBeforeCompile = 0;
+		let counterDone = 0;
+		let counterHandler = 0;
+		const compiler = webpack(
+			{
+				context: path.resolve(__dirname, "fixtures/watch"),
+				watch: true,
+				mode: "development",
+				snapshot: {
+					managedPaths: [/^(.+?[\\/]node_modules[\\/])/]
+				},
+				experiments: {
+					futureDefaults: true
+				},
+				module: {
+					// unsafeCache: false,
+					rules: [
+						{
+							test: /\.js$/,
+							use: "some-loader"
+						}
+					]
+				},
+				plugins: [
+					c => {
+						c.hooks.beforeCompile.tap("test", () => {
+							counterBeforeCompile++;
+						});
+						c.hooks.done.tap("test", () => {
+							counterDone++;
+						});
+					}
+				]
+			},
+			(err, stats) => {
+				if (err) return done(err);
+				if (stats.hasErrors()) return done(new Error(stats.toString()));
+				counterHandler++;
+			}
+		);
+		compiler.outputFileSystem = createFsFromVolume(new Volume());
+		setTimeout(() => {
+			expect(counterBeforeCompile).toBe(1);
+			expect(counterDone).toBe(1);
+			expect(counterHandler).toBe(1);
+			compiler.close(done);
+		}, 5000);
+	});
+});
diff --git a/test/fixtures/watch/node_modules/inline-loader/index.js b/test/fixtures/watch/node_modules/inline-loader/index.js
new file mode 100644
--- /dev/null
+++ b/test/fixtures/watch/node_modules/inline-loader/index.js
@@ -0,0 +1,3 @@
+module.exports = function(x) {
+	return x;
+}
diff --git a/test/fixtures/watch/node_modules/inline-loader/package.json b/test/fixtures/watch/node_modules/inline-loader/package.json
new file mode 100644
--- /dev/null
+++ b/test/fixtures/watch/node_modules/inline-loader/package.json
@@ -0,0 +1,4 @@
+{
+  "name": "inline-loader",
+  "version": "1.0.0"
+}
diff --git a/test/fixtures/watch/node_modules/nested-package1/index.js b/test/fixtures/watch/node_modules/nested-package1/index.js
new file mode 100644
diff --git a/test/fixtures/watch/node_modules/nested-package1/package.json b/test/fixtures/watch/node_modules/nested-package1/package.json
new file mode 100644
--- /dev/null
+++ b/test/fixtures/watch/node_modules/nested-package1/package.json
@@ -0,0 +1,4 @@
+{
+  "name": "nested-package1",
+  "version": "1.0.0"
+}
diff --git a/test/fixtures/watch/node_modules/package/index.js b/test/fixtures/watch/node_modules/package/index.js
new file mode 100644
--- /dev/null
+++ b/test/fixtures/watch/node_modules/package/index.js
@@ -0,0 +1,4 @@
+import "nested-package1";
+import "nested-package2";
+import "inline-loader!nested-package1";
+import "inline-loader!nested-package2";
diff --git a/test/fixtures/watch/node_modules/package/node_modules/nested-package2/index.js b/test/fixtures/watch/node_modules/package/node_modules/nested-package2/index.js
new file mode 100644
diff --git a/test/fixtures/watch/node_modules/package/node_modules/nested-package2/package.json b/test/fixtures/watch/node_modules/package/node_modules/nested-package2/package.json
new file mode 100644
--- /dev/null
+++ b/test/fixtures/watch/node_modules/package/node_modules/nested-package2/package.json
@@ -0,0 +1,4 @@
+{
+  "name": "nested-package2",
+  "version": "1.0.0"
+}
diff --git a/test/fixtures/watch/node_modules/package/package.json b/test/fixtures/watch/node_modules/package/package.json
new file mode 100644
--- /dev/null
+++ b/test/fixtures/watch/node_modules/package/package.json
@@ -0,0 +1,4 @@
+{
+  "name": "package",
+  "version": "1.0.0"
+}
diff --git a/test/fixtures/watch/node_modules/some-loader/index.js b/test/fixtures/watch/node_modules/some-loader/index.js
new file mode 100644
--- /dev/null
+++ b/test/fixtures/watch/node_modules/some-loader/index.js
@@ -0,0 +1,3 @@
+module.exports = function(x) {
+	return x;
+}
diff --git a/test/fixtures/watch/node_modules/some-loader/package.json b/test/fixtures/watch/node_modules/some-loader/package.json
new file mode 100644
--- /dev/null
+++ b/test/fixtures/watch/node_modules/some-loader/package.json
@@ -0,0 +1,4 @@
+{
+  "name": "some-loader",
+  "version": "1.0.0"
+}
diff --git a/test/fixtures/watch/src/index.js b/test/fixtures/watch/src/index.js
new file mode 100644
--- /dev/null
+++ b/test/fixtures/watch/src/index.js
@@ -0,0 +1,5 @@
+import "package";
+import "inline-loader!package";
+
+import "./local";
+import "inline-loader!./local";
diff --git a/test/fixtures/watch/src/local.js b/test/fixtures/watch/src/local.js
new file mode 100644
--- /dev/null
+++ b/test/fixtures/watch/src/local.js
@@ -0,0 +1,2 @@
+import "package";
+import "inline-loader!package";