1 # tiny-lr [![Build Status](https://travis-ci.org/mklabs/tiny-lr.svg?branch=master)](https://travis-ci.org/mklabs/tiny-lr)
3 This script manages a tiny [LiveReload](http://livereload.com/) server
6 [![NPM](https://nodei.co/npm/tiny-lr.png?downloads=true&stars=true)](https://nodei.co/npm/tiny-lr/)
8 It exposes an HTTP server and express middleware, with a very basic REST
9 Api to notify the server of a particular change.
11 It doesn't have any watch ability, it must be done at the build process or
14 Instead, it exposes a very simple API to notify the server that some
15 changes have been made, then broadcasted to every livereload client
18 # notify a single change
19 curl http://localhost:35729/changed?files=style.css
21 # notify using a longer path
22 curl http://localhost:35729/changed?files=js/app.js
24 # notify multiple changes, comma or space delimited
25 curl http://localhost:35729/changed?files=index.html,style.css,docs/docco.css
27 Or you can bulk the information into a POST request, with body as a JSON array of files.
29 curl -X POST http://localhost:35729/changed -d '{ "files": ["style.css", "app.js"] }'
32 node -pe 'JSON.stringify({ files: ["some.css", "files.css"] })' > files.json
33 curl -X POST -d @files.json http://localhost:35729
35 As for the livereload client, you need to install the browser extension:
36 http://feedback.livereload.com/knowledgebase/articles/86242-how-do-i-install-and-use-the-browser-extensions-
37 (**note**: you need to listen on port 35729 to be able to use with your
40 or add the livereload script tag manually:
41 http://feedback.livereload.com/knowledgebase/articles/86180-how-do-i-add-the-script-tag-manually-
42 (and here you can choose whatever port you want)
46 The best way to integrate the runner in your workflow is to add it as a `reload`
47 step within your build tool.
50 var tinylr = require('tiny-lr');
52 // standard LiveReload port
55 // tinylr(opts) => new tinylr.Server(opts);
56 tinylr().listen(port, function() {
57 console.log('... Listening on %s ...', port);
61 You can define your own route and listen for specific request:
64 var server = tinylr();
66 server.on('GET /myplace', function(req, res) {
72 And stop the server manually:
78 This will close any websocket connection established and emit a close event.
82 To use as a connect / express middleware, tiny-lr needs query /
83 bodyParser middlewares prior in the stack (to handle POST requests)
85 Any handled requests ends at the tinylr level, not found and errors are
86 nexted to the rest of the stack.
89 var port = process.env.LR_PORT || process.env.PORT || 35729;
91 var path = require('path');
92 var express = require('express');
93 var tinylr = require('tiny-lr');
94 var body = require('body-parser');
98 // This binds both express app and tinylr on the same port
103 .use(tinylr.middleware({ app: app }))
104 .use(express.static(path.resolve('./')))
105 .listen(port, function() {
106 console.log('listening on %d', port);
110 The port you listen on is important, and tinylr should **always** listen on
111 the LiveReload standard one: `35729`. Otherwise, you won't be able to rely
112 on the browser extensions, though you can still use the manual snippet
115 You can also start two different servers, one on your app port, the
116 other listening on the LiveReload port.
120 Head over to [https://github.com/gruntjs/grunt-contrib-watch](https://github.com/gruntjs/grunt-contrib-watch#live-reloading)
124 See [make-livereload](https://github.com/mklabs/make-livereload) repo.
125 This repository defines a bin wrapper you can use and install with:
127 npm install make-livereload -g
129 It bundles the same bin wrapper previously used in tiny-lr repo.
131 Usage: tiny-lr [options]
135 -h, --help output usage information
136 -V, --version output the version number
138 pid Path to the generated PID file (default: ./tiny-lr.pid)
142 See [gulp-livereload](https://github.com/vohof/gulp-livereload) repo.
146 - `livereload` - Path to the client side lib (defaults to `path.join(__dirname, '../node_modules/livereload-js/dist/livereload.js')`)
147 - `port` - Livereload port (defaults to `35729`)
148 - `errorListener` - A callback to invoke when an error occurs (otherwise, fallbacks to standard error output)
149 - `app` - An express or other middleware based HTTP server
150 - `key` - Option to pass in to create an https server
151 - `cert` - Option to pass in to create an https server
152 - `pfx` - Can also be used to create an https server instead of `key` & `cert`
153 - `liveCSS` - LiveReload option to enable live CSS reloading (defaults to true)
154 - `liveJs` - LiveReload option to enable live JS reloading (defaults to true)
155 - `liveImg` - LiveReload option to enable live images reloading (defaults to true)
165 - [tiny-lr](#tiny-lr)
166 - [GET /](#tiny-lr-get-)
167 - [GET /changed](#tiny-lr-get-changed)
168 - [POST /changed](#tiny-lr-post-changed)
169 - [GET /livereload.js](#tiny-lr-get-livereloadjs)
170 - [GET /kill](#tiny-lr-get-kill)
178 var url = parse(this.request.url);
179 var server = this.app;
181 var ws = this.ws = new WebSocket('ws://' + url.host + '/livereload');
183 ws.onopen = function(event) {
186 protocols: ['http://livereload.com/protocols/official-7']
189 ws.send(JSON.stringify(hello));
192 ws.onmessage = function(event) {
193 assert.deepEqual(event.data, JSON.stringify({
195 protocols: ['http://livereload.com/protocols/official-7'],
196 serverName: 'tiny-lr'
199 assert.ok(Object.keys(server.clients).length);
204 properly cleans up established connection on exit.
209 ws.onclose = done.bind(null, null);
213 .expect(200, function() {
214 console.log('server shutdown');
220 <a name="tiny-lr-get-" />
222 respond with nothing, but respond.
227 .expect('Content-Type', /json/)
228 .expect('{"tinylr":"Welcome","version":"0.0.1"}')
232 unknown route respond with proper 404 and error message.
237 .expect('Content-Type', /json/)
238 .expect('{"error":"not_found","reason":"no such route"}')
242 <a name="tiny-lr-get-changed" />
244 with no clients, no files.
249 .expect('Content-Type', /json/)
250 .expect(/"clients":\[\]/)
251 .expect(/"files":\[\]/)
255 with no clients, some files.
259 .get('/changed?files=gonna.css,test.css,it.css')
260 .expect('Content-Type', /json/)
261 .expect('{"clients":[],"files":["gonna.css","test.css","it.css"]}')
265 <a name="tiny-lr-post-changed" />
267 with no clients, no files.
272 .expect('Content-Type', /json/)
273 .expect(/"clients":\[\]/)
274 .expect(/"files":\[\]/)
278 with no clients, some files.
281 var data = { clients: [], files: ['cat.css', 'sed.css', 'ack.js'] };
285 .send({ files: data.files })
286 .expect('Content-Type', /json/)
287 .expect(JSON.stringify(data))
291 <a name="tiny-lr-get-livereloadjs" />
292 ## GET /livereload.js
293 respond with livereload script.
297 .get('/livereload.js')
298 .expect(/LiveReload/)
302 <a name="tiny-lr-get-kill" />
307 var server = this.server;
310 .expect(200, function(err) {
311 if(err) return done(err);
312 assert.ok(!server._handle);
319 - Tiny-lr is a [LiveReload](http://livereload.com/) implementation. They
320 really made frontend editing better for a lot of us. They have a
321 [LiveReload App on the Mac App Store](https://itunes.apple.com/us/app/livereload/id482898991)
322 you might want to check out.
324 - To all [contributors](https://github.com/mklabs/tiny-lr/graphs/contributors)
326 - [@FGRibreau](https://github.com/FGRibreau) / [pid.js
327 gist](https://gist.github.com/1846952)) for the background friendly
328 bin wrapper, used in [make-livereload](https://github.com/mklabs/make-livereload)