You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

151 lines
4.6 KiB

11 years ago
9 years ago
10 years ago
10 years ago
10 years ago
9 years ago
9 years ago
9 years ago
10 years ago
9 years ago
9 years ago
9 years ago
10 years ago
12 years ago
10 years ago
9 years ago
11 years ago
9 years ago
9 years ago
11 years ago
9 years ago
11 years ago
11 years ago
11 years ago
9 years ago
11 years ago
9 years ago
11 years ago
9 years ago
10 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
10 years ago
  1. #!/usr/bin/env node
  2. "use strict";
  3. var dope = require("console-dope");
  4. var http = require("http");
  5. var cliArgs = require("command-line-args");
  6. var o = require("object-tools");
  7. var t = require("typical");
  8. var path = require("path");
  9. var loadConfig = require("config-master");
  10. var homePath = require("home-path");
  11. var logStats = require("stream-log-stats");
  12. var connect = require("connect");
  13. var morgan = require("morgan");
  14. var serveStatic = require("serve-static");
  15. var directory = require("serve-index");
  16. var compress = require("compression");
  17. var cliOptions = require("../lib/cli-options");
  18. /* specify the command line arg definitions and usage forms */
  19. var cli = cliArgs(cliOptions);
  20. var usage = cli.getUsage({
  21. title: "local-web-server",
  22. description: "Lightweight static web server, zero configuration.",
  23. footer: "Project home: https://github.com/75lb/local-web-server",
  24. forms: [
  25. "$ ws <server options>",
  26. "$ ws --config",
  27. "$ ws --help"
  28. ],
  29. groups: {
  30. server: "Server",
  31. misc: "Misc"
  32. }
  33. });
  34. /* parse command line args */
  35. try {
  36. var argv = cli.parse();
  37. } catch(err){
  38. halt(err.message);
  39. }
  40. /* Load and merge together options from
  41. - ~/.local-web-server.json
  42. - {cwd}/.local-web-server.json
  43. - the `local-web-server` property of {cwd}/package.json
  44. */
  45. var storedConfig = loadConfig(
  46. path.join(homePath(), ".local-web-server.json"),
  47. path.join(process.cwd(), ".local-web-server.json"),
  48. { jsonPath: path.join(process.cwd(), "package.json"), configProperty: "local-web-server" }
  49. );
  50. var builtInDefaults = {
  51. port: 8000,
  52. directory: process.cwd(),
  53. "refresh-rate": 500,
  54. mime: {}
  55. };
  56. /* override built-in defaults with stored config and then command line args */
  57. argv.server = o.extend(builtInDefaults, storedConfig, argv.server);
  58. /* user input validation */
  59. var logFormat = argv.server["log-format"];
  60. if (!t.isNumber(argv.server.port)) {
  61. halt("please supply a numeric port value");
  62. }
  63. if (argv.misc.config){
  64. dope.log("Stored config: ");
  65. dope.log(storedConfig);
  66. process.exit(0);
  67. } else if (argv.misc.help){
  68. dope.log(usage);
  69. } else {
  70. process.on("SIGINT", function(){
  71. dope.showCursor();
  72. dope.log();
  73. process.exit(0);
  74. });
  75. var app = connect();
  76. /* enable cross-origin requests on all resources */
  77. app.use(function(req, res, next){
  78. res.setHeader("Access-Control-Allow-Origin", "*");
  79. next();
  80. });
  81. /* log using --log-format (if supplied) */
  82. if(logFormat) {
  83. if (logFormat === "none"){
  84. // do nothing, no logging required
  85. } else {
  86. if (logFormat === "logstalgia"){
  87. /* customised logger :date token, purely to satisfy Logstalgia. */
  88. morgan.token("date", function(){
  89. var a = new Date();
  90. return (a.getDate() + "/" + a.getUTCMonth() + "/" + a.getFullYear() + ":" + a.toTimeString())
  91. .replace("GMT", "").replace(" (BST)", "");
  92. });
  93. logFormat = "combined";
  94. }
  95. app.use(morgan(logFormat));
  96. }
  97. /* if no `--log-format` was specified, pipe the default format output
  98. into `log-stats`, which prints statistics to the console */
  99. } else {
  100. dope.hideCursor();
  101. app.use(morgan("common", { stream: logStats({ refreshRate: argv.server["refresh-rate"] }) }));
  102. }
  103. /* --compress enables compression */
  104. if (argv.server.compress) app.use(compress());
  105. /* set the mime-type overrides specified in the config */
  106. serveStatic.mime.define(argv.server.mime);
  107. /* enable static file server, including directory browsing support */
  108. app.use(serveStatic(path.resolve(argv.server.directory)))
  109. .use(directory(path.resolve(argv.server.directory), { icons: true }));
  110. /* launch server */
  111. http.createServer(app)
  112. .on("error", function(err){
  113. if (err.code === "EADDRINUSE"){
  114. halt("port " + argv.server.port + " is already is use");
  115. } else {
  116. halt(err.message);
  117. }
  118. })
  119. .listen(argv.server.port);
  120. /* write launch information to stderr (stdout is reserved for web log output) */
  121. if (path.resolve(argv.server.directory) === process.cwd()){
  122. dope.error("serving at %underline{%s}", "http://localhost:" + argv.server.port);
  123. } else {
  124. dope.error("serving %underline{%s} at %underline{%s}", argv.server.directory, "http://localhost:" + argv.server.port);
  125. }
  126. }
  127. function halt(message){
  128. dope.red.log("Error: %s", message);
  129. dope.log(usage);
  130. process.exit(1);
  131. }