1 | 'use strict';
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | var 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 |
|
17 | var info = chalk.gray,
|
18 | error = chalk.bold.red;
|
19 |
|
20 | var glsInstanceCounter = 0;
|
21 |
|
22 | var callback = {
|
23 | processExit: function (code, sig, server) {
|
24 | glsInstanceCounter--;
|
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 |
|
33 | process.exit(0);
|
34 | }
|
35 | },
|
36 |
|
37 | lrServerReady: function () {
|
38 | console.log(info('livereload[tiny-lr] listening on %s ...'), this.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 |
|
52 |
|
53 |
|
54 | module.exports = exports = (function() {
|
55 | var defaults = {
|
56 | options: {
|
57 | cwd: undefined
|
58 | },
|
59 | livereload: {
|
60 | port: 35729
|
61 | }
|
62 | };
|
63 | defaults.options.env = JSON.parse(JSON.stringify(process.env));
|
64 | defaults.options.env.NODE_ENV = 'development';
|
65 |
|
66 | return function(args, options, livereload){
|
67 | var config = {}
|
68 | config.args = util.isArray(args) ? args : [args];
|
69 |
|
70 | config.options = merge(defaults.options, options || {});
|
71 |
|
72 | if (livereload) {
|
73 | config.livereload = (typeof livereload === 'object' ? livereload : {port: livereload});
|
74 | }else{
|
75 | config.livereload = (livereload === false ? false : defaults.livereload);
|
76 | }
|
77 |
|
78 |
|
79 | return merge({
|
80 | config: config,
|
81 | server: undefined,
|
82 | lr: undefined
|
83 | }, exports);
|
84 | };
|
85 | })();
|
86 |
|
87 |
|
88 |
|
89 |
|
90 | exports.script = path.join(__dirname, 'scripts/static.js');
|
91 |
|
92 |
|
93 |
|
94 |
|
95 | exports.new = function (script) {
|
96 | if(!script){
|
97 | return console.log(error('script file not specified.'));
|
98 | }
|
99 | var args = util.isArray(script) ? script : [script];
|
100 | return this(args);
|
101 | };
|
102 |
|
103 |
|
104 |
|
105 |
|
106 | exports.static = function (folder, port) {
|
107 | var script = this.script;
|
108 | folder = folder || process.cwd();
|
109 | util.isArray(folder) && (folder = folder.join(','));
|
110 | port = port || 3000;
|
111 | return this([script, folder, port]);
|
112 | };
|
113 |
|
114 |
|
115 |
|
116 |
|
117 | exports.start = function (execPath) {
|
118 | if (this.server) {
|
119 | debug(info('kill server'));
|
120 | this.server.kill('SIGKILL');
|
121 |
|
122 | this.server = undefined;
|
123 | } else {
|
124 | if(this.config.livereload){
|
125 | this.lr = tinylr(this.config.livereload);
|
126 | this.lr.listen(this.config.livereload.port, callback.lrServerReady.bind(this));
|
127 | }
|
128 | }
|
129 |
|
130 |
|
131 |
|
132 | this.config.execPath = execPath || this.config.execPath || process.execPath;
|
133 | var deferred = Q.defer();
|
134 | this.server = spawn(this.config.execPath, this.config.args, this.config.options);
|
135 | this.server.stdout.setEncoding('utf8');
|
136 | this.server.stderr.setEncoding('utf8');
|
137 |
|
138 | this.server.stdout.on('data', function (data) {
|
139 | deferred.notify(data);
|
140 | callback.serverLog(data);
|
141 | });
|
142 | this.server.stderr.on('data', function (data) {
|
143 | deferred.notify(data);
|
144 | callback.serverError(data);
|
145 | });
|
146 | this.server.once('exit', function (code, sig) {
|
147 | setTimeout(function() {
|
148 | deferred.resolve({
|
149 | code: code,
|
150 | signal: sig
|
151 | });
|
152 | if (glsInstanceCounter == 0)
|
153 | callback.serverExit(code, sig);
|
154 | }, 0)
|
155 | });
|
156 |
|
157 | var exit = function(code, sig) {
|
158 | callback.processExit(code,sig,server);
|
159 | }
|
160 | process.listeners('exit') || process.once('exit', exit);
|
161 |
|
162 | glsInstanceCounter++;
|
163 | return deferred.promise;
|
164 | };
|
165 |
|
166 |
|
167 |
|
168 |
|
169 | exports.stop = function () {
|
170 | var deferred = Q.defer();
|
171 | if (this.server) {
|
172 | this.server.once('exit', function (code) {
|
173 | deferred.resolve(code);
|
174 | });
|
175 |
|
176 | debug(info('kill server'));
|
177 |
|
178 | this.server.kill('SIGKILL');
|
179 |
|
180 | this.server = undefined;
|
181 | }else{
|
182 | deferred.resolve(0);
|
183 | }
|
184 | if(this.lr){
|
185 | debug(info('close livereload server'));
|
186 | this.lr.close();
|
187 |
|
188 | this.lr = undefined;
|
189 | }
|
190 |
|
191 | return deferred.promise;
|
192 | };
|
193 |
|
194 |
|
195 |
|
196 |
|
197 | exports.notify = function (event) {
|
198 | if(event && event.path){
|
199 | var filepath = path.relative(__dirname, event.path);
|
200 | debug(info('file(s) changed: %s'), event.path);
|
201 | this.lr.changed({body: {files: [filepath]}});
|
202 | }
|
203 |
|
204 | return es.map(function(file, done) {
|
205 | var filepath = path.relative(__dirname, file.path);
|
206 | debug(info('file(s) changed: %s'), filepath);
|
207 | this.lr.changed({body: {files: [filepath]}});
|
208 | done(null, file);
|
209 | }.bind(this));
|
210 | };
|
211 |
|