Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Watched directory is reported as initial-missing if has no files #224

Closed
WiseBird opened this issue Dec 5, 2022 · 6 comments · Fixed by #237
Closed

Watched directory is reported as initial-missing if has no files #224

WiseBird opened this issue Dec 5, 2022 · 6 comments · Fixed by #237

Comments

@WiseBird
Copy link

WiseBird commented Dec 5, 2022

Causes webpack to constantly recompile as the directory is reported as removed:
image

Tried to reproduce but it works fine (more details below).

Basically, the culprit is the watch method of the DirectoryWatcher class, when it is triggered for the already inited directory.

The method is triggered from the WatcherManager class:

	watchDirectory(directory, startTime) {
                // you can notice that we trigger watch for the same directory that we created watcher for
		return this.getDirectoryWatcher(directory).watch(directory, startTime);
	}

The flow looks like this:

	watch(filePath, startTime) {
		// doesn't matter

		let safeTime;
		if (filePath === this.path) { // this is true due to the way we triggered watch (from watchDirectory)
			this.setNestedWatching(true);
			safeTime = this.lastWatchEvent;
			for (const entry of this.files.values()) { // files collection is empty as we don't have any files in the directory
				fixupEntryAccuracy(entry);
				safeTime = Math.max(safeTime, entry.safeTime);
			}
		} else {
			// skipped 
		}

		if (safeTime) { // safeTime is undefined, as we have no files
			// skipped
		} else if (this.initialScan) { // false, as it's already been scanned
			// ignored
		} else if (
			!this.directories.has(filePath) && // true as the watched directory doesn't have itself in the list of sub directories
			watcher.checkStartTime(this.initialScanFinished, false) // here it's more tricky, in my real app this is true but in the reproduction I mentioned above it's false
		) {
			process.nextTick(() => {
				if (this.closed) return;
				watcher.emit("initial-missing", "watch (missing on attach)"); // here we trigger the initial-missing event
			});
		}
		return watcher;
	}

My suggestion would be to additionally check that the filePath doesn't not equal to this.path before triggering initial-missing event, but maybe I am missing something.

@alexander-akait
Copy link
Member

I think such case is for nested empty directories

@WiseBird
Copy link
Author

WiseBird commented Dec 6, 2022

Do you mean it works as expected?

@alexander-akait
Copy link
Member

Yeah, because we need to track them too, what is the problem with it? Maybe you can provide example?

@WiseBird
Copy link
Author

WiseBird commented Dec 9, 2022

Problem is that directory is not really missing, but DirectoryWatcher reports it as missing and Webpack keeps recompiling the code as it thinks that there are some changes.

And I am not saying that we should remove the check completely, I am saying that we don't need it when filePath === this.path because we will never find the directory inside itself (in other words !this.directories.has(filePath) is always true for filePath === this.path case)

@alexander-akait
Copy link
Member

@WiseBird Sounds resonable can you send a PR? Also we will check all our test cases

@BR0kEN-
Copy link

BR0kEN- commented Jun 7, 2023

Stumbled upon this too.

There is a function that results in setting up 3 directories watchers by Webpack:

export function importVueFile(path: string): Promise<Component> {
  // The app-specific component always prevails.
  cache.files[path] ??= import(`@/apps/${__APP_ID__}/components/${path}.vue`)
    // The fallback - is a component within the app's family.
    .catch(() => import(`@/apps/${__APP_FAMILY__}/components/${path}.vue`))
    // The last try goes to a global component.
    .catch(() => import(`@/components/${path}.vue`))
    .catch((error) => {
      // eslint-disable-next-line no-console
      console.error(error);

      return {
        inheritAttrs: false,
        template: `There is no "${path}" component!`,
      };
    });

  return cache.files[path];
}

And, ironically, none of them have files inside - only child dirs:

docker@cli:/var/www/app/vendor/REDACTED/REDACTED$ ls -la /var/www/app/vendor/REDACTED/REDACTED/resources/js/apps/REDACTED/components
total 0
drwxr-xr-x  3 docker dialout  96 Jun  7 12:58 .
drwxr-xr-x  4 docker dialout 128 Jun  7 12:58 ..
drwxr-xr-x 12 docker dialout 384 Jun  7 10:39 pages
docker@cli:/var/www/app/vendor/REDACTED/REDACTED$ ls -la /var/www/app/vendor/REDACTED/REDACTED/resources/js/components
total 0
drwxr-xr-x  8 docker dialout  256 Jun  7 12:58 .
drwxr-xr-x 15 docker dialout  480 Jun  7 12:58 ..
drwxr-xr-x  3 docker dialout   96 Mar 14 17:05 dashboard
drwxr-xr-x 34 docker dialout 1088 Jun  7 12:58 elements
drwxr-xr-x 16 docker dialout  512 Jun  7 12:58 form
drwxr-xr-x  3 docker dialout   96 Apr  7 00:35 layouts
drwxr-xr-x  4 docker dialout  128 Jun  5 20:58 pages
drwxr-xr-x 10 docker dialout  320 Jun  7 12:58 structure
docker@cli:/var/www/app/vendor/REDACTED/REDACTED$ ls -la /var/www/app/vendor/REDACTED/REDACTED/resources/js/apps/REDACTED/components
total 0
drwxr-xr-x 3 docker dialout  96 Jun  5 20:58 .
drwxr-xr-x 7 docker dialout 224 Jun  7 12:58 ..
drwxr-xr-x 8 docker dialout 256 Jun  7 12:58 elements

Once I created one empty index.ts inside each of those 3 dirs, the looped watch rebuild stopped reporting them as removed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants