server.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. var http = require("http");
  2. var fs = require("fs");
  3. var path = require("path");
  4. var config = require("./config");
  5. var svg = publicFile(config.defaults.public.svg);
  6. var indexPage = publicFile(config.defaults.indexPage);
  7. //var css = publicFile(config.defaults.public.css);
  8. var header = staticFile(config.defaults.components.header);
  9. var footer = staticFile(config.defaults.components.footer);
  10. var zlib = require("zlib");
  11. /**
  12. * @param {UI} ui
  13. * @returns {*}
  14. */
  15. function startServer(ui) {
  16. var connect = ui.bs.utils.connect;
  17. var serveStatic = ui.bs.utils.serveStatic;
  18. /**
  19. * Create a connect server
  20. */
  21. var app = connect();
  22. var socketJs = getSocketJs(ui);
  23. var jsFilename = "/" + md5(socketJs, 10) + ".js";
  24. //var cssFilename = "/" + md5(css, 10) + ".css";
  25. /**
  26. * Create a single big file with all deps
  27. */
  28. //app.use(serveFile(jsFilename, "js", socketJs));
  29. app.use(serveFile(config.defaults.socketJs, "js", socketJs));
  30. // also serve for convenience/testing
  31. app.use(serveFile(config.defaults.pagesConfig, "js", ui.pagesConfig));
  32. //
  33. app.use(serveFile(config.defaults.clientJs, "js", ui.clientJs));
  34. /**
  35. * Add any markup from plugins/hooks/templates
  36. */
  37. insertPageMarkupFromHooks(
  38. app,
  39. ui.pages,
  40. indexPage
  41. .replace("%pageMarkup%", ui.pageMarkup)
  42. .replace("%templates%", ui.templates)
  43. .replace("%svg%", svg)
  44. .replace("%header%", header)
  45. .replace(/%footer%/g, footer)
  46. );
  47. /**
  48. * gzip css
  49. */
  50. //app.use(serveFile(cssFilename, "css", css));
  51. app.use(serveStatic(path.join(__dirname, "../public")));
  52. /**
  53. * all public dir as static
  54. */
  55. app.use(serveStatic(publicDir("")));
  56. /**
  57. * History API fallback
  58. */
  59. app.use(require("connect-history-api-fallback"));
  60. /**
  61. * Development use
  62. */
  63. app.use("/node_modules", serveStatic(packageDir("node_modules")));
  64. /**
  65. * Return the server.
  66. */
  67. return {
  68. server: http.createServer(app),
  69. app: app
  70. };
  71. }
  72. /**
  73. * @param app
  74. * @param pages
  75. * @param markup
  76. */
  77. function insertPageMarkupFromHooks(app, pages, markup) {
  78. var cached;
  79. app.use(function (req, res, next) {
  80. if (req.url === "/" || pages[req.url.slice(1)]) {
  81. res.writeHead(200, {"Content-Type": "text/html", "Content-Encoding": "gzip"});
  82. if (!cached) {
  83. var buf = Buffer.from(markup, "utf-8");
  84. zlib.gzip(buf, function (_, result) {
  85. cached = result;
  86. res.end(result);
  87. });
  88. } else {
  89. res.end(cached);
  90. }
  91. } else {
  92. next();
  93. }
  94. });
  95. }
  96. /**
  97. * Serve Gzipped files & cache them
  98. * @param app
  99. * @param all
  100. */
  101. var gzipCache = {};
  102. function serveFile(path, type, string) {
  103. var typemap = {
  104. js: "application/javascript",
  105. css: "text/css"
  106. };
  107. return function (req, res, next) {
  108. if (req.url !== path) {
  109. return next();
  110. }
  111. res.writeHead(200, {
  112. "Content-Type": typemap[type],
  113. "Content-Encoding": "gzip",
  114. "Cache-Control": "no-cache, no-store, must-revalidate",
  115. "Expires": 0,
  116. "Pragma": "no-cache"
  117. });
  118. if (gzipCache[path]) {
  119. return res.end(gzipCache[path]);
  120. }
  121. var buf = Buffer.from(string, "utf-8");
  122. zlib.gzip(buf, function (_, result) {
  123. gzipCache[path] = result;
  124. res.end(result);
  125. });
  126. };
  127. }
  128. /**
  129. * @param cp
  130. * @returns {string}
  131. */
  132. function getSocketJs (cp) {
  133. return [
  134. cp.bs.getExternalSocketConnector({namespace: "/browser-sync-cp"})
  135. ].join(";");
  136. }
  137. ///**
  138. // * @returns {*}
  139. // * @param filepath
  140. // */
  141. //function fileContent (filepath) {
  142. // return fs.readFileSync(require.resolve(filepath), "utf8");
  143. //}
  144. /**
  145. * @param src
  146. * @param length
  147. */
  148. function md5(src, length) {
  149. var crypto = require("crypto");
  150. var hash = crypto.createHash("md5").update(src, "utf8").digest("hex");
  151. return hash.slice(0, length);
  152. }
  153. /**
  154. * CWD directory helper for static dir
  155. * @param {string} filepath
  156. * @returns {string}
  157. */
  158. function publicDir (filepath) {
  159. return path.join(__dirname, "/../public" + filepath) || "";
  160. }
  161. /**
  162. * @param {string} filepath
  163. * @returns {string|string}
  164. */
  165. function staticDir (filepath) {
  166. return path.join(__dirname, "/../static" + filepath) || "";
  167. }
  168. /**
  169. * @param {string} filepath
  170. * @returns {*}
  171. */
  172. function publicFile(filepath) {
  173. return fs.readFileSync(publicDir(filepath), "utf-8");
  174. }
  175. /**
  176. * @param filepath
  177. * @returns {*}
  178. */
  179. function staticFile(filepath) {
  180. return fs.readFileSync(staticDir(filepath), "utf-8");
  181. }
  182. /**
  183. * @param {string} filepath
  184. * @returns {string}
  185. */
  186. function packageDir (filepath) {
  187. return path.join(__dirname, "/../" + filepath);
  188. }
  189. module.exports = startServer;