diff --git a/.gitignore b/.gitignore
index 1cd3404..2aa68ad 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,4 +3,7 @@ node_modules
*.log
.DS_Store
bundle.js
-bundle-expected.js
\ No newline at end of file
+bundle-expected.js
+.tmp
+*.swp
+*.swo
diff --git a/.npmignore b/.npmignore
index 1663f92..ec15756 100644
--- a/.npmignore
+++ b/.npmignore
@@ -9,4 +9,5 @@ demo/
docs/
example/
.npmignore
+.tmp
LICENSE.md
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..eb80bb5
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,10 @@
+language: node_js
+node_js:
+ - "0.8"
+ - "0.10"
+ - "0.12"
+ - "4.0"
+ - "4.1"
+ - "5.0"
+before_install:
+ - npm install -g npm@~2.14.5
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..ddc1580
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,160 @@
+# 8.2.0
+
+Add support for SSL (HTTPS) with `--ssl`, `--cert` and `--key` options.
+
+# 8.1.0
+
+Add `--cors` flag to enable `Access-Control-Allow-Origin: *`
+
+# 8.0.4
+
+Bump required deps.
+
+# 8.0.3
+
+Fix `opts.live` as a string, allowing an array of options to be passed to filter file names.
+
+# 8.0.2
+
+Fix flow so that bundling events start after server connects, also updated upstream in watchify-middleware.
+
+# 8.0.1
+
+Fix parsing issue with LiveReload resp modifier.
+
+# 8.0.0
+
+The server code has been refactored to use connect/express-style middleware stacking. Fixes [#80](https://github.com/mattdesl/budo/issues/80), [#79](https://github.com/mattdesl/budo/issues/79), [#124](https://github.com/mattdesl/budo/issues/124), [#128](https://github.com/mattdesl/budo/issues/128).
+
+##### Major Changes
+
+Functions for `opts.middleware` now assumes the following signature, and will not behave differently based on the number of arguments you specify:
+
+ - `middleware(req, res, next)`
+
+##### Minor Changes
+
+The `middleware` options can now be an array of functions, or a single function.
+
+# 7.1.0
+
+Added `--watch-glob` option which allows you to override the default watch glob without having to go through the `live()` / `watch()` API
+
+# 7.0.4
+
+Small patch [#117](https://github.com/mattdesl/budo/pull/117) to fix a failing test in 7.0.3.
+
+# 7.0.3
+
+- Bole no longer double-logs on shut-down and re-start.
+- Fixed issue with request sizes being logged incorrectly in terminal
+
+# 7.0.1 .. 7.0.2
+
+Small patches for [#110](https://github.com/mattdesl/budo/pull/110) and [#111](https://github.com/mattdesl/budo/pull/111).
+
+# 7.0.0
+
+Fixes previous patch and also updates to garnish redesign, leading to new log styles.
+
+Since various ndjson flags have changed, this is a potentially breaking change.
+
+Also added a `--verbose` / `-v` option like watchify, which adds some additional debug messages.
+
+# 6.1.1
+
+Fixes live reload for directory routes like `localhost:9966/mydir`.
+
+# 6.1.0
+
+Search for `index.html` across all static `--dir` folders, finding the first one.
+
+# 6.0.0
+
+##### Major Changes
+
+- `garnish` is now included by default in CLI and API
+ - you can use `--ndjson` and `ndjson: true` to have raw output (for custom pretty-printers)
+
+##### Minor Changes
+
+- added `--title` option for the default HTML title
+- added `--css` option for a default style sheet
+
+# 5.0.0
+
+##### Major Changes
+
+- you can just type `budo . | garnish` for the entry point (or `index.js`)
+- added `--onupdate` for things like linting, see [the docs](docs/command-line-usage.md#--onupdate)
+- if no `--host` is specified, resolves to internal IP
+ - you can still hit `localhost:9966` and it will work
+- the `
+```
+
+You can specify a different end point for the server with a colon. This is useful for relative and absolute paths, for example:
+
+```sh
+budo /proj/foo/index.js:static/bundle.js
+```
+
+Now, you can use the following as your HTML:
+
+```html
+
+```
+
+Also see the [`--serve` option](#multiple entries).
+
+## local installation
+
+If you are using these in your modules for demos/etc, you should save them locally so that others can get the same versions when they `git clone` and `npm install` your repo.
+
+```sh
+npm install budo --save-dev
+```
+
+For local tools, we need to use [npm-scripts](https://docs.npmjs.com/misc/scripts). Open up your package.json and update `"scripts"` so it looks like this:
+
+```sh
+ "scripts": {
+ "start": "budo index.js"
+ },
+```
+
+Now running the following will start the development server:
+
+```sh
+npm run start
+```
+
+## live reload
+
+budō also includes support for [LiveReload](livereload.com). The `--live` argument injects a script tag into your HTML file and listens for a live reload server.
+
+```sh
+budo index.js --live
+```
+
+Now when you save the `index.js` file, it will trigger a LiveReload event on your `localhost:9966` tab after watchify has finished bundling. It also listens to HTML and CSS reload, and injects stylesheets without a page refresh.
+
+From the command line, you can specify a filename glob to only trigger LiveReload in those cases. For example, to only allow CSS and HTML changes to trigger a LiveReload:
+
+```sh
+budo index.js --live=*.{html,css}
+```
+
+*Note:* Your `index.html` must have a `
` tag for the LiveReload script to get injected!
+
+## multiple entries
+
+Budo also supports multiple entry points; they will all get concatenated into a single bundle. If you aren't using a colon separator (`:`), the entry point will default to the first path. Or, you can explicitly set the path with the `--serve` option, as below:
+
+```sh
+budo test/one.js test/two.js --serve static/bundle.js
+```
+
+Note the path here is relative to your `--dir` folder from where the `index.html` is being served.
+
+## browserify arguments
+
+Everything after the `--` argument will not be parsed/manipulated, and will be passed directly to browserify.
+
+```sh
+budo main.js --live -- -t babelify -t glslify
+```
+
+You can also add a [`"browserify"` field](https://github.com/substack/browserify-handbook#browserifytransform-field) to your `package.json` file, and budo will use that config. This is not typically recommended for modules, but it can be useful when building applications.
+
+## launch
+
+To launch the browser once the server connects, you can use the `--open` or `-o` flag:
+
+```sh
+budo index.js --open
+```
+
+Also see [opnr](https://github.com/mattdesl/opnr), which allows for a similar functionality without forcing it as a command-line flag.
+
+## `--onupdate`
+
+In the CLI, you can run shell commands when the bundle updates using the `--onupdate` option. For example, to lint with [standard](https://github.com/feross/standard) and provide an alert with [notify-error](https://github.com/mattdesl/notify-error):
+
+```sh
+budo index.js --onupdate "standard | notify-error"
+```
+
+Now, when you save the bundle, `standard` will run on your directory. If lint errors are found, they will print to the console and show an alert notification:
+
+
+
+The flag is only available in the command-line.
+
+## internal IP
+
+By default, budo's server will listen on your internal IP. This address is the first message logged to terminal.
+
+This makes it easy to test during development across devices.
+
+You can specify another address with the `--host` flag.
+
+## pushstate
+
+You can set a `--pushstate` flag to make the server capable for HTML5 pushState Single-Page Applications.
+
+Now, any 404 requests (such as `/foo/bar/blah`) will get routed to the home `index.html`.
+
+It is suggested you add a `` in your `index.html` for this to work with nested paths:
+
+```html
+
+
+
+
+
+```
+
+## hot module replacement
+
+The following can integrate easily with budo:
+
+- Generic HMR: [browserify-hmr](https://github.com/AgentME/browserify-hmr)
+- React: [livereactload](https://github.com/milankinen/livereactload)
+- Vue: [vueify](https://github.com/vuejs/vueify) (to be used with `browserify-hmr`)
+
+You can usually follow the steps in those tools, except instead of using `watchify`, we will use `budo` and pass our browserify options after a full stop `--`.
+
+Example with [livereactload](https://github.com/milankinen/livereactload):
+
+```sh
+budo index.js:bundle.js -- -t babelify -p livereactload
+```
+
+Make sure you don't pass a `--live` flag to budo, otherwise it will trigger hard reloads on file save.
\ No newline at end of file
diff --git a/docs/comparisons.md b/docs/comparisons.md
deleted file mode 100644
index 31657ca..0000000
--- a/docs/comparisons.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# comparisons
-
-## budō
-
-[budō](https://github.com/mattdesl/budo) lies somewhere between the rich feature set of [Beefy](#beefy) and the small focus of [wzrd](#wzrd). It spawns a watchify process, produces ndjson logs, and includes some more experimental features for live-reloading, [script injection](https://github.com/mattdesl/budo-chrome), and rapid prototyping.
-
-## beefy
-
-[Beefy](https://github.com/chrisdickinson/beefy) is a feature-rich dev tool for browserify, and much of the inspiration for this project. However, it currently has some shortcomings[[1]](https://github.com/chrisdickinson/beefy/issues/49)[[2]](https://github.com/chrisdickinson/beefy/issues/63) and often feels clunky to deliver as a local dependency. It also takes a different approach to bundling, by using watchify's programmatic API rather than [execspawn](https://www.npmjs.com/package/npm-execspawn).
-
-```sh
-#example ...
-beefy index.js --open
-```
-
-## wzrd
-
-[wzrd](https://github.com/maxogden/wzrd) is a tiny spin-off of beefy that is ideal for [local dependencies](https://github.com/stackgl/learning-webgl-03/blob/db8f36a534b2a184924f8b890014ff3dd9a5b391/package.json#L6-L9). It introduces some novel ideas like entry mapping and ndjson output with tools like [garnish](https://github.com/mattdesl/garnish).
-
-However, incremental bundling is likely outside of its scope.
-
-```sh
-#example ...
-wzrd index.js:bundle.js | garnish
-```
-
-## wtch
-
-[wtch](https://github.com/mattdesl/wtch) is a small live-reload utility that budō builds on. It watches for JS/CSS/HTML changes and triggers a live-reload event. It can be used to augment wzrd with some watching capabilities.
-
-```sh
-#example ...
-wzrd index.js:bundle.js | wtch | garnish
-
-#with watchify ...
-watchify index.js -o bundle.js | wtch bundle.js | garnish
-```
-
-## garnish
-
-[garnish](https://github.com/mattdesl/garnish) simply prettifies bole and ndjson log output from tools that decide to use it. This includes wzrd, wtch, and budō.
\ No newline at end of file
diff --git a/docs/tests-and-examples.md b/docs/tests-and-examples.md
index 22cb209..06b36e0 100644
--- a/docs/tests-and-examples.md
+++ b/docs/tests-and-examples.md
@@ -18,7 +18,9 @@ Now you can run the following to see the unit tests:
npm test
```
-## running the example
+## running the examples
+
+See the [package.json](../package.json) `"scripts"` field for how these work.
#### basic
@@ -38,4 +40,11 @@ To run the example with live reloading:
npm run live
```
-Again, open `localhost:9966` and try making changes to `example/app.js`, `example/index.html` or `example/theme.css`. The CSS should be injected without a page refresh, and HTML/JS content will trigger a page reload.
\ No newline at end of file
+Again, open `localhost:9966` and try making changes to `example/app.js`, `example/index.html` or `example/theme.css`. The CSS should be injected without a page refresh, and HTML/JS content will trigger a page reload.
+
+## other examples
+
+#### LESS on the fly
+
+See [budo-less](https://github.com/mattdesl/budo-less) for an example of how you can integrate LESS into budo, giving you the same rapid development cycle and CSS injection without any need to write files to disk during development.
+
diff --git a/example/app.js b/example/app.js
index ee518e8..652aee7 100644
--- a/example/app.js
+++ b/example/app.js
@@ -1,30 +1,31 @@
-var dpr = window.devicePixelRatio||1
-var ctx = require('2d-context')()
-var fit = require('canvas-fit')(ctx.canvas, window, dpr)
+/*globals Image*/
+import createLoop from 'canvas-loop'
+import createContext from '2d-context'
-//setup canvas DOM state
-window.addEventListener('resize', fit, false)
-require('domready')(function() {
- fit()
- document.body.appendChild(ctx.canvas)
+const context = createContext()
+const canvas = context.canvas
+
+const app = createLoop(canvas, {
+ scale: window.devicePixelRatio
})
+document.body.appendChild(canvas)
-var img = new Image()
+const img = new Image()
+img.onload = () => app.start()
img.src = 'baboon.png'
-var time = 0
-require('raf-loop')(function(dt) {
- var width = window.innerWidth,
- height = window.innerHeight
- ctx.clearRect(0, 0, width, height)
+let time = 0
+
+app.on('tick', (dt) => {
+ const [ width, height ] = app.shape
+ context.clearRect(0, 0, width, height)
- time += dt/1000
+ time += dt / 1000
- ctx.save()
- ctx.scale(dpr, dpr)
- ctx.fillRect(Math.sin(time)*50 + 200, 35, 150, 150)
- ctx.fillText("from browserify!", 40, 40)
- if (img.width > 0 || img.height > 0)
- ctx.drawImage(img, 50, 50)
- ctx.restore()
-}).start()
\ No newline at end of file
+ context.save()
+ context.scale(app.scale, app.scale)
+ context.fillRect(Math.sin(time) * 50 + 300, 50, 20, 40)
+ context.fillText('from browserify!', 40, 40)
+ context.drawImage(img, 50, 50)
+ context.restore()
+})
diff --git a/example/demo/index.html b/example/demo/index.html
new file mode 100644
index 0000000..8daa6f6
--- /dev/null
+++ b/example/demo/index.html
@@ -0,0 +1,10 @@
+
+
+
+
+
+ budo
+
+
+
+
\ No newline at end of file
diff --git a/example/index.html b/example/index.html
index ac946c8..7136b5c 100644
--- a/example/index.html
+++ b/example/index.html
@@ -1,11 +1,12 @@
-
-
+
+
budo
+
\ No newline at end of file
diff --git a/example/main.css b/example/main.css
new file mode 100644
index 0000000..693b449
--- /dev/null
+++ b/example/main.css
@@ -0,0 +1,3 @@
+body {
+ background: #e1e1e1;
+}
\ No newline at end of file
diff --git a/example/theme.css b/example/theme.css
deleted file mode 100644
index c0f1b2d..0000000
--- a/example/theme.css
+++ /dev/null
@@ -1,3 +0,0 @@
-body {
- background: #eee;
-}
\ No newline at end of file
diff --git a/index.js b/index.js
index f845e41..5004990 100644
--- a/index.js
+++ b/index.js
@@ -1,52 +1,75 @@
-var log = require('bole')('budo')
-var minimist = require('minimist')
-var portfinder = require('portfinder')
-var xtend = require('xtend')
-var assign = require('xtend/mutable')
+var parseArgs = require('./lib/parse-args')
+var budo = require('./lib/budo')
+var color = require('term-color')
+var stdout = require('stdout-stream')
+var exec = require('child_process').exec
-var getOutput = require('./lib/get-output')
+module.exports = budo
+module.exports.cli = budoCLI
-var budo = require('./lib/budo')
-var noop = function(){}
-
-module.exports = function(args, cb) {
- cb = cb||noop
-
- var argv = minimist(args)
- if (argv._.length === 0) {
- console.error("No entry scripts specified!")
- process.exit(1)
- }
-
- argv.port = argv.port || 9966
- argv.dir = argv.dir || process.cwd()
- getOutput(argv, function(err, output) {
- if (err) {
- console.error("Error: Could not create temp bundle.js directory")
- process.exit(1)
- }
- //determine next port
- portfinder.basePort = argv.port
- portfinder.getPort(function(err, port) {
- if (err) {
- console.error("Error: Could not get available port")
- process.exit(1)
- }
-
- //run watchify server
- var emitter = budo(args, xtend(argv, {
- port: port,
- output: output
- })).on('error', function(err) {
- console.error("Error running budo on", port, err)
- process.exit(1)
- }).on('exit', function() {
- log.info('closing')
- })
-
- emitter.on('connect', function(result) {
- cb(result)
- })
- })
- })
-}
\ No newline at end of file
+function budoCLI (args, opts) {
+ var argv = parseArgs(args, opts)
+
+ // if no stream is specified, default to stdout
+ if (argv.stream !== false) {
+ argv.stream = stdout
+ }
+
+ var entries = argv._
+ delete argv._
+
+ argv.browserifyArgs = argv['--']
+ delete argv['--']
+
+ if (argv.version) {
+ console.log('budo v' + require('./package.json').version)
+ console.log('browserify v' + require('browserify/package.json').version)
+ console.log('watchify v' + require('watchify-middleware').getWatchifyVersion())
+ return null
+ }
+
+ if (argv.help) {
+ var help = require('path').join(__dirname, 'bin', 'help.txt')
+ require('fs').createReadStream(help)
+ .pipe(process.stdout)
+ return null
+ }
+
+ if (argv.outfile) {
+ console.error(color.yellow('WARNING'), '--outfile has been removed in budo@3.0')
+ }
+
+ if (typeof argv.port === 'string') {
+ argv.port = parseInt(argv.port, 10)
+ }
+ if (typeof argv.livePort === 'string') {
+ argv.livePort = parseInt(argv.livePort, 10)
+ }
+
+ // opts.live can be a glob or a boolean
+ if (typeof argv.live === 'string' && /(true|false)/.test(argv.live)) {
+ argv.live = argv.live === 'true'
+ }
+
+ // CLI only option for executing a child process
+ var instance = budo(entries, argv).on('error', exit)
+ var onUpdates = [].concat(argv.onupdate).filter(Boolean)
+ onUpdates.forEach(function (cmd) {
+ instance.on('update', execFunc(cmd))
+ })
+
+ return instance
+}
+
+function execFunc (cmd) {
+ return function run () {
+ var p = exec(cmd)
+ p.stderr.pipe(process.stderr)
+ p.stdout.pipe(process.stdout)
+ }
+}
+
+function exit (err) {
+ console.log(color.red('ERROR'), err.message)
+ process.exit(1)
+}
diff --git a/lib/budo.js b/lib/budo.js
index 1ad9f86..2db48bc 100644
--- a/lib/budo.js
+++ b/lib/budo.js
@@ -1,68 +1,306 @@
-var path = require('path')
-var Emitter = require('events/')
-var watchify = require('./watchify')
-var minimist = require('minimist')
+var bole = require('bole')
var xtend = require('xtend')
-var assign = require('xtend/mutable')
-var http = require('./server').http
-var log = require('bole')('budo')
-
-module.exports = function(watchifyArgs, opt) {
- var output = opt.output
- var port = opt.port || 9966
- var host = opt.host
-
- var emitter = new Emitter()
-
- //patch watchify args with new outfile
- setOutfile(watchifyArgs, output.from)
- //spin up watchify instance
- var watchProc = watchify(watchifyArgs)
-
- var serverOpt = xtend(opt, { output: output })
- var server = http(serverOpt)
- .on('error', function(err) {
- emitter.emit('error', err)
- })
- .listen(port, host, function(err) {
- if (err) {
- emitter.emit('error', new Error("Could not connect to server:", err))
- return
- }
- var uri = "http://"+(host||'localhost')+":"+port+"/"
- log.info("Server running at", uri)
-
- //bug with chokidar@1.0.0-rc3
- //anything in OSX tmp dirs need a wildcard
- //to work with fsevents
- var glob = output.tmp
- ? path.join(output.dir, '**.js')
- : output.from
-
- //add the uri / output to budo instance
- assign(emitter, {
- uri: uri,
- output: xtend(output, { glob: glob })
- })
- emitter.emit('connect', emitter)
+var once = require('once')
+var path = require('path')
+var EventEmitter = require('events').EventEmitter
+var isMatch = require('micromatch')
+var openUrl = require('opn')
+var internalIp = require('internal-ip')
+var garnish = require('garnish')
+
+var defaults = require('./parse-args').defaults
+var getPorts = require('./get-ports')
+var createServer = require('./server')
+var createBundler = require('./bundler')
+var createFileWatch = require('./file-watch')
+var createTinylr = require('./tinylr')
+var mapEntry = require('./map-entry')
+
+var noop = function () {}
+
+module.exports = createBudo
+function createBudo (entries, opts) {
+ var log = bole('budo')
+
+ // if no entries are specified, just options
+ if (entries && !Array.isArray(entries) && typeof entries === 'object') {
+ opts = entries
+ entries = []
+ }
+
+ // do not mutate user options
+ opts = xtend({}, defaults, { stream: false }, opts)
+ entries = entries || []
+
+ // perhaps later this will be configurable
+ opts.cwd = process.cwd()
+
+ // log to output stream
+ if (opts.stream) {
+ // by default, pretty-print to the stream with info logging
+ if (!opts.ndjson) {
+ var pretty = garnish({
+ level: opts.verbose ? 'debug' : 'info',
+ name: 'budo'
+ })
+ pretty.pipe(opts.stream)
+ opts.stream = pretty
+ }
+
+ bole.output({
+ stream: opts.stream,
+ level: 'debug'
+ })
+ }
+
+ // optionally allow as arrays
+ entries = [].concat(entries).filter(Boolean)
+
+ var entryObjects = entries.map(mapEntry)
+ var entryFiles = entryObjects.map(function (entry) {
+ return entry.from
+ })
+
+ if (opts.serve && typeof opts.serve !== 'string') {
+ throw new TypeError('opts.serve must be a string or undefined')
+ } else if (!opts.serve && entries.length > 0) {
+ opts.serve = entryObjects[0].url
+ }
+
+ // default to cwd
+ if (!opts.dir || opts.dir.length === 0) {
+ opts.dir = opts.cwd
+ }
+
+ var emitter = new EventEmitter()
+ var bundler, middleware
+
+ if (entries.length > 0) {
+ bundler = createBundler(entryFiles, opts)
+ middleware = bundler.middleware
+
+ bundler.on('log', function (ev) {
+ if (ev.type === 'bundle') {
+ var time = ev.elapsed
+ ev.elapsed = time
+ ev.name = 'browserify'
+ ev.type = undefined
+ ev.colors = {
+ elapsed: time > 1000 ? 'yellow' : 'dim',
+ message: 'dim '
+ }
+ log.info(ev)
+ }
+ })
+
+ // uncaught syntax errors should not stop the server
+ // this only happens when errorHandler: false
+ bundler.on('error', function (err) {
+ console.error('Error:', err.message ? err.message : err)
+ })
+ bundler.on('bundle-error', emitter.emit.bind(emitter, 'bundle-error'))
+ bundler.on('update', emitter.emit.bind(emitter, 'update'))
+ bundler.on('pending', emitter.emit.bind(emitter, 'pending'))
+
+ emitter.on('update', function (contents, deps) {
+ if (deps.length > 1) {
+ log.debug({
+ name: 'browserify',
+ message: deps.length + ' files changed'
})
-
- emitter.close = function() {
- watchProc.kill()
- server.close()
- emitter.emit('exit')
+ }
+ })
+ }
+
+ var defaultWatchGlob = opts.watchGlob || '**/*.{html,css}'
+ var server = createServer(middleware, opts)
+ var closed = false
+ var started = false
+ var fileWatcher = null
+ var tinylr = null
+ var deferredWatch = noop
+ var deferredLive = noop
+
+ // keep track of the original host
+ // (can be undefined)
+ var hostAddress = opts.host
+
+ // public API
+ emitter.close = once(close)
+ emitter.reload = reload
+ emitter.live = live
+ emitter.watch = watch
+
+ // setup defaults for live reload / watchify
+ if (opts.live) {
+ emitter
+ .watch()
+ .live()
+ .on('watch', function (ev, file) {
+ if (ev !== 'change' && ev !== 'add') {
+ return
+ }
+ defaultFileEvent(file)
+ })
+ .on('pending', function () {
+ defaultFileEvent(opts.serve)
+ })
+ }
+
+ // start portfinding + connect
+ getPorts(opts, handlePorts)
+ return emitter
+
+ function defaultFileEvent (file) {
+ var filename = path.basename(file)
+ if ((Array.isArray(opts.live) || typeof opts.live === 'string') &&
+ isMatch(filename, opts.live).length === 0) {
+ return
+ }
+ emitter.reload(file)
+ }
+
+ function reload (file) {
+ process.nextTick(emitter.emit.bind(emitter, 'reload', file))
+ if (tinylr) {
+ tinylr.reload(file)
+ }
+ }
+
+ // enable file watch capabilities
+ function watch (glob, watchOpt) {
+ if (!started) {
+ deferredWatch = emitter.watch.bind(null, glob, watchOpt)
+ } else {
+ // destroy previous
+ if (fileWatcher) fileWatcher.close()
+ glob = glob && glob.length > 0 ? glob : defaultWatchGlob
+ glob = Array.isArray(glob) ? glob : [ glob ]
+ watchOpt = xtend({ poll: opts.poll }, watchOpt)
+
+ fileWatcher = createFileWatch(glob, watchOpt)
+ fileWatcher.on('watch', emitter.emit.bind(emitter, 'watch'))
+ }
+ return emitter
+ }
+
+ // enables LiveReload capabilities
+ function live (liveOpts) {
+ if (!started) {
+ deferredLive = emitter.live.bind(null, liveOpts)
+ } else {
+ // destroy previous
+ if (tinylr) tinylr.close()
+
+ // default port
+ liveOpts = xtend({ port: opts.livePort }, liveOpts)
+
+ // default to budo host
+ var hostName = liveOpts.host ? getHostAddress(liveOpts.host) : opts.host
+
+ // the LiveReload ',
- '',
- '