connect-utils.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. "use strict";
  2. var _ = require("./lodash.custom");
  3. var fs = require("fs");
  4. var config = require("./config");
  5. function getPath(options, relative, port) {
  6. if (options.get("mode") === "snippet") {
  7. return options.get("scheme") + "://HOST:" + port + relative;
  8. }
  9. else {
  10. return "//HOST:" + port + relative;
  11. }
  12. }
  13. var connectUtils = {
  14. /**
  15. * Allow users to disable the Browsersync snippet
  16. * @param {Immutable.Map} options
  17. * @returns {Boolean}
  18. */
  19. enabled: function (options) {
  20. const userValue = options.get("snippet");
  21. if (typeof userValue === "boolean") {
  22. return userValue;
  23. }
  24. return true;
  25. },
  26. /**
  27. * @param {Immutable.Map} options
  28. * @returns {String}
  29. */
  30. scriptTags: function (options) {
  31. var scriptPath = this.clientScript(options);
  32. var async = options.getIn(["snippetOptions", "async"]);
  33. var scriptDomain = options.getIn(["script", "domain"]);
  34. /**
  35. * Generate the [src] attribute based on user options
  36. */
  37. var scriptSrc = (function () {
  38. if (options.get("localOnly")) {
  39. return [
  40. options.get("scheme"),
  41. "://localhost:",
  42. options.get("port"),
  43. scriptPath
  44. ].join("");
  45. }
  46. /**
  47. * First, was "scriptPath" set? if so the user wanted full control over the
  48. * script tag output
  49. *
  50. */
  51. if (_.isFunction(options.get("scriptPath"))) {
  52. return options
  53. .get("scriptPath")
  54. .apply(null, getScriptArgs(options, scriptPath));
  55. }
  56. /**
  57. * Next, if "script.domain" was given, allow that + the path to the JS file
  58. * eg:
  59. * script.domain=localhost:3000
  60. * -> localhost:3000/browser-sync/browser-sync-client.js
  61. */
  62. if (scriptDomain) {
  63. if (_.isFunction(scriptDomain)) {
  64. return scriptDomain.call(null, options) + scriptPath;
  65. }
  66. if (scriptDomain.match(/\{port\}/)) {
  67. return (scriptDomain.replace("{port}", options.get("port")) +
  68. scriptPath);
  69. }
  70. return scriptDomain + scriptPath;
  71. }
  72. /**
  73. * Now if server or proxy, use dynamic script
  74. * eg:
  75. * browser-sync start --server
  76. * ->
  77. * "HOST:3000/browser-sync/browser-sync-client.js".replace("HOST", location.hostname)
  78. */
  79. if (options.get("server") || options.get("proxy")) {
  80. return scriptPath;
  81. }
  82. /**
  83. * Final use case is snippet mode
  84. * -> "http://HOST:3000/browser-sync/browser-sync-client.js".replace("HOST", location.hostname)
  85. * -> "//HOST:3000/browser-sync/browser-sync-client.js".replace("HOST", location.hostname)"
  86. */
  87. return getPath(options, scriptPath, options.get("port"));
  88. })();
  89. /**
  90. * Decide which template shall be used to generate the script tags
  91. */
  92. var template = (function () {
  93. if (scriptDomain || options.get("localOnly")) {
  94. return config.templates.scriptTagSimple;
  95. }
  96. return config.templates.scriptTag;
  97. })();
  98. /**
  99. * Finally read the template file from disk and replace
  100. * the dynamic values.
  101. */
  102. return fs
  103. .readFileSync(template, "utf8")
  104. .replace("%script%", scriptSrc)
  105. .replace("%async%", async ? "async" : "");
  106. },
  107. /**
  108. * @param {Map} options
  109. * @returns {String}
  110. */
  111. socketConnector: function (options) {
  112. var socket = options.get("socket");
  113. var template = fs.readFileSync(config.templates.connector, "utf-8");
  114. var url = connectUtils.getConnectionUrl(options);
  115. /**
  116. * ***Backwards compatibility***. While `socket.path` is technically a
  117. * socketIoClientConfig property, it's been documented previously
  118. * as a top-level option, so must stay.
  119. */
  120. var clientConfig = socket.get("socketIoClientConfig").merge({
  121. path: socket.get("path")
  122. });
  123. template = template
  124. .replace("%config%", JSON.stringify(clientConfig.toJS()))
  125. .replace("%options%", JSON.stringify(options))
  126. .replace("%url%", url);
  127. return template;
  128. },
  129. /**
  130. * @param {Object} socketOpts
  131. * @param {Map} options
  132. * @returns {String|Function}
  133. */
  134. getNamespace: function (socketOpts, options) {
  135. var namespace = socketOpts.namespace;
  136. if (typeof namespace === "function") {
  137. return namespace(options);
  138. }
  139. if (!namespace.match(/^\//)) {
  140. namespace = "/" + namespace;
  141. }
  142. return namespace;
  143. },
  144. /**
  145. * @param {Map} options
  146. * @returns {string}
  147. */
  148. getConnectionUrl: function (options) {
  149. var socketOpts = options.get("socket").toJS();
  150. var namespace = connectUtils.getNamespace(socketOpts, options);
  151. var protocol = "";
  152. var withHostnamePort = "'{protocol}' + location.hostname + ':{port}{ns}'";
  153. var withHost = "'{protocol}' + location.host + '{ns}'";
  154. var withDomain = "'{domain}{ns}'";
  155. var port = options.get("port");
  156. // default use-case is server/proxy
  157. var string = withHost;
  158. if (options.get("mode") !== "server") {
  159. protocol = options.get("scheme") + "://";
  160. string = withHostnamePort;
  161. }
  162. if (options.get("mode") === "proxy" && options.getIn(["proxy", "ws"])) {
  163. port = options.getIn(["socket", "port"]);
  164. }
  165. /**
  166. * Ensure socket.domain is always a string (for noop replacements later)
  167. */
  168. socketOpts.domain = (function () {
  169. if (options.get("localOnly")) {
  170. string = withDomain;
  171. return [
  172. options.get("scheme"),
  173. "://localhost:",
  174. options.get("port")
  175. ].join("");
  176. }
  177. if (socketOpts.domain) {
  178. string = withDomain;
  179. /**
  180. * User provided a function
  181. */
  182. if (_.isFunction(socketOpts.domain)) {
  183. return socketOpts.domain.call(null, options);
  184. }
  185. /**
  186. * User provided a string
  187. */
  188. if (_.isString(socketOpts.domain)) {
  189. return socketOpts.domain;
  190. }
  191. }
  192. return "";
  193. })();
  194. return string
  195. .replace("{protocol}", protocol)
  196. .replace("{port}", port)
  197. .replace("{domain}", socketOpts.domain.replace("{port}", port))
  198. .replace("{ns}", namespace);
  199. },
  200. /**
  201. * @param {Object} [options]
  202. * @param {Boolean} [both]
  203. */
  204. clientScript: function (options, both) {
  205. var prefix = options.getIn(["socket", "clientPath"]);
  206. var script = prefix + "/browser-sync-client.js";
  207. var versioned = prefix + "/browser-sync-client.js?v=" + options.get("version");
  208. if (both) {
  209. return {
  210. path: script,
  211. versioned: versioned
  212. };
  213. }
  214. return versioned;
  215. }
  216. };
  217. /**
  218. * @param options
  219. * @returns {*[]}
  220. */
  221. function getScriptArgs(options, scriptPath) {
  222. var abspath = options.get("scheme") + "://HOST:" + options.get("port") + scriptPath;
  223. return [scriptPath, options.get("port"), options.set("absolute", abspath)];
  224. }
  225. module.exports = connectUtils;
  226. //# sourceMappingURL=connect-utils.js.map