UNPKG

7.17 kBJavaScriptView Raw
1"use strict";
2
3var through = require('through2'),
4 gutil = require('gulp-util'),
5 http = require('http'),
6 https = require('https'),
7 inject = require('connect-inject'),
8 connect = require('connect'),
9 proxy = require('proxy-middleware'),
10 watch = require('node-watch'),
11 fs = require('fs'),
12 serveIndex = require('serve-index'),
13 serveStatic = require('serve-static'),
14 path = require('path'),
15 open = require('open'),
16 enableMiddlewareShorthand = require('./enableMiddlewareShorthand'),
17 socket = require('socket.io'),
18 url = require('url'),
19 extend = require('node.extend');
20
21
22var BROWSER_SCIPTS_DIR = path.join(__dirname, 'browser-scripts');
23
24
25
26
27module.exports = function(options) {
28 var defaults = {
29 /**
30 *
31 * BASIC DEFAULTS
32 *
33 **/
34 host: 'localhost',
35 port: 8000,
36 defaultFile: 'index.html',
37 fallback: null,
38 https: false,
39 open: false,
40 log: 'info',
41
42 /**
43 *
44 * MIDDLEWARE DEFAULTS
45 *
46 * NOTE:
47 * All middleware should defaults should have the 'enable'
48 * property if you want to support shorthand syntax like:
49 *
50 * webserver({
51 * livereload: true
52 * });
53 *
54 */
55
56 // Middleware: Livereload
57 livereload: {
58 enable: false,
59 port: 35729,
60 filter: function(filename, cb) {
61 cb( !(/node_modules/.test(filename)) );
62 },
63 clientConsole: false,
64 },
65
66 // Middleware: Directory listing
67 // For possible options, see:
68 // https://github.com/expressjs/serve-index
69 directoryListing: {
70 enable: false,
71 path: './',
72 options: undefined
73 },
74
75 // Middleware: Proxy
76 // For possible options, see:
77 // https://github.com/andrewrk/connect-proxy
78 proxies: []
79
80 };
81
82 // Deep extend user provided options over the all of the defaults
83 // Allow shorthand syntax, using the enable property as a flag
84 var config = enableMiddlewareShorthand(defaults, options, ['directoryListing', 'livereload']);
85
86 var openInBrowser = function () {
87 if (config.open === false) return;
88 open('http' + (config.https ? 's' : '') + '://' + config.host + ':' + config.port);
89 openInBrowser = undefined;
90 };
91
92 // connect app
93 var app = connect();
94 // Proxy requests
95 for (var i = 0, len = config.proxies.length; i < len; i++) {
96 var proxyoptions = url.parse(config.proxies[i].target);
97 if (config.proxies[i].hasOwnProperty('options')) {
98 extend(proxyoptions, config.proxies[i].options);
99 }
100
101 proxyoptions.route = config.proxies[i].source;
102 app.use(proxy(proxyoptions));
103
104 gutil.log(config.proxies[i].source + ' is proxied.');
105 }
106 // directory listing
107 if (config.directoryListing.enable) {
108 app.use(serveIndex(path.resolve(config.directoryListing.path), config.directoryListing.options));
109 }
110
111 // socket.io
112 if (config.livereload.enable) {
113 var ioServerOrigin = 'http://' + config.host + ':' + config.livereload.port;
114
115 var snippetParams = [];
116
117 if (config.livereload.clientConsole) {
118 snippetParams.push("extra=capture-console");
119 }
120
121 var snippet =
122 "<script type='text/javascript' async defer src='"
123 + ioServerOrigin
124 + "/livereload.js?"
125 + snippetParams.join('&')
126 + "'></script>";
127
128 app.use(inject({
129 snippet: snippet,
130 rules: [{
131 match: /<\/body>/,
132 fn: function(w, s) {
133 return s + w;
134 }
135 }]
136 }));
137
138 var io = config.livereload.io = socket();
139 io.serveClient(true);
140 io.path("");
141 io.on('connection', function(socket){
142 gutil.log('Livereload client connected');
143
144 socket.on('console_log', function(data){
145 var args = [
146 gutil.colors.green('log')
147 ];
148 for (var i in data) {
149 args.push(data[i]);
150 }
151 gutil.log.apply(null, args);
152 });
153 socket.on('console_warn', function(data){
154 var args = [
155 gutil.colors.yellow('warn')
156 ];
157 for (var i in data) {
158 args.push(data[i]);
159 }
160 gutil.log.apply(null, args);
161 });
162 socket.on('console_info', function(data){
163 var args = [
164 gutil.colors.cyan('info')
165 ];
166 for (var i in data) {
167 args.push(data[i]);
168 }
169 gutil.log.apply(null, args);
170 });
171 socket.on('console_error', function(data){
172 var args = [
173 gutil.colors.red('err')
174 ];
175 for (var i in data) {
176 args.push(data[i]);
177 }
178 gutil.log.apply(null, args);
179 });
180 });
181
182 var ioApp = connect();
183
184 ioApp.use(serveStatic(BROWSER_SCIPTS_DIR, { index: false }));
185
186 var ioServer = config.livereload.ioServer =
187 http.createServer(ioApp).listen(config.livereload.port, config.host);
188
189 io.attach(ioServer, {
190 path: '/socket.io'
191 });
192 }
193
194 // http server
195 var webserver = null;
196 if (config.https) {
197 var options = {
198 key: fs.readFileSync(config.https.key || __dirname + '/../ssl/dev-key.pem'),
199 cert: fs.readFileSync(config.https.cert || __dirname + '/../ssl/dev-cert.pem')
200 };
201
202 webserver = https.createServer(options, app);
203 }
204 else {
205 webserver = http.createServer(app);
206 }
207
208 var files = [];
209
210 // Create server
211 var stream = through.obj(function(file, enc, callback) {
212 if ('debug' === config.log) {
213 app.use(function(req, res, next) {
214 gutil.log(req.method + ' ' + req.url);
215
216 next();
217 });
218 }
219
220
221 app.use(serveStatic(file.path, {
222 index: (config.directoryListing.enable ? false : config.defaultFile)
223 }));
224
225 if (config.livereload.enable) {
226 watch(file.path, function(filename) {
227 config.livereload.filter(filename, function(shouldReload) {
228 if (shouldReload) {
229 gutil.log('Livereload: file changed: ' + filename);
230
231 config.livereload.io.sockets.emit('reload');
232 // Treat changes to sourcemaps as changes to the original files.
233 filename = filename.replace(/\.map$/, '');
234
235 config.livereload.io.sockets.emit('file_changed', {
236 path: filename,
237 name: path.basename(filename),
238 ext: path.extname(filename),
239 });
240 }
241 });
242 });
243 }
244
245 this.push(file);
246
247 callback();
248 })
249 .on('data', function(f) {
250 files.push(f);
251
252 // start the web server
253 webserver.listen(config.port, config.host, openInBrowser);
254
255 gutil.log('Webserver started at', gutil.colors.cyan('http' + (config.https ? 's' : '') + '://' + config.host + ':' + config.port));
256 })
257 .on('end', function(){
258 if (config.fallback) {
259 files.forEach(function(file){
260 var fallbackFile = file.path + '/' + config.fallback;
261 if (fs.existsSync(fallbackFile)) {
262 app.use(function(req, res) {
263 res.setHeader('Content-Type', 'text/html; charset=UTF-8');
264 fs.createReadStream(fallbackFile).pipe(res);
265 });
266 }
267 });
268 }
269 });
270
271
272 // once stream killed
273 stream.on('kill', function() {
274 webserver.close();
275
276 if (config.livereload.enable) {
277 config.livereload.ioServer.close();
278 }
279 });
280
281 return stream;
282};