parcel-bundler / watcher

👀 A native C++ Node module for querying and subscribing to filesystem events
MIT License
642 stars 40 forks source link

FSEvents behaves differently compared to inotify with glob excludes #171

Open SamVerschueren opened 2 months ago

SamVerschueren commented 2 months ago

Hey 👋

I was looking into the behaviour of parcel watcher and noticed a difference between macOS (FSEvents) and Linux (inotify). I believe Linux is correct in this one, as it behaves identically as the WASM version.

Let's assume the following code

import * as watcher from '@parcel/watcher';

await watcher.subscribe(
    process.cwd(), 
    (err, events) => {
        console.log(events);
    },
    {
        ignore: ['foo'],
    }
);

You can play around with it in this StackBlitz project.

You will not receive events for either foo, or any of it's children like foo/bar if they are created in the current working directory. This behaves identical on both macOS, Linux, and WASM.

However, if we change the ignore from foo to **/foo, things get interesting.

import * as watcher from '@parcel/watcher';

await watcher.subscribe(
    process.cwd(), 
    (err, events) => {
        console.log(events);
    },
    {
        ignore: ['**/foo'],
    }
);

On macOS, Linux, and WASM, you will not receive events for foo. On Linux and WASM, you will also not receive events for children like foo/bar. However, on macOS, you do receive events for children of foo.

This is also the case for the parcel watcher in VSCode where I used a file system watcher to subscribe to events on a directory.

I don't know if this is expected, but I assume the idea behind parcel-watcher is to have something which works identically on all platforms?

bpasero commented 2 months ago

I think the main difference is that (to my knowledge) on Linux recursive file watching requires to install a watcher per folder, so you need to recursively go down the watch path and install watchers on each node. I think the ignore pattern is applied during that phase, such as **/foo will match on a path bar/foo and then stop events. But on platforms with good file watching support (macOS and Windows), the glob pattern is tested on the full path and that will not match the glob pattern.