Skip to content

Commit

Permalink
Merge pull request #106 from webpack/feature/ignored
Browse files Browse the repository at this point in the history
add `ignored` option
  • Loading branch information
sokra committed May 16, 2019
2 parents c1f18f7 + 529823d commit 9689e42
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 5 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ var wp = new Watchpack({
// poll defaults to undefined, which prefer native watching methods
// Note: enable polling when watching on a network path
// When WATCHPACK_POLLING environment variable is set it will override this option

ignored: "**/.git",
// ignored: "string" - a glob pattern for files or folders that should not be watched
// ignored: ["string", "string"] - multiple glob patterns that should be ignored
// All subdirectories are ignored too
});

// Watchpack.prototype.watch(files: string[], directories: string[], startTime?: number)
Expand Down
17 changes: 15 additions & 2 deletions lib/DirectoryWatcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class DirectoryWatcher extends EventEmitter {
this.directories = new Map();
this.lastWatchEvent = 0;
this.initialScan = true;
this.ignored = options.ignored;
this.nestedWatching = false;
this.polledWatching = typeof options.poll === "number" ? options.poll : options.poll ? 5007 : false;
this.initialScanRemoved = new Set();
Expand All @@ -75,9 +76,14 @@ class DirectoryWatcher extends EventEmitter {
this.doScan(true);
}

checkIgnore(path) {
if(!this.ignored) return false;
path = path.replace(/\\/g, "/");
return this.ignored.test(path);
}

createWatcher() {
try {
// TODO options.ignored
if(this.polledWatching) {
// Poll for changes
const interval = setInterval(() => {
Expand Down Expand Up @@ -140,6 +146,9 @@ class DirectoryWatcher extends EventEmitter {

setFileTime(filePath, mtime, initial, ignoreWhenEqual, type) {
const now = Date.now();

if(this.checkIgnore(filePath)) return;

const old = this.files.get(filePath);

let safeTime, accuracy;
Expand Down Expand Up @@ -176,6 +185,7 @@ class DirectoryWatcher extends EventEmitter {
}

setDirectory(directoryPath, mtime, initial, type) {
if(this.checkIgnore(directoryPath)) return;
if(directoryPath === this.path) {
if(!initial) {
this.forEachWatcher(this.path, w => w.emit("change", directoryPath, mtime, type));
Expand Down Expand Up @@ -300,12 +310,15 @@ class DirectoryWatcher extends EventEmitter {
this.doScan(false);
return;
}

const filePath = path.join(this.path, filename);
if(this.checkIgnore(filePath)) return;

if(this._activeEvents.get(filename) === undefined) {
this._activeEvents.set(filename, false);
const checkStats = () => {
if(this.closed) return;
this._activeEvents.set(filename, false);
const filePath = path.join(this.path, filename);
fs.stat(filePath, (err, stats) => {
if(this.closed) return;
if(this._activeEvents.get(filename) === true) {
Expand Down
32 changes: 29 additions & 3 deletions lib/watchpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

const watcherManager = require("./watcherManager");
const EventEmitter = require("events").EventEmitter;
const globToRegExp = require("glob-to-regexp");

let EXISTANCE_ONLY_TIME_ENTRY; // lazy required

Expand All @@ -18,14 +19,36 @@ function addWatchersToSet(watchers, set) {
}
}

const stringToRegexp = ignored => {
const source = globToRegExp(ignored, { globstar: true, extended: true }).source;
const matchingStart = source.slice(0, source.length - 1) + "(?:$|\\/)";
return matchingStart;
}

const ignoredToRegexp = ignored => {
if(Array.isArray(ignored)) {
return new RegExp(
ignored.map(i =>
stringToRegexp(i)
).join("|")
);
} else if(typeof ignored === "string") {
return new RegExp(stringToRegexp(ignored));
} else if(ignored) {
throw new Error(`Invalid option for 'ignored': ${ignored}`);
} else {
return undefined;
}
}

class Watchpack extends EventEmitter {
constructor(options) {
super();
if(!options) options = {};
if(!options.aggregateTimeout) options.aggregateTimeout = 200;
this.options = options;
this.watcherOptions = {
ignored: options.ignored,
ignored: ignoredToRegexp(options.ignored),
poll: options.poll
};
this.fileWatchers = [];
Expand All @@ -41,10 +64,13 @@ class Watchpack extends EventEmitter {
this.paused = false;
const oldFileWatchers = this.fileWatchers;
const oldDirWatchers = this.dirWatchers;
this.fileWatchers = files.map(file =>
const filter = this.watcherOptions.ignored
? path => !this.watcherOptions.ignored.test(path.replace(/\\/g, "/"))
: () => true;
this.fileWatchers = files.filter(filter).map(file =>
this._fileWatcher(file, watcherManager.watchFile(file, this.watcherOptions, startTime))
);
this.dirWatchers = directories.map(dir =>
this.dirWatchers = directories.filter(filter).map(dir =>
this._dirWatcher(dir, watcherManager.watchDirectory(dir, this.watcherOptions, startTime))
);
oldFileWatchers.forEach(w => w.close());
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"should": "^8.3.1"
},
"dependencies": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2",
"neo-async": "^2.5.0"
},
Expand Down
87 changes: 87 additions & 0 deletions test/Watchpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,32 @@ describe("Watchpack", function() {
});
});

it("should not watch a single ignored file", function(done) {
var w = new Watchpack({
aggregateTimeout: 300,
ignored: "**/a"
});
var changeEvents = 0;
var aggregatedEvents = 0;
w.on("change", () => {
changeEvents++;
});
w.on("aggregated", () => {
aggregatedEvents++;
});
w.watch([path.join(fixtures, "a")], []);
testHelper.tick(() => {
testHelper.file("a");
testHelper.tick(1000, () => {
changeEvents.should.be.eql(0);
aggregatedEvents.should.be.eql(0);
testHelper.getNumberOfWatchers().should.be.eql(0);
w.close();
done();
});
});
});

it("should watch multiple files", function(done) {
var w = new Watchpack({
aggregateTimeout: 1000
Expand Down Expand Up @@ -104,6 +130,67 @@ describe("Watchpack", function() {
});
});

it("should not watch an ignored directory", function(done) {
var w = new Watchpack({
aggregateTimeout: 300,
ignored: [
"**/dir"
]
});
var changeEvents = 0;
var aggregatedEvents = 0;
w.on("change", () => {
changeEvents++;
});
w.on("aggregated", () => {
aggregatedEvents++;
});
testHelper.dir("dir");
testHelper.tick(200, function() {
w.watch([], [path.join(fixtures, "dir")]);
testHelper.tick(200, function() {
testHelper.file(path.join("dir", "a"));
testHelper.tick(1000, function() {
changeEvents.should.be.eql(0);
aggregatedEvents.should.be.eql(0);
testHelper.getNumberOfWatchers().should.be.eql(0);
w.close();
done();
});
});
});
});

it("should not watch an ignored file in a directory", function(done) {
var w = new Watchpack({
aggregateTimeout: 300,
ignored: [
"**/a"
]
});
var changeEvents = 0;
var aggregatedEvents = 0;
w.on("change", () => {
changeEvents++;
});
w.on("aggregated", () => {
aggregatedEvents++;
});
testHelper.dir("dir");
testHelper.tick(200, function() {
w.watch([], [path.join(fixtures, "dir")]);
testHelper.tick(200, function() {
testHelper.file(path.join("dir", "a"));
testHelper.tick(1000, function() {
changeEvents.should.be.eql(0);
aggregatedEvents.should.be.eql(0);
w.close();
done();
});
});
});
});

it("should watch a file then a directory", function(done) {
var w = new Watchpack({
aggregateTimeout: 1000
Expand Down
4 changes: 4 additions & 0 deletions test/helpers/TestHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,7 @@ TestHelper.prototype.tick = function tick(arg, fn) {
fn();
}, arg);
};

TestHelper.prototype.getNumberOfWatchers = function getNumberOfWatchers() {
return Object.keys(watcherManager.directoryWatchers).length;
};
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,11 @@ getpass@^0.1.1:
dependencies:
assert-plus "^1.0.0"

glob-to-regexp@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==

glob@7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
Expand Down

0 comments on commit 9689e42

Please sign in to comment.