Skip to content

Commit b7825d9

Browse files
committed
Add script.domain property - re: #1128
1 parent b72455d commit b7825d9

6 files changed

Lines changed: 191 additions & 47 deletions

File tree

lib/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module.exports = {
1111
},
1212
templates: {
1313
scriptTag: path.join(__dirname, "templates/script-tags.tmpl"),
14+
scriptTagSimple: path.join(__dirname, "templates/script-tags-simple.tmpl"),
1415
connector: path.join(__dirname, "templates/connector.tmpl")
1516
},
1617
socketIoScript: "/public/socket.io.js",

lib/connect-utils.js

Lines changed: 94 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,44 +4,91 @@ var _ = require("../lodash.custom");
44
var fs = require("fs");
55
var config = require("./config");
66

7+
function getPath(options, relative, port) {
8+
if (options.get("mode") === "snippet") {
9+
return options.get("scheme") + "://HOST:" + port + relative;
10+
} else {
11+
return "//HOST:" + port + relative;
12+
}
13+
}
14+
715
var connectUtils = {
816
/**
917
* @param {Immutable.Map} options
1018
* @returns {String}
1119
*/
1220
scriptTags: function (options) {
1321

14-
function getPath(relative, port) {
15-
if (options.get("mode") === "snippet") {
16-
return options.get("scheme") + "://HOST:" + port + relative;
17-
} else {
18-
return "//HOST:" + port + relative;
22+
var scriptPath = this.clientScript(options);
23+
var async = options.getIn(["snippetOptions", "async"]);
24+
var scriptDomain = options.getIn(["script", "domain"]);
25+
26+
/**
27+
* Generate the [src] attribute based on user options
28+
*/
29+
var scriptSrc = (function () {
30+
31+
/**
32+
* First, was 'scriptPath' set? if so the user wanted full control over the
33+
* script tag output
34+
*
35+
*/
36+
if (_.isFunction(options.get("scriptPath"))) {
37+
return options.get("scriptPath").apply(null, getScriptArgs(options, scriptPath));
1938
}
20-
}
2139

22-
var template = fs.readFileSync(config.templates.scriptTag, "utf-8");
23-
var scriptPath = this.clientScript(options);
24-
var async = options.getIn(["snippetOptions", "async"]);
25-
var script;
26-
var override = false;
27-
28-
if (_.isFunction(options.get("scriptPath"))) {
29-
var args = getScriptArgs(options, scriptPath);
30-
script = options.get("scriptPath").apply(null, args);
31-
override = true;
32-
} else {
33-
script = getPath(scriptPath, options.get("port"));
34-
}
40+
/**
41+
* Next, if 'script.domain' was given, allow that + the path to the JS file
42+
* eg:
43+
* script.domain=localhost:3000
44+
* -> localhost:3000/browser-sync/browser-sync-client.js
45+
*/
46+
if (scriptDomain) {
47+
if (_.isFunction(scriptDomain)) {
48+
return scriptDomain.call(null, options) + scriptPath;
49+
}
50+
if (scriptDomain.match(/\{port\}/)) {
51+
return scriptDomain.replace("{port}", options.get("port")) + scriptPath;
52+
}
53+
return scriptDomain + scriptPath;
54+
}
3555

36-
if (!override && (options.get("server") || options.get("proxy"))) {
37-
script = scriptPath;
38-
}
56+
/**
57+
* Now if server or proxy, use dynamic script
58+
* eg:
59+
* browser-sync start --server
60+
* ->
61+
* "HOST:3000/browser-sync/browser-sync-client.js".replace("HOST", location.hostname)
62+
*/
63+
if (options.get("server") || options.get("proxy")) {
64+
return scriptPath;
65+
}
3966

40-
template = template
41-
.replace("%script%", script)
42-
.replace("%async%", async ? "async" : "");
67+
/**
68+
* Final use case is snippet mode
69+
* -> "http://HOST:3000/browser-sync/browser-sync-client.js".replace("HOST", location.hostname)
70+
* -> "//HOST:3000/browser-sync/browser-sync-client.js".replace("HOST", location.hostname)"
71+
*/
72+
return getPath(options, scriptPath, options.get("port"));
73+
})();
4374

44-
return template;
75+
/**
76+
* Decide which template shall be used to generate the script tags
77+
*/
78+
var template = (function () {
79+
if (scriptDomain) {
80+
return config.templates.scriptTagSimple;
81+
}
82+
return config.templates.scriptTag;
83+
})();
84+
85+
/**
86+
* Finally read the template file from disk and replace
87+
* the dynamic values.
88+
*/
89+
return fs.readFileSync(template, "utf8")
90+
.replace("%script%", scriptSrc)
91+
.replace("%async%", async ? "async" : "");
4592
},
4693
/**
4794
* @param {Map} options
@@ -116,17 +163,32 @@ var connectUtils = {
116163
port = options.getIn(["socket", "port"]);
117164
}
118165

119-
if (socketOpts.domain) {
120-
string = withDomain;
121-
if (typeof socketOpts.domain === "function") {
122-
socketOpts.domain = socketOpts.domain.call(null, options);
166+
/**
167+
* Ensure socket.domain is always a string (for noop replacements later)
168+
*/
169+
socketOpts.domain = (function () {
170+
if (socketOpts.domain) {
171+
string = withDomain;
172+
/**
173+
* User provided a function
174+
*/
175+
if (_.isFunction(socketOpts.domain)) {
176+
return socketOpts.domain.call(null, options);
177+
}
178+
/**
179+
* User provided a string
180+
*/
181+
if (_.isString(socketOpts.domain)) {
182+
return socketOpts.domain;
183+
}
123184
}
124-
}
185+
return "";
186+
})();
125187

126188
return string
127189
.replace("{protocol}", protocol)
128190
.replace("{port}", port)
129-
.replace("{domain}", socketOpts.domain)
191+
.replace("{domain}", socketOpts.domain.replace("{port}", port))
130192
.replace("{ns}", namespace);
131193
},
132194
/**

lib/default-config.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,14 @@ module.exports = {
444444
}
445445
},
446446

447+
/**
448+
* Configure the script domain
449+
* @property script
450+
* @param {String|Function} [domain=undefined]
451+
* @since 2.14.0
452+
* @type Object
453+
*/
454+
447455
tagNames: {
448456
"less": "link",
449457
"scss": "link",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<script %async% id="__bs_script__" src="%script%"></script>

test/specs/e2e/e2e.options.scriptpath.js

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@ var assert = require("chai").assert;
66
var request = require("supertest");
77

88
describe("E2E script path test - given a callback", function () {
9-
10-
var instance;
11-
12-
before(function (done) {
9+
it("Sets the script path", function (done) {
1310
browserSync.reset();
1411

1512
var config = {
@@ -21,19 +18,15 @@ describe("E2E script path test - given a callback", function () {
2118
return "localhost:PORT" + scriptPath;
2219
}
2320
};
24-
instance = browserSync(config, done).instance;
25-
});
26-
27-
after(function () {
28-
instance.cleanup();
29-
});
30-
31-
it("Sets the script path", function () {
32-
assert.include(instance.options.get("snippet"), "localhost:PORT/browser-sync/browser-sync-client.");
21+
browserSync(config, function (err, bs) {
22+
assert.include(bs.options.get("snippet"), "localhost:PORT/browser-sync/browser-sync-client.");
23+
bs.cleanup();
24+
done();
25+
});
3326
});
3427
});
3528

36-
describe("E2E Socket path test - given a callback", function () {
29+
describe("E2E Socket namespace test - given a string", function () {
3730

3831
var instance;
3932

@@ -55,7 +48,7 @@ describe("E2E Socket path test - given a callback", function () {
5548
instance.cleanup();
5649
});
5750

58-
it("sets the socket path", function (done) {
51+
it("sets the socket namespace", function (done) {
5952
request(instance.server)
6053
.get(instance.options.getIn(["scriptPaths", "path"]))
6154
.expect(200)

test/specs/utils/utils.connect.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
"use strict";
22

33
var utils = require("../../../lib/connect-utils");
4+
var bs = require("../../../");
5+
var req = require("supertest");
46
var merge = require("../../../lib/cli/cli-options").merge;
57
var assert = require("chai").assert;
68

@@ -144,4 +146,81 @@ describe("Connection snippetUtils", function () {
144146
var actual = utils.socketConnector(options);
145147
assert.include(actual, "___browserSync___.io('' + location.host + '/browser-sync', ___browserSync___.socketConfig);");
146148
});
149+
it("E2E Should allow setting of socket.domain + script.domain as strings", function (done) {
150+
bs.reset();
151+
bs.create().init({
152+
ui: false,
153+
logLevel: "silent",
154+
script: {
155+
domain: "http://localhost:3000"
156+
},
157+
socket: {
158+
domain: "http://localhost:3000"
159+
}
160+
}, function (err, bs) {
161+
162+
assert.include(bs.options.get("snippet"), "<script async id=\"__bs_script__\" src=\"http://localhost:3000/browser-sync");
163+
164+
var expected = "___browserSync___.io('http://localhost:3000/browser-sync'";
165+
166+
req(bs.server)
167+
.get(bs.options.getIn(["scriptPaths", "path"]))
168+
.expect(200)
169+
.end(function (err, res) {
170+
assert.include(res.text, expected, "Socket domain updated in response");
171+
bs.cleanup();
172+
done();
173+
});
174+
});
175+
});
176+
it("E2E Should allow setting of script.domain as functions", function (done) {
177+
bs.reset();
178+
bs.create().init({
179+
ui: false,
180+
logLevel: "silent",
181+
script: {
182+
domain: function (options) {
183+
return "http://mylocal:" + options.get("port");
184+
}
185+
}
186+
}, function (err, bs) {
187+
assert.include(bs.options.get("snippet"), "<script async id=\"__bs_script__\" src=\"http://mylocal:3000/browser-sync");
188+
bs.cleanup();
189+
done();
190+
});
191+
});
192+
it("E2E Should allow setting of script.domain with placeholder", function (done) {
193+
bs.reset();
194+
bs.create().init({
195+
ui: false,
196+
logLevel: "silent",
197+
script: {
198+
domain: "http://localhost:{port}"
199+
}
200+
}, function (err, bs) {
201+
assert.ok(bs.options.get("snippet").match(/http:\/\/localhost:\d{4,5}\/browser-sync/));
202+
bs.cleanup();
203+
done();
204+
});
205+
});
206+
it("E2E Should allow setting of socket.domain with placeholder", function (done) {
207+
bs.reset();
208+
bs.create().init({
209+
ui: false,
210+
logLevel: "silent",
211+
socket: {
212+
domain: "http://localhost:{port}"
213+
}
214+
}, function (err, bs) {
215+
req(bs.server)
216+
.get(bs.options.getIn(["scriptPaths", "path"]))
217+
.expect(200)
218+
.end(function (err, res) {
219+
// console.log(res.text)
220+
assert.ok(res.text.match(/io\('http:\/\/localhost:\d{4,5}\/browser-sync/));
221+
bs.cleanup();
222+
done();
223+
});
224+
});
225+
});
147226
});

0 commit comments

Comments
 (0)