├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── index.js ├── lib └── wiper.js ├── package.json └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | 30 | # OS files 31 | .DS_Store 32 | 33 | # Coveralls token files 34 | .coveralls.yml 35 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.8" 4 | - "0.10" 5 | - "0.12" 6 | - "iojs" 7 | before_install: npm install -g npm 8 | script: npm test -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | Changelog 3 | ========= 4 | 5 | # 1.x release 6 | 7 | ## v1.3.0 (master) 8 | 9 | - Feature: change from throttle to debounce to prevent duplicate event 10 | - Feature: add timeout parameter for debounce 11 | - Remove: un-used quiet parameter, we are quiet by default 12 | 13 | ## v1.2.0 14 | 15 | - Workaround: throttle livereload (wait 5 seconds) 16 | 17 | ## v1.1.1 18 | 19 | - Fix: wiper error should exit with code 1 20 | 21 | ## v1.1.0 22 | 23 | - Feature: use chokidar instead of gaze 24 | - Feature: added https support 25 | 26 | ## v1.0.3 27 | 28 | - Enhance: output message now use `debug` module 29 | - Enhance: io.js test 30 | 31 | ## v1.0.2 32 | 33 | - Fix: error handling 34 | - Fix: page refresh 35 | 36 | ## v1.0.1 37 | 38 | - Fix: documents and tests 39 | 40 | ## v1.0.0 41 | 42 | - Major: public release 43 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 David Frank 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | wiper 3 | ===== 4 | 5 | [![npm version][npm-image]][npm-url] 6 | [![build status][travis-image]][travis-url] 7 | 8 | A command line tool that [watch](https://github.com/paulmillr/chokidar) file changes and do a [livereload](https://github.com/mklabs/tiny-lr) when needed (compatible with both node.js and io.js), and works over https. 9 | 10 | 11 | # Motivation 12 | 13 | This allows us to use `npm` as our build tool instead of `grunt` or `gulp`. 14 | 15 | 16 | # Install 17 | 18 | `npm install wiper --save-dev` or `npm install -g wiper` 19 | 20 | 21 | # Usage 22 | 23 | In your `package.json`, add these lines. 24 | 25 | ```json 26 | { 27 | "scripts": { 28 | "watch": "DEBUG=wiper wiper -p 1234 -t 2000 -w \\*\\*/\\*.js,\\*\\*/\\*.css" 29 | } 30 | } 31 | ``` 32 | 33 | Now try `npm run watch`, a livereload server will be running at `localhost:1234` and watching updates to javascript/css files. 34 | 35 | 36 | ## Options 37 | 38 | - `-p` port to listen on, default to 35729. 39 | - `-t` debounce timeout, default to 5000ms. 40 | - `-w` files to watch; note that you should use `\*` to prevent bash from expanding globs, as we want wiper to expand it instead, also see that we double escape `\\*` in package.json due to additional string escapes. 41 | - `--cert=ssl.crt` and `--key=ssl.key` to start livereload server on https, generate your self-signed certificate and import them into your CA trust store for this to work. 42 | 43 | 44 | ## Integration 45 | 46 | To integrate with your koa/express server, use modules like [koa-livereload](https://github.com/yosuke-furukawa/koa-livereload) or [connect-livereload](https://github.com/intesso/connect-livereload). 47 | 48 | ```javascript 49 | // for http 50 | app.use(livereload({ 51 | port: 1234 52 | })); 53 | 54 | // for https 55 | app.use(livereload({ 56 | src: 'https://example.com:1234/livereload.js?snipver=1' 57 | })); 58 | ``` 59 | 60 | Or manually insert this line onto your template. 61 | 62 | ```html 63 | 64 | ``` 65 | 66 | Now your browsers will be refreshed automatically when file change occurs. And see, no `grunt` or `gulp` needed, just good-old `npm`. 67 | 68 | 69 | # License 70 | 71 | MIT 72 | 73 | [npm-image]: https://img.shields.io/npm/v/wiper.svg?style=flat-square 74 | [npm-url]: https://www.npmjs.com/package/wiper 75 | [travis-image]: https://img.shields.io/travis/bitinn/wiper.svg?style=flat-square 76 | [travis-url]: https://travis-ci.org/bitinn/wiper 77 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * index.js 5 | * 6 | * A command line tool that gaze at your file changes and do a tiny-lr when needed 7 | */ 8 | 9 | var opts = require('minimist')(process.argv.slice(2)); 10 | var Wiper = require('./lib/wiper'); 11 | 12 | // command line mode 13 | if (!module.parent) { 14 | factory(opts); 15 | } 16 | 17 | function factory(opts) { 18 | var w = new Wiper(opts); 19 | w.run(); 20 | }; 21 | -------------------------------------------------------------------------------- /lib/wiper.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * wiper.js 4 | */ 5 | 6 | var chokidar = require('chokidar'); 7 | var livereload = require('tiny-lr'); 8 | var fs = require('fs'); 9 | var log = require('debug')('wiper'); 10 | 11 | module.exports = Wiper; 12 | 13 | /** 14 | * Watch for file changes and refresh your browser tabs 15 | * 16 | * @param Object opts Options 17 | * @return Void 18 | */ 19 | function Wiper(opts) { 20 | 21 | opts = opts || {}; 22 | 23 | if (opts.w) { 24 | opts.w = opts.w.split(','); 25 | } else { 26 | opts.w = ['**/*.js', '**/*.css']; 27 | } 28 | 29 | if (!opts.p) { 30 | opts.p = 35729; 31 | } 32 | 33 | if (!opts.t) { 34 | opts.t = 5000; 35 | } 36 | 37 | this.opts = opts; 38 | 39 | }; 40 | 41 | /** 42 | * Start the livereload server and watch files 43 | * 44 | * @param Function cb Callback 45 | * @return Void 46 | */ 47 | Wiper.prototype.run = function(cb) { 48 | var self = this; 49 | var opts = this.opts; 50 | 51 | if (opts.cert && opts.key) { 52 | this.server = livereload({ 53 | key: fs.readFileSync(opts.key) 54 | , cert: fs.readFileSync(opts.cert) 55 | }); 56 | log('livereload on https'); 57 | } else { 58 | this.server = livereload(); 59 | log('livereload on http'); 60 | } 61 | 62 | this.server.listen(opts.p, function() { 63 | log('livereload server started on port: ' + opts.p); 64 | 65 | var list = opts.w; 66 | list.push('!node_modules/**'); 67 | 68 | self.watcher = chokidar.watch(list); 69 | log('started watching files: ' + opts.w.join(', ')); 70 | 71 | var timeout; 72 | self.watcher.on('all', function(event, file) { 73 | if (timeout) { 74 | clearTimeout(timeout); 75 | } 76 | 77 | timeout = setTimeout(function() { 78 | log(file + ' has ' + event); 79 | 80 | self.server.changed({ 81 | body: { 82 | files: file 83 | } 84 | }); 85 | }, opts.t); 86 | }); 87 | 88 | if (cb) { 89 | cb(); 90 | } 91 | }); 92 | 93 | this.server.server.removeAllListeners('error'); 94 | this.server.server.on('error', function(err) { 95 | if (err.code === 'EADDRINUSE') { 96 | console.error('port: ' + opts.p + ' is not available'); 97 | self.server.close(); 98 | 99 | if (self.watcher) { 100 | self.watcher.close(); 101 | } 102 | process.exit(1); 103 | } else { 104 | console.error(err); 105 | } 106 | }); 107 | }; 108 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wiper", 3 | "version": "1.3.0", 4 | "description": "A command line tool that gaze at your file changes and do a tiny-lr when needed", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha test.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/bitinn/wiper.git" 12 | }, 13 | "keywords": [ 14 | "watch", 15 | "livereload" 16 | ], 17 | "author": "David Frank", 18 | "license": "MIT", 19 | "bugs": { 20 | "url": "https://github.com/bitinn/wiper/issues" 21 | }, 22 | "homepage": "https://github.com/bitinn/wiper", 23 | "devDependencies": { 24 | "chai": "^2.2.0", 25 | "mocha": "^2.2.4" 26 | }, 27 | "bin": "index.js", 28 | "dependencies": { 29 | "chokidar": "^1.0.1", 30 | "debug": "^2.1.3", 31 | "minimist": "^1.1.1", 32 | "tiny-lr": "^0.1.5" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | 2 | // test tools 3 | var chai = require('chai'); 4 | var expect = chai.expect; 5 | 6 | var Chokidar = require('chokidar').FSWatcher; 7 | var TinyLR = require('tiny-lr').Server; 8 | 9 | // test subject 10 | var Wiper = require('./lib/wiper'); 11 | 12 | describe('wiper', function() { 13 | 14 | it('should setup default options', function() { 15 | var w = new Wiper(); 16 | expect(w.opts.w).to.deep.equal(['**/*.js', '**/*.css']); 17 | expect(w.opts.p).to.equal(35729); 18 | expect(w.opts.t).to.equal(5000); 19 | }); 20 | 21 | it('should setup custom options', function() { 22 | var w = new Wiper({ w: 'a,b', p: 1234, t: 2000, cert: 'ssl.crt', key: 'ssl.key' }); 23 | expect(w.opts.w).to.deep.equal(['a', 'b']); 24 | expect(w.opts.p).to.equal(1234); 25 | expect(w.opts.t).to.equal(2000); 26 | expect(w.opts.cert).to.equal('ssl.crt'); 27 | expect(w.opts.key).to.equal('ssl.key'); 28 | }); 29 | 30 | it('should setup livereload server and watch files', function(done) { 31 | var w = new Wiper({ p: 1234, w: 'a' }); 32 | w.run(function() { 33 | expect(w.server.port).to.equal(1234); 34 | expect(w.server).to.be.instanceof(TinyLR); 35 | expect(w.watcher).to.be.instanceof(Chokidar); 36 | done(); 37 | }); 38 | }); 39 | 40 | }); 41 | --------------------------------------------------------------------------------