paulmillr / chokidar

Minimal and efficient cross-platform file watching library
https://paulmillr.com
MIT License
10.98k stars 580 forks source link

Multiple rules targeting same folder end up ignoring the file #561

Closed laggingreflex closed 5 years ago

laggingreflex commented 7 years ago

With this directory structure:

├─────watch.js
└─────src
      ├─────src.js
      └─────sub
            └─────sub.js

and this is the code:

chokidar.watch([
  'src/**/test/*.js',
  'src/**/*.test.js',
  'tests/**/*.js',
  '{src,lib}/**/*.{js,coffee}',
  '*.{js,coffee}',
], {
  ignored: [
    'node_modules/**',
    '**/node_modules/**'
  ]
})

It doesn't trigger change events for src/sub/sub.js file.

Removing the following makes it work again:

  // 'src/**/test/*.js',
  // 'src/**/*.test.js',
  'tests/**/*.js',
  '{src,lib}/**/*.{js,coffee}',
  '*.{js,coffee}',

The commented out patterns are causing the problem. Is this a bug, or does the array actually control specificity?

Windows 10, node v7, chokidar: v1.6.1

repro: https://github.com/laggingreflex/chokidar-test-561

laggingreflex commented 7 years ago

It seems from the code that it really is about adding more specificity. If one of the two globs in the array could match the same path, and one of them chooses to ignore a file, it will prefer ignoring the file. So in above case since src/**/test/*.js ignores src/sub/sub.js it ends up ignoring it, even though {src,lib}/**/*.{js,coffee} should've included it.

I've arrived at this conclusion from NodeFsHandler.prototype._addToNodeFs where it accepts and passes on forward a priorWh object which seems to add or reuse a filterPath which is then passed to readdirp, effectively making readdirp filter all paths that all previous globs flagged for ignoring.

If you comment out the section where it "inherits" priorWh the problem goes away*.

  // if (!wh.hasGlob && priorWh) {
  //   wh.hasGlob = priorWh.hasGlob;
  //   wh.globFilter = priorWh.globFilter;
  //   wh.filterPath = priorWh.filterPath;
  //   wh.filterDir = priorWh.filterDir;
  // }

*not being able to watch src/sub/sub.js wasn't the only problem it seems, it was also not firing "ready" event as mentioned in somewhat related #449, but that's probably a different problem, and it's still not solved by the above solution.

laggingreflex commented 7 years ago

All tests still pass with above code commented out. @es128 does it serve an important purpose? It seems it was added in https://github.com/paulmillr/chokidar/commit/871f3461761eeaa96b40388baf83718aa547ec1a. FsEventsHandler.prototype._addToFsEvents doesn't appear to have any such logic.

es128 commented 7 years ago

Reusing watch handles has to do with efficient resource utilization on the machine - we used to see users hitting system limits often for certain use cases.

This is a bug that needs to be addressed, but not by ripping out the resource controls if it can be avoided. Seems we need either an exclusion on the reuse for conflicting/intersecting globs with the same parent, or some way to account for multiple patterns in filterPath.

hoschi commented 7 years ago

I run into the same problem with chockidar@1.6.1 while debugging https://github.com/avajs/ava

my files look like:

frontend > find src/widgets/banner
src/widgets/banner
src/widgets/banner/bannerReducer.test.js
src/widgets/banner/BannerItem.test.js
src/widgets/banner/bannerReducer.js
src/widgets/banner/BannerContainer.test.js
src/widgets/banner/BannerItem.js
src/widgets/banner/BannerContainer.js
src/widgets/banner/bannerItem.scss
src/widgets/banner/bannerSaga.test.js
src/widgets/banner/bannerTestData.js
src/widgets/banner/BannerItem.stories.js
src/widgets/banner/bannerSaga.js
src/widgets/banner/Banner.stories.js
src/widgets/banner/banner.scss

patterns watched: [ 'src/**/*.js', 'src/widgets/banner/**/*.test.js' ] patterns ignored:

[ '.git/**/*',
  '.nyc_output/**/*',
  '.sass-cache/**/*',
  'bower_components/**/*',
  'coverage/**/*',
  'node_modules/**/*' ]

When I call watcher.getWatched() on my Arch linux (node: 6.3.1, kernel: 4.9.8-1) I get

[ 'BannerContainer.test.js',
  'BannerItem.test.js',
  'bannerReducer.test.js',
  'bannerSaga.test.js' ]

as described from OP the second watch pattern overrides the general one.

But when I run the same code on Mac (node: 6.4.0, system: macOS 10.12.3 (16D32), kernel: Darwin 16.4.0) it works as expected:

[ 'Banner.stories.js',
  'BannerContainer.js',
  'BannerContainer.test.js',
  'BannerItem.js',
  'BannerItem.stories.js',
  'BannerItem.test.js',
  'bannerReducer.js',
  'bannerReducer.test.js',
  'bannerSaga.js',
  'bannerSaga.test.js',
  'bannerTestData.js' ]

Is this bug just on some plattforms?

jwx commented 7 years ago

Any movement on this?

alex-shamshurin commented 6 years ago

Two years later the same problem

alex-shamshurin commented 6 years ago

I noticed that it works when if specify files with glob patterns, i.e chokidar.watch(['package.json', 'yarn.lock', 'otherFile.js']) won't work from the same dir, but chokidar.watch(['pac*.json', 'yarn.*', 'otherF*.js']) will work.

fidian commented 5 years ago

I also have this problem when trying to glob against multiple file extensions.

// Notices only *.ts
chokidar.watch(['src/**/*.ts', 'src/**/*.html'])

// Notices everything
chokidar.watch(['src/**/*.{ts,html}'])
paulmillr commented 5 years ago

Works correctly for me with chokidar 3.2.0-pre (npm i github:paulmillr/chokidar), tested Ubuntu and MacOS.

onetrev commented 4 years ago

If someone else is finding this issue, maybe this is exactly how it's supposed to work? But I found a work around by adding in an additional watch item. For example I was watching for all PHP file changes in my entire project, and also watching for CSS changes in certain paths. But then it stopped looking for PHP changes in those same paths. So I simply added a watch for PHP files in the same path.

chokidar.watch([
        './**/*.php',
        './template-parts/blocks/**/*.css',
        './template-parts/blocks/**/*.php'
      ])