diff --git a/bin/cmd.js b/bin/cmd.js index c6431a6..abd216f 100755 --- a/bin/cmd.js +++ b/bin/cmd.js @@ -9,6 +9,11 @@ var fromArgs = require('browserify/bin/args'); var w, outfile, verbose, dotfile; var prevErrs = [], first = true; +var alias = { + 'ignore-watch': 'ignoreWatch', + 'delay': 'delay' // to forward delay var to watchify +}; + function showError (err) { if (prevErrs.indexOf(String(err)) < 0) { console.error(err + ''); @@ -17,7 +22,11 @@ function showError (err) { } (function retry () { - w = watchify(fromArgs(process.argv.slice(2))); + var opts = fromArgs(process.argv.slice(2)); + Object.keys(opts.argv).forEach(function(key) { + if (alias[key]) opts[alias[key]] = opts.argv[key]; + }); + w = watchify(opts); outfile = w.argv.o || w.argv.outfile; verbose = w.argv.v || w.argv.verbose; diff --git a/index.js b/index.js index ccbaedb..c544ab3 100644 --- a/index.js +++ b/index.js @@ -3,6 +3,7 @@ var copy = require('shallow-copy'); var browserify = require('browserify'); var fs = require('fs'); var chokidar = require('chokidar'); +var minimatch = require('minimatch'); module.exports = watchify; watchify.browserify = browserify; @@ -21,6 +22,13 @@ function watchify (files, opts) { var pending = false; var changingDeps = {}; var first = true; + + var ignore = [].concat(opts.ignoreWatch || []); + for (var i = 0; i < ignore.length; i++) { + if (typeof ignore[i] === "string") { + ignore[i] = minimatch.makeRe("**/" +ignore[i]); + } + } if (opts.cache) { cache = opts.cache; @@ -38,11 +46,13 @@ function watchify (files, opts) { }); b.on('dep', function (dep) { + if (shouldIgnore(dep.id)) return; cache[dep.id] = dep; - watchFile(dep.id, dep.id); + watchFile(dep.id); }); b.on('file', function (file) { + if (shouldIgnore(file)) return; watchFile(file); }); @@ -104,6 +114,15 @@ function watchify (files, opts) { }, opts.delay || 600); pending = true; } + + function shouldIgnore (file) { + for (var i = 0; i < ignore.length; i++) { + if (file.match(ignore[i])) { + return true; + } + } + return false; + } var bundle = b.bundle.bind(b); b.close = function () { diff --git a/package.json b/package.json index 14bf876..8f463a5 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "optimist": "~0.5.0", "shallow-copy": "0.0.1", "through": "~2.3.4", - "chokidar": "^0.8.1" + "chokidar": "^0.8.1", + "minimatch": "~0.3.0" }, "scripts": { "test": "tape test/*.js" diff --git a/readme.markdown b/readme.markdown index 5f7cb54..99707c0 100644 --- a/readme.markdown +++ b/readme.markdown @@ -1,10 +1,10 @@ # watchify -watch mode for browserify builds +Watch mode for browserify builds [![build status](https://secure.travis-ci.org/substack/watchify.png)](http://travis-ci.org/substack/watchify) -Update any source file and your browserify bundle will be recompiled on the +Update any source file and your browserify bundle will be incrementally recompiled on the spot. # example @@ -33,7 +33,26 @@ $ watchify browser.js -d -o static/bundle.js -v # usage -All the bundle options are the same as the browserify command except for `-v`. +Watchify supports all the same options as the browserify command with the following additions: + +``` + --ignore-watch=GLOB + + Don't attach file watchers to the following glob. + Useful for e.g. ignoring `node_modules` (`--ignore-watch=node_modules/**`) + + --delay=ms [default: 600] + + The number of ms to wait before emitting an 'update' event on a file change. + Set lower to get more immediate updates at the risk of causing multiple bundle changes per save. + It's usually not worth =changing this. + + --verbose, -v + + Verbose mode. Will print to stderr on a rebuild. +``` + +The above options (excepting `verbose`) exist as options to the `watchify()` constructor in camelCase. # methods diff --git a/test/ignore.js b/test/ignore.js new file mode 100644 index 0000000..33d8805 --- /dev/null +++ b/test/ignore.js @@ -0,0 +1,71 @@ +var test = require('tape'); +var fs = require('fs'); +var path = require('path'); +var mkdirp = require('mkdirp'); +var spawn = require('child_process').spawn; +var split = require('split'); + +var cmd = path.resolve(__dirname, '../bin/cmd.js'); +var os = require('os'); +var tmpdir = path.join((os.tmpdir || os.tmpDir)(), 'watchify-' + Math.random()); + +var files = { + main: path.join(tmpdir, 'main.js'), + dep: path.join(tmpdir, 'dep.js'), + bundle: path.join(tmpdir, 'bundle.js') +}; + +mkdirp.sync(tmpdir); +fs.writeFileSync(files.main, 'require("./dep");\nconsole.log(555);'); +fs.writeFileSync(files.dep, 'console.log(222);'); + +test('ignore', function (t) { + t.plan(8); + var ps = spawn(cmd, [ files.main, '-o', files.bundle, '-v', '--ignore-watch=de*' ]); + var lineNum = 0; + ps.stderr.pipe(split()).on('data', function onBundle(line) { + lineNum ++; + if (lineNum === 1) { + run(files.bundle, function (err, output) { + t.ifError(err); + t.equal(output, '222\n555\n'); + fs.writeFile(files.dep, 'console.log(333)'); + // since the bundle won't run + setTimeout(function(){ + t.equal(lineNum, 1); + onBundle(); + }, 1000); + }); + } + else if (lineNum === 2) { + run(files.bundle, function (err, output) { + t.ifError(err); + t.equal(output, '222\n555\n'); + fs.writeFile(files.main, 'require("./dep");\nconsole.log(444);'); + }); + } + else if (lineNum === 3) { + run(files.bundle, function (err, output) { + t.ifError(err); + t.equal(output, '333\n444\n'); + + // Ensure no other events fire + setTimeout(function() { + t.equal(lineNum, 3); + ps.kill(); + }, 500); + }); + } + }); +}); + +function run (file, cb) { + var ps = spawn(process.execPath, [ file ]); + var data = []; + ps.stdout.on('data', function (buf) { data.push(buf) }); + ps.stdout.on('end', function () { + cb(null, Buffer.concat(data).toString('utf8')); + }); + ps.on('error', cb); + return ps; +} diff --git a/test/many.js b/test/many.js index ba18dee..954ca6a 100644 --- a/test/many.js +++ b/test/many.js @@ -57,8 +57,6 @@ fs.writeFileSync(files.lines, 'beep\nboop'); test('many edits', function (t) { t.plan(expected.length * 2 + edits.length); var ps = spawn(cmd, [ files.main, '-t', 'brfs', '-o', files.bundle, '-v' ]); - ps.stdout.pipe(process.stdout); - ps.stderr.pipe(process.stdout); var lineNum = 0; ps.stderr.pipe(split()).on('data', function (line) { if (line.length === 0) return; diff --git a/test/many_immediate.js b/test/many_immediate.js index a7c1c07..2831f93 100644 --- a/test/many_immediate.js +++ b/test/many_immediate.js @@ -57,8 +57,6 @@ fs.writeFileSync(files.lines, 'beep\nboop'); test('many immediate', function (t) { t.plan(expected.length * 2 + edits.length); var ps = spawn(cmd, [ files.main, '-t', 'brfs', '-o', files.bundle, '-v' ]); - ps.stdout.pipe(process.stdout); - ps.stderr.pipe(process.stdout); var lineNum = 0; ps.stderr.pipe(split()).on('data', function (line) { if (line.length === 0) return;