UNPKG

5.31 kBJavaScriptView Raw
1'use strict';
2/**
3 * Created by gimm on 3/13/2015.
4 */
5
6var util = require('util'),
7 path = require('path'),
8 assert = require('assert'),
9 spawn = require('child_process').spawn,
10 merge = require('deepmerge'),
11 tinylr = require('tiny-lr'),
12 es = require('event-stream'),
13 Q = require('q'),
14 chalk = require('chalk'),
15 debug = require('debug')('gulp-live-server');
16
17var config = {},
18 server = undefined, // the server child process
19 lr = undefined, // tiny-lr server
20 info = chalk.gray,
21 error = chalk.bold.red;
22
23var callback = {
24 processExit: function (code, sig) {
25 debug(info('Main process exited with [code => %s | sig => %s]'), code, sig);
26 server && server.kill();
27 },
28
29 serverExit: function (code, sig) {
30 debug(info('server process exited with [code => %s | sig => %s]'), code, sig);
31 if(sig !== 'SIGKILL'){
32 //server stopped unexpectedly
33 process.exit(0);
34 }
35 },
36
37 lrServerReady: function () {
38 console.log(info('livereload[tiny-lr] listening on %s ...'), config.livereload.port);
39 },
40
41 serverLog: function (data) {
42 console.log(info(data.trim()));
43 },
44
45 serverError: function (data) {
46 console.log(error(data.trim()));
47 }
48};
49
50/**
51 * set config data for the new server child process
52 * @type {Function}
53 */
54module.exports = exports = (function() {
55 var defaults = {
56 options: {
57 cwd: undefined
58 },
59 livereload: {
60 port: 35729
61 }
62 };
63 defaults.options.env = process.env;
64 defaults.options.env.NODE_ENV = 'development';
65
66 return function(args, options, livereload){
67 config.args = util.isArray(args) ? args : [args];
68 //deal with options
69 config.options = merge(defaults.options, options || {});
70 //deal with livereload
71 if (livereload) {
72 config.livereload = (typeof livereload === 'object' ? livereload : {port: livereload});
73 }else{
74 config.livereload = (livereload === false ? false : defaults.livereload);
75 }
76 return exports;
77 };
78})();
79
80/**
81* default server script, the static server
82*/
83exports.script = path.join(__dirname, 'scripts/static.js');
84
85/**
86* create a server child process with the script file
87*/
88exports.new = function (script) {
89 if(!script){
90 return console.log(error('script file not specified.'));
91 }
92 return this([script]);
93};
94
95/**
96* create a server child process with the static server script
97*/
98exports.static = function (folder, port) {
99 var script = this.script;
100 folder = folder || process.cwd();
101 util.isArray(folder) && (folder = folder.join(','));
102 port = port || 3000;
103 return this([script, folder, port]);
104};
105
106/**
107* start/restart the server
108*/
109exports.start = function () {
110 if (server) { // server already running
111 debug(info('kill server'));
112 server.kill('SIGKILL');
113 //server.removeListener('exit', callback.serverExit);
114 server = undefined;
115 } else {
116 if(config.livereload){
117 lr = tinylr(config.livereload);
118 lr.listen(config.livereload.port, callback.lrServerReady);
119 }
120 }
121
122 var deferred = Q.defer();
123 server = spawn('node', config.args, config.options);
124 server.stdout.setEncoding('utf8');
125 server.stderr.setEncoding('utf8');
126
127 server.stdout.on('data', function (data) {
128 deferred.notify(data);
129 callback.serverLog(data);
130 });
131 server.stderr.on('data', function (data) {
132 deferred.notify(data);
133 callback.serverError(data);
134 });
135 server.once('exit', function (code, sig) {
136 deferred.resolve({
137 code: code,
138 signal: sig
139 });
140 callback.serverExit(code, sig);
141 });
142
143 process.listeners('exit') || process.once('exit', callback.processExit);
144
145 return deferred.promise;
146};
147
148/**
149* stop the server
150*/
151exports.stop = function () {
152 var deferred = Q.defer();
153 if (server) {
154 server.once('exit', function (code) {
155 deferred.resolve(code);
156 });
157
158 debug(info('kill server'));
159 //use SIGHUP instead of SIGKILL, see issue #34
160 server.kill('SIGKILL');
161 //server.removeListener('exit', callback.serverExit);
162 server = undefined;
163 }else{
164 deferred.resolve(0);
165 }
166 if(lr){
167 debug(info('close livereload server'));
168 lr.close();
169 //TODO how to stop tiny-lr from hanging the terminal
170 lr = undefined;
171 }
172
173 return deferred.promise;
174};
175
176/**
177* tell livereload.js to reload the changed resource(s)
178*/
179exports.notify = function (event) {
180 if(event && event.path){
181 var filepath = path.relative(__dirname, event.path);
182 debug(info('file(s) changed: %s'), event.path);
183 lr.changed({body: {files: [filepath]}});
184 }
185
186 return es.map(function(file, done) {
187 var filepath = path.relative(__dirname, file.path);
188 debug(info('file(s) changed: %s'), filepath);
189 lr.changed({body: {files: [filepath]}});
190 done(null, file);
191 });
192};