-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
executable file
·173 lines (149 loc) · 5.3 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#!/usr/bin/env node
'use strict';
var path = require('path');
var http = require('http');
var express = require('express');
var portfinder = require('portfinder');
var opener = require('opener');
var program = require('commander');
var serveStatic = require('serve-static');
var pkg = require('./package.json');
var defaults = require('./defaults.json');
// parse option as a list
function li(delimiter) {
delimiter = delimiter || ' ';
return function (value) {
return !value ? [] : value.split(delimiter);
};
}
// parse option as seconds
function seconds(deflt) {
deflt = deflt || 0;
return function (value) {
var i = parseInt(value, 10);
if (isNaN(i)) return d;
return i;
}
}
// middleware to add CORS headers
function cors() {
return function (req, res, next) {
res.set({
'Access-Control-Allow-Origin': '*'
});
next();
};
}
// middleware to prevent caching - via headers
function nocache() {
return function (req, res, next) {
res.set({
'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0'
});
next();
}
}
// simple file watching.
// TODO: support globbing and multiple watch dirs
function watch(path, callback) {
var o = {
ignoreDotFiles: !program.hidden,
persistent: true,
interval: watchInterval
};
require('watch')
.watchTree(path, o, function (f, curr, prev) {
if (typeof f == "object" && prev === null && curr === null) {
} else if (prev === null) {
} else if (curr !== null && curr.nlink === 0) {
} else {
callback();
}
});
return true;
}
function noop() {}
program
.version(pkg.version)
.usage('[options] [directory]')
.option('-u, --url <URL>', 'URL to open in the browser.\n\t\t\t\tDo not include the origin (protocol/host/port).')
.option('-p, --port <PORT>', 'Listen on PORT. \n\t\t\t\tAn available port will be chosen if not specified.')
.option('-w, --watch', 'When you don\'t want to watch the root directory.')
.option('-l, --log <TYPE>', 'Turn on log messages.\n\t\t\t\tTypes are: tiny, verbose')
.option('-a, --age <SECONDS>', 'Max age in seconds.', seconds(defaults.maxAge))
.option('-c, --cors', 'Enable CORS headers.')
.option('-i, --interval <MS>',
'Watch polling interval in milliseconds. Default 500.', seconds(defaults.watchInterval))
.option('-R, --no-reload', 'No Livereload')
.option('-O, --no-open', 'Dont open browser after starting the server')
.option('-N, --no-cache', 'Turn off all caching')
.option('-L, --no-listing', 'Turn off directory listings')
.option('-I, --index <FILES>',
'Optional default index page. \n\t\t\t\tSpace separated list eg default.html index.html.', li())
.option('-A, --address <ADDRESS>', 'Address to use [' + defaults.address + ']', defaults.address)
.option('-H, --hidden', 'Allow hidden files')
.option('-C, --compression', 'Turn on gzipping')
.parse(process.argv);
var app = express();
var server = http.createServer(app);
var log = !program.log ? noop : console.log;
var verbose = program.log === 'verbose' ? console.log : noop;
var maxAge = !program.cache ? 0 : (program.age || defaults.maxAge) * 1000;
var indexPages = program.index && program.index.length ? program.index : defaults.indexPages;
var watchInterval = program.interval || defaults.watchInterval;
var cwd = process.cwd();
var directory = !!program.args.length ? path.resolve(cwd, program.args[0]) : cwd;
var watchDirectory = program.watch ? path.resolve(cwd, program.watch) : directory;
var staticOptions = { index: indexPages, maxAge: maxAge, hidden: program.hidden};
var listingOptions = { hidden: program.hidden, icons: true, view: 'details' };
verbose('Using directory: %s', directory);
app.enable('trust proxy');
app.disable('x-powered-by');
program.log && app.use(require('morgan')(program.log === 'verbose' ? 'default' : 'dev'));
program.compression && app.use(require('compression'));
program.cors && app.use(cors());
!program.cache && app.use(nocache());
if (program.reload) {
// inject the livereload script into html pages
app.use(require('connect-inject')({
snippet: [
'<script src="/socket.io/socket.io.js"></script>',
'<script>io.connect(window.location.origin).on(\'reload\', function (data) { window.location.reload(); });</script>'
]
}));
verbose('Starting live reload server');
var io = require('socket.io').listen(server, { log: false });
io.set('log level', 1);
verbose('creating change watcher');
watch(watchDirectory, function () {
io.sockets.emit('reload');
});
}
// basic static file server
app.use(serveStatic(directory, staticOptions));
// directory listings
program.listing && app.use(require('serve-index')(directory, listingOptions));
// very basic error handling.
// TODO: is more needed here?
app.use(function (err, req, res, next) {
console.error(err);
});
function listen(p) {
server.listen(p);
log('Listening on port %s', p);
var url = 'http://' + program.address + ':' + p.toString() + '/' + (program.url || '');
if (program.open) {
verbose('Opening browser...');
!program.log && console.log(pkg.name + ' running at %s', url);
opener(url);
}
}
if (!program.port) {
portfinder.basePort = defaults.basePort;
portfinder.getPort(function (err, port) {
if (err) throw err;
listen(port);
});
} else {
listen(program.port);
}