UNPKG

5.36 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 var args = util.isArray(script) ? script : [script];
93 return this(args);
94};
95
96/**
97* create a server child process with the static server script
98*/
99exports.static = function (folder, port) {
100 var script = this.script;
101 folder = folder || process.cwd();
102 util.isArray(folder) && (folder = folder.join(','));
103 port = port || 3000;
104 return this([script, folder, port]);
105};
106
107/**
108* start/restart the server
109*/
110exports.start = function () {
111 if (server) { // server already running
112 debug(info('kill server'));
113 server.kill('SIGKILL');
114 //server.removeListener('exit', callback.serverExit);
115 server = undefined;
116 } else {
117 if(config.livereload){
118 lr = tinylr(config.livereload);
119 lr.listen(config.livereload.port, callback.lrServerReady);
120 }
121 }
122
123 var deferred = Q.defer();
124 server = spawn('node', config.args, config.options);
125 server.stdout.setEncoding('utf8');
126 server.stderr.setEncoding('utf8');
127
128 server.stdout.on('data', function (data) {
129 deferred.notify(data);
130 callback.serverLog(data);
131 });
132 server.stderr.on('data', function (data) {
133 deferred.notify(data);
134 callback.serverError(data);
135 });
136 server.once('exit', function (code, sig) {
137 deferred.resolve({
138 code: code,
139 signal: sig
140 });
141 callback.serverExit(code, sig);
142 });
143
144 process.listeners('exit') || process.once('exit', callback.processExit);
145
146 return deferred.promise;
147};
148
149/**
150* stop the server
151*/
152exports.stop = function () {
153 var deferred = Q.defer();
154 if (server) {
155 server.once('exit', function (code) {
156 deferred.resolve(code);
157 });
158
159 debug(info('kill server'));
160 //use SIGHUP instead of SIGKILL, see issue #34
161 server.kill('SIGKILL');
162 //server.removeListener('exit', callback.serverExit);
163 server = undefined;
164 }else{
165 deferred.resolve(0);
166 }
167 if(lr){
168 debug(info('close livereload server'));
169 lr.close();
170 //TODO how to stop tiny-lr from hanging the terminal
171 lr = undefined;
172 }
173
174 return deferred.promise;
175};
176
177/**
178* tell livereload.js to reload the changed resource(s)
179*/
180exports.notify = function (event) {
181 if(event && event.path){
182 var filepath = path.relative(__dirname, event.path);
183 debug(info('file(s) changed: %s'), event.path);
184 lr.changed({body: {files: [filepath]}});
185 }
186
187 return es.map(function(file, done) {
188 var filepath = path.relative(__dirname, file.path);
189 debug(info('file(s) changed: %s'), filepath);
190 lr.changed({body: {files: [filepath]}});
191 done(null, file);
192 });
193};