browser-sync
Advanced tools
Comparing version 0.9.1 to 1.0.0
var browserSync = require("./lib/index"); | ||
var lr = require("./live-reload"); | ||
@@ -8,8 +7,7 @@ console.time("init"); | ||
var files = ["test/fixtures/assets/*", "test/fixtures/*.html"]; | ||
files = ["/Users/shakyshane/Sites/swoon-static/assets/css/**"] | ||
var options = { | ||
server: { | ||
baseDir: ["test/fixtures"] | ||
}, | ||
// server: { | ||
// baseDir: ["test/fixtures"] | ||
// }, | ||
// proxy: "swoon.static/store-home.php", | ||
@@ -21,8 +19,14 @@ ghostMode: { | ||
}, | ||
// tunnel: true, | ||
ports: { | ||
min: 4000, | ||
max: 4003 | ||
}, | ||
open: true, | ||
logConnections: false, | ||
minify: false, | ||
minify: true, | ||
// host: , | ||
notify: true, | ||
xip: true, | ||
browser: ["google chrome", "safari"] | ||
xip: false, | ||
browser: ["google chrome"] | ||
}; | ||
@@ -38,5 +42,5 @@ | ||
console.timeEnd("init"); | ||
setTimeout(function () { | ||
browserSync.notify("5 Seconds have passed!"); | ||
}, 5000); | ||
// setTimeout(function () { | ||
// browserSync.notify("5 Seconds have passed!"); | ||
// }, 5000); | ||
}); |
@@ -1,22 +0,24 @@ | ||
var gulp = require('gulp'); | ||
var jshint = require('gulp-jshint'); | ||
var contribs = require('gulp-contribs'); | ||
var sass = require('gulp-sass'); | ||
var rubySass = require('gulp-ruby-sass'); | ||
var browserSync = require('./lib/index'); | ||
"use strict"; | ||
gulp.task('lint', function () { | ||
gulp.src(['test/specs/**/*.js', '!test/fixtures/**', 'lib/*']) | ||
.pipe(jshint('test/specs/.jshintrc')) | ||
.pipe(jshint.reporter('default')) | ||
.pipe(jshint.reporter('fail')) | ||
var gulp = require("gulp"); | ||
var jshint = require("gulp-jshint"); | ||
var contribs = require("gulp-contribs"); | ||
var sass = require("gulp-sass"); | ||
var rubySass = require("gulp-ruby-sass"); | ||
var browserSync = require("./lib/index"); | ||
gulp.task("lint", function () { | ||
gulp.src(["test/specs/**/*.js", "!test/fixtures/**", "lib/*"]) | ||
.pipe(jshint("test/specs/.jshintrc")) | ||
.pipe(jshint.reporter("default")) | ||
.pipe(jshint.reporter("fail")); | ||
}); | ||
gulp.task('contribs', function () { | ||
gulp.src('README.md') | ||
gulp.task("contribs", function () { | ||
gulp.src("README.md") | ||
.pipe(contribs()) | ||
.pipe(gulp.dest("./")) | ||
.pipe(gulp.dest("./")); | ||
}); | ||
gulp.task('default', ['lint']); | ||
gulp.task("default", ["lint"]); | ||
@@ -29,3 +31,3 @@ var paths = { | ||
gulp.task('sass', function () { | ||
gulp.task("sass", function () { | ||
browserSync.notify("Compiling SCSS files... Please Wait"); | ||
@@ -41,3 +43,3 @@ gulp.src(paths.scss) | ||
*/ | ||
gulp.task('browser-sync', function () { | ||
gulp.task("browser-sync", function () { | ||
@@ -56,2 +58,6 @@ // var clientScript = require("/Users/shakyshane/Sites/browser-sync-modules/browser-sync-client/index"); | ||
}); | ||
setTimeout(function () { | ||
browserSync.exit(); | ||
}, 3000); | ||
}); | ||
@@ -62,3 +68,3 @@ | ||
*/ | ||
gulp.task('bs-reload', function () { | ||
gulp.task("bs-reload", function () { | ||
browserSync.reload(); | ||
@@ -70,6 +76,6 @@ }); | ||
*/ | ||
gulp.task('watch', ['browser-sync'], function () { | ||
gulp.watch(paths.scss, ['sass']); | ||
gulp.watch(paths.html, ['bs-reload']); | ||
gulp.task("watch", ["browser-sync"], function () { | ||
gulp.watch(paths.scss, ["sass"]); | ||
gulp.watch(paths.html, ["bs-reload"]); | ||
}); | ||
@@ -8,6 +8,7 @@ "use strict"; | ||
var config = require("./config"); | ||
var tunnel = require("./tunnel"); | ||
var messages = require("./messages"); | ||
var utils = require("./utils").utils; | ||
var fileWatcher = require("./file-watcher"); | ||
var bsControlPanel = require("browser-sync-control-panel"); | ||
var bsClient = require("browser-sync-client"); | ||
@@ -22,4 +23,3 @@ var _ = require("lodash"); | ||
"plugin:socket": socket.plugin, | ||
"plugin:logger": logger.plugin, | ||
"plugin:controlpanel": bsControlPanel.plugin | ||
"plugin:logger": logger.plugin | ||
}; | ||
@@ -32,3 +32,2 @@ | ||
this.cwd = process.cwd(); | ||
this.minPorts = 2; | ||
this.events = new events.EventEmitter(); | ||
@@ -99,2 +98,3 @@ this.events.setMaxListeners(20); | ||
this.loadPlugins(); | ||
this.getPlugin("logger")(this.events, options); | ||
@@ -104,20 +104,15 @@ | ||
if (options.server && options.proxy) { | ||
err = "Invalid config. You cannot specify both a server & proxy option."; | ||
this.callback(err); | ||
utils.fail(err, options, true); | ||
utils.fail(messages.configError(err), options, true); | ||
} | ||
var success = function (ports) { | ||
services.init(this)(ports, files, options); | ||
}.bind(this); | ||
var error = function (err) { | ||
this.callback(err); | ||
utils.fail(err, options, true); | ||
}.bind(this); | ||
utils.getPorts(options) | ||
.then(this.handleSuccess.bind(this, options)) | ||
.catch(this.handleError.bind(this, options)); | ||
utils.getPorts(options, this.minPorts) | ||
.then(success) | ||
.catch(error); | ||
return this; | ||
@@ -127,2 +122,52 @@ }; | ||
/** | ||
* @param options | ||
* @param err | ||
*/ | ||
BrowserSync.prototype.handleError = function (options, err) { | ||
this.callback(err); | ||
utils.fail(err, options, true); | ||
}; | ||
/** | ||
* @param options | ||
* @param ports | ||
*/ | ||
BrowserSync.prototype.handleSuccess = function (options, ports) { | ||
var that = this; | ||
var debug = this.debug = utils.getDebugger(options); | ||
function init() { | ||
services.init(that)(ports[0], options.files || [], options); | ||
} | ||
if (typeof options.online === "undefined") { | ||
debug("Checking if there's an internet connection..."); | ||
require("dns").resolve("www.google.com", function(err) { | ||
if (err) { | ||
debug("Could not resolve www.google.com, setting online: false"); | ||
options.online = false; | ||
} else { | ||
debug("Resolved, setting online: true"); | ||
options.online = true; | ||
} | ||
init(); | ||
}); | ||
} else { | ||
init(); | ||
} | ||
}; | ||
/** | ||
* Callback helper | ||
@@ -156,2 +201,9 @@ * @param err | ||
this.io.sockets.emit("browser:notify", data); | ||
}, | ||
"service:running": function (data) { | ||
utils.openBrowser(data.url, options); | ||
}, | ||
"msg:debug": function (data) { | ||
var debug = utils.getDebugger(options); | ||
debug(data.msg, data.vars || "", options); | ||
} | ||
@@ -201,40 +253,71 @@ }; | ||
* @param {String} host | ||
* @param {Object} ports | ||
* @param {Number} port | ||
* @param {Object} options | ||
* @param {Object} io | ||
* @returns {*|http.Server} | ||
* @param {String|Function} scripts | ||
* @returns {Boolean|http.Server} | ||
*/ | ||
BrowserSync.prototype.initServer = function (host, ports, options, io) { | ||
BrowserSync.prototype.initServer = function (host, port, options, scripts) { | ||
var proxy = options.proxy || false; | ||
var server = options.server || false; | ||
var proxy = options.proxy || false; | ||
var server = options.server || false; | ||
var debug = utils.getDebugger(options); | ||
var snippet = (!server && !proxy); | ||
var baseDir = utils.getBaseDir(server.baseDir || "./"); | ||
var type = false; | ||
var type = "snippet"; | ||
var events = this.events; | ||
var servers = serverModule.launchServer(host, ports, options, io); | ||
var servers = serverModule.launchServer(host, port, options, scripts); | ||
if (server) { | ||
if (server || snippet) { | ||
if (servers.staticServer) { | ||
servers.staticServer.listen(ports.server); | ||
servers.staticServer.listen(port); | ||
debug("Static Server runnning..."); | ||
} | ||
type = "server"; | ||
type = server ? "server" : "snippet"; | ||
} | ||
if (proxy) { | ||
if (servers.proxyServer) { | ||
servers.proxyServer.listen(ports.proxy); | ||
servers.proxyServer.listen(port); | ||
debug("Proxy running, proxing: %s", options.proxy.target); | ||
} | ||
type = "proxy"; | ||
} | ||
options.url = utils.getUrl(utils._makeUrl(host, ports[type]), options); | ||
debug("Running mode: %s", type.toUpperCase()); | ||
options.url = utils.getUrl(utils._makeUrl(host, port), options); | ||
if (type && (server || proxy)) { | ||
utils.openBrowser(options.url, options); | ||
if (options.tunnel && options.online) { | ||
this.events.emit("open", { | ||
tunnel.init(this, port, emitEvent); | ||
} else { | ||
emitEvent(options.urls.local); | ||
} | ||
} else { | ||
emitEvent("n/a"); | ||
} | ||
function emitEvent(url, tunnel) { | ||
events.emit("service:running", { | ||
type: type, | ||
baseDir: baseDir || null, | ||
port: ports[type] | ||
port: port, | ||
url: url, | ||
tunnel: tunnel ? url : false | ||
}); | ||
@@ -241,0 +324,0 @@ } |
@@ -15,143 +15,4 @@ /* | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Files to watch | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-files | ||
*/ | ||
files: [], | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Directories or files to exclude | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-exclude | ||
*/ | ||
exclude: false, | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Server | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-server | ||
*/ | ||
server: false, | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Proxy | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-proxy | ||
*/ | ||
proxy: false, | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Start path | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-startPath | ||
*/ | ||
startPath: null, | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Ghost Mode | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-ghostmode | ||
*/ | ||
ghostMode: { | ||
clicks: true, | ||
links: true, | ||
forms: true, | ||
scroll: true | ||
}, | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Open (true|false) | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-open | ||
*/ | ||
open: true, | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| xip (true|false) | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-xip | ||
*/ | ||
xip: false, | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Timestamps (true|false) | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-timestamps | ||
*/ | ||
timestamps: true, | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| File Timeout (milliseconds) | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-filetimeout | ||
*/ | ||
fileTimeout: 1000, | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Inject Changes | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-injectchanges | ||
*/ | ||
injectChanges: true, | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Scroll Proportionally (true|false) | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-scrollproportionally | ||
*/ | ||
scrollProportionally: true, | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Scroll Throttle (milliseconds) | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-scrollthrottle | ||
*/ | ||
scrollThrottle: 0, | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Notify (true|false) | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-notify | ||
*/ | ||
notify: true, | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Host | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-host | ||
*/ | ||
host: null, | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Excluded File Types | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-excludedfiletypes | ||
*/ | ||
excludedFileTypes: [], | ||
/* | ||
|-------------------------------------------------------------------------- | ||
| Reload Delay | ||
|-------------------------------------------------------------------------- | ||
| https://github.com/shakyShane/browser-sync/wiki/options#wiki-reloadDelay | ||
*/ | ||
reloadDelay: 0 | ||
// options here | ||
}; |
"use strict"; | ||
var messages = require("./messages"); | ||
var config = require("./config"); | ||
var messages = require("./messages"); | ||
var config = require("./config"); | ||
var defaultConfig = require("./default-config"); | ||
var fs = require("fs"); | ||
var fs = require("fs"); | ||
var path = require("path"); | ||
@@ -23,14 +25,14 @@ module.exports = { | ||
getDefaultConfigFile: function () { | ||
var defaultPath = process.cwd() + config.configFile; | ||
return this._getConfigFile(defaultPath); | ||
return defaultConfig; | ||
}, | ||
/** | ||
* Retrieve the config file | ||
* @param {String} path | ||
* @returns {*} | ||
* @private | ||
* @param filePath | ||
*/ | ||
_getConfigFile: function (path) { | ||
if (fs.existsSync(path)) { | ||
return require(fs.realpathSync(path)); | ||
_getConfigFile: function (filePath) { | ||
var relPath = path.resolve(process.cwd() + "/" + filePath); | ||
if (fs.existsSync(relPath)) { | ||
return require(relPath); | ||
} | ||
@@ -37,0 +39,0 @@ return false; |
@@ -8,3 +8,3 @@ "use strict"; | ||
var program = require("commander"); | ||
var _ = require("lodash"); | ||
var merge = require("opt-merger").merge; | ||
@@ -14,45 +14,2 @@ module.exports.allowedOptions = ["host", "server", "proxy"]; | ||
/** | ||
* @param {String} string | ||
* @returns {string} | ||
*/ | ||
function ucfirst(string) { | ||
return string.charAt(0).toUpperCase() + string.slice(1); | ||
} | ||
/** | ||
* Template for creating a method name | ||
* @param {String} key | ||
* @returns {String} | ||
*/ | ||
module.exports.methodName = function (key) { | ||
return "_merge%sOption".replace("%s", ucfirst(key)); | ||
}; | ||
/** | ||
* @param {Object} obj | ||
* @param {String} key | ||
* @param {Object} args | ||
* @returns {Object} | ||
*/ | ||
module.exports.transformOption = function (obj, key, args) { | ||
if (args[key] && typeof obj[key] !== "undefined") { | ||
obj[key] = cliOptions[exports.methodName(key)](obj[key], args[key], args); | ||
} | ||
return obj; | ||
}; | ||
/** | ||
* @param {Object} defaultConfig | ||
* @param {Object} args | ||
* @param {Array} allowedOptions | ||
* @returns {Object} | ||
*/ | ||
module.exports.mergeOptions = function (defaultConfig, args, allowedOptions) { | ||
return allowedOptions | ||
.reduce(function (obj, key) { | ||
return exports.transformOption(obj, key, args); | ||
}, defaultConfig); | ||
}; | ||
/** | ||
* Handle command-line usage with 'start' | ||
@@ -64,3 +21,2 @@ * @param args | ||
var options = {}; | ||
var userConfig; | ||
@@ -71,22 +27,6 @@ | ||
userConfig = info._getConfigFile(args.config); | ||
} else { | ||
userConfig = info.getDefaultConfigFile(); | ||
} | ||
if (args.xip) { | ||
defaultConfig.xip = true; | ||
} | ||
var options = merge(defaultConfig, userConfig || {}, cliOptions.callbacks); | ||
if (args.open === false) { | ||
defaultConfig.open = false; | ||
} | ||
if (userConfig) { | ||
options = _.merge(defaultConfig, userConfig); | ||
options = exports.mergeOptions(defaultConfig, options, exports.allowedOptions); | ||
} else { | ||
options = exports.mergeOptions(defaultConfig, args, exports.allowedOptions); | ||
options.files = cliOptions._mergeFilesOption(args.files, options.exclude); | ||
} | ||
cb(null, { | ||
@@ -101,3 +41,3 @@ files: options.files || [], | ||
* @param {Object} args - optimist object | ||
* @param {Object} argv - process.argv | ||
* @param {Object} argv | ||
* @param {Function} cb | ||
@@ -110,10 +50,16 @@ */ | ||
.usage("<command> [options]") | ||
.option("--files", "File paths to watch") | ||
.option("--server", "Run a Local server (uses your cwd as the web root)") | ||
.option("--files", "File paths to watch") | ||
.option("--exclude", "File patterns to ignore") | ||
.option("--server", "Run a Local server (uses your cwd as the web root)") | ||
.option("--directory", "Show a directory listing for the server") | ||
.option("--proxy", "Proxy an existing server") | ||
.option("--xip", "Use xip.io domain routing") | ||
.option("--no-open", "Don't open a new browser window") | ||
.option("--config", "Specify a path to a bs-config.js file") | ||
.option("--host", "Specify a hostname to use"); | ||
.option("--proxy", "Proxy an existing server") | ||
.option("--xip", "Use xip.io domain routing") | ||
.option("--tunnel", "Use a public URL") | ||
.option("--config", "Specify a path to a bs-config.js file") | ||
.option("--host", "Specify a hostname to use") | ||
.option("--logLevel", "Set the logger output level (silent, info or debug)") | ||
.option("--port", "Specify a port to use") | ||
.option("--no-open", "Don't open a new browser window") | ||
.option("--no-ghost", "Disable Ghost Mode") | ||
.option("--no-online", "Force offline usage"); | ||
@@ -120,0 +66,0 @@ program |
"use strict"; | ||
var path = require("path"); | ||
var _ = require("lodash"); | ||
module.exports = { | ||
var utils = { | ||
/** | ||
* Merge Server Options | ||
* @param {Object} defaultValue | ||
* @param {String} arg | ||
* @param {Object} [argv] - process.argv | ||
* @returns {{baseDir: string}} | ||
* @param pattern | ||
* @returns {*|string} | ||
* @private | ||
*/ | ||
_mergeServerOption: function (defaultValue, arg, args) { | ||
wrapPattern: function (pattern) { | ||
var prefix = "!"; | ||
var suffix = "/**"; | ||
var lastChar = pattern.charAt(pattern.length - 1); | ||
var extName = path.extname(pattern); | ||
// If there's a file ext, don't append any suffix | ||
if (extName.length) { | ||
suffix = ""; | ||
} else { | ||
if (lastChar === "/") { | ||
suffix = "**"; | ||
} | ||
if (lastChar === "*") { | ||
suffix = ""; | ||
} | ||
} | ||
return [prefix, pattern, suffix].join(""); | ||
} | ||
}; | ||
module.exports.utils = utils; | ||
module.exports.callbacks = { | ||
/** | ||
* Merge server options | ||
* @param defaultValue | ||
* @param newValue | ||
* @param args | ||
* @returns {*} | ||
*/ | ||
server: function (defaultValue, newValue, args) { | ||
// Return if object or array given | ||
if (arg.baseDir) { | ||
return arg; | ||
if (typeof newValue === "undefined") { | ||
return defaultValue; | ||
} | ||
if (newValue.baseDir) { | ||
return newValue; | ||
} | ||
var obj = { | ||
@@ -25,10 +63,12 @@ baseDir: "./" | ||
if (arg !== true) { | ||
obj.baseDir = arg; | ||
if (newValue !== true) { | ||
obj.baseDir = newValue; | ||
} | ||
if (args) { | ||
if (args.index) { | ||
obj.index = args.index; | ||
} | ||
if (args.directory) { | ||
@@ -43,11 +83,11 @@ obj.directory = true; | ||
* @param defaultValue | ||
* @param arg | ||
* @param newValue | ||
* @param args | ||
* @param config | ||
* @returns {*} | ||
* @private | ||
*/ | ||
_mergeProxyOption: function (defaultValue, arg) { | ||
proxy: function (defaultValue, newValue, args, config) { | ||
var protocol = "http"; | ||
var host = "localhost"; | ||
var target = ""; | ||
var port = 80; | ||
@@ -58,7 +98,7 @@ var segs; | ||
if (typeof arg !== "string") { | ||
if (typeof newValue !== "string") { | ||
return false; | ||
} | ||
var url = arg.replace(/^(https?):\/\//, function (match, solo) { | ||
var url = newValue.replace(/^(https?):\/\//, function (match, solo) { | ||
protocol = solo; | ||
@@ -97,9 +137,9 @@ return ""; | ||
* @param {Object} defaultValue | ||
* @param {String} arg | ||
* @param {String} newValue | ||
* @returns {String} | ||
* @private | ||
*/ | ||
_mergeHostOption: function (defaultValue, arg) { | ||
if (arg && typeof arg === "string") { | ||
return arg; | ||
host: function (defaultValue, newValue) { | ||
if (newValue && typeof newValue === "string") { | ||
return newValue; | ||
} | ||
@@ -110,6 +150,6 @@ return null; | ||
* @param defaultValue | ||
* @param arg | ||
* @param newValue | ||
* @private | ||
*/ | ||
_mergePortsOption: function (defaultValue, arg) { | ||
ports: function (defaultValue, newValue) { | ||
@@ -119,10 +159,10 @@ var segs; | ||
if (typeof arg === "string") { | ||
if (typeof newValue === "string") { | ||
if (~arg.indexOf(",")) { | ||
segs = arg.split(","); | ||
if (~newValue.indexOf(",")) { | ||
segs = newValue.split(","); | ||
obj.min = parseInt(segs[0], 10); | ||
obj.max = parseInt(segs[1], 10); | ||
} else { | ||
obj.min = parseInt(arg, 10); | ||
obj.min = parseInt(newValue, 10); | ||
obj.max = null; | ||
@@ -135,4 +175,4 @@ } | ||
return { | ||
min: arg.min, | ||
max: arg.max || null | ||
min: newValue.min, | ||
max: newValue.max || null | ||
}; | ||
@@ -142,27 +182,55 @@ } | ||
/** | ||
* @private | ||
* @param defaultValue | ||
* @param newValue | ||
* @returns {*} | ||
*/ | ||
_mergeGhostModeOption: function (defaultValue, arg) { | ||
if (!arg || arg === "false") { | ||
ghostMode: function (defaultValue, newValue) { | ||
var def = _.cloneDeep(defaultValue); | ||
if (newValue === "false" || newValue === false) { | ||
return false; | ||
} | ||
return arg; | ||
if (newValue === "true" || newValue === true) { | ||
def.location = true; | ||
return def; | ||
} | ||
if (newValue && typeof newValue.forms !== "undefined") { | ||
if (newValue.forms === false) { | ||
newValue.forms = {}; | ||
_.each(def.forms, function (value, key) { | ||
newValue.forms[key] = false; | ||
}); | ||
} | ||
if (newValue.forms === true) { | ||
delete newValue.forms; | ||
} | ||
} | ||
return _.merge(def, newValue); | ||
}, | ||
/** | ||
* | ||
* @param {String|Array} files | ||
* @param {String|Array} [exclude] | ||
* @returns {Array} | ||
* @private | ||
* @param defaultValue | ||
* @param newValue | ||
* @param args | ||
* @param config | ||
* @returns {*} | ||
*/ | ||
_mergeFilesOption: function (files, exclude) { | ||
files: function (defaultValue, newValue, args, config) { | ||
var merged; | ||
var split; | ||
var exclude = config && config.exclude ? config.exclude : false; | ||
if (files) { | ||
if (typeof files === "string") { | ||
if (newValue) { | ||
if (typeof newValue === "string") { | ||
merged = []; | ||
if (~files.indexOf(",")) { | ||
split = files.split(","); | ||
if (~newValue.indexOf(",")) { | ||
split = newValue.split(","); | ||
merged = merged.concat(split.map(function (item) { | ||
@@ -172,6 +240,6 @@ return item.trim(); | ||
} else { | ||
merged.push(files); | ||
merged.push(newValue); | ||
} | ||
} else { | ||
merged = files; | ||
merged = newValue; | ||
} | ||
@@ -181,7 +249,10 @@ } | ||
if (typeof exclude === "string") { | ||
merged.push(this._wrapPattern(exclude)); | ||
merged.push(utils.wrapPattern(exclude)); | ||
} else { | ||
if (Array.isArray(exclude)) { | ||
exclude.forEach(function (pattern) { | ||
merged.push(this._wrapPattern(pattern)); | ||
merged.push(utils.wrapPattern(pattern)); | ||
}, this); | ||
@@ -192,30 +263,3 @@ } | ||
return merged; | ||
}, | ||
/** | ||
* @param pattern | ||
* @returns {*|string} | ||
* @private | ||
*/ | ||
_wrapPattern: function (pattern) { | ||
var prefix = "!"; | ||
var suffix = "/**"; | ||
var lastChar = pattern.charAt(pattern.length - 1); | ||
var extName = path.extname(pattern); | ||
// If there's a file ext, don't append any suffix | ||
if (extName.length) { | ||
suffix = ""; | ||
} else { | ||
if (lastChar === "/") { | ||
suffix = "**"; | ||
} | ||
if (lastChar === "*") { | ||
suffix = ""; | ||
} | ||
} | ||
return [prefix, pattern, suffix].join(""); | ||
} | ||
}; |
module.exports = { | ||
debugInfo: true, | ||
files: false, | ||
injectFileTypes: ["css", "png", "jpg", "jpeg", "svg", "gif", "webp"], | ||
@@ -11,3 +12,4 @@ minify: true, | ||
clicks: true, | ||
links: false, | ||
scroll: true, | ||
location: false, | ||
forms: { | ||
@@ -17,12 +19,8 @@ submit: true, | ||
toggles: true | ||
}, | ||
scroll: true, | ||
location: false | ||
} | ||
}, | ||
logLevel: "info", | ||
server: false, | ||
proxy: false, | ||
ports: { | ||
min: 3000, | ||
max: 4000 | ||
}, | ||
port: 3000, | ||
open: true, | ||
@@ -29,0 +27,0 @@ browser: "default", |
"use strict"; | ||
var fs = require("fs"); | ||
var fs = require("fs"); | ||
var Gaze = require("gaze").Gaze; | ||
var _ = require("lodash"); | ||
var _ = require("lodash"); | ||
@@ -7,0 +7,0 @@ /** |
100
lib/index.js
#! /usr/bin/env node | ||
"use strict"; | ||
var pjson = require("../package.json"); | ||
var BrowserSync = require("./browser-sync"); | ||
var pjson = require("../package.json"); | ||
var defaultConfig = require("./default-config"); | ||
var utils = require("./utils"); | ||
@@ -11,3 +11,2 @@ var cli = require("./cli"); | ||
var info = cli.info; | ||
var options = cli.options; | ||
@@ -17,6 +16,4 @@ var args = require("optimist").argv; | ||
var _ = require("lodash"); | ||
var browserSync = new BrowserSync(); | ||
var browserSync = new BrowserSync(); | ||
/** | ||
@@ -26,2 +23,3 @@ * @param {Array|Null} files | ||
* @param {Function} [cb] | ||
* @returns {BrowserSync} | ||
*/ | ||
@@ -36,3 +34,5 @@ module.exports.start = function (files, config, cb) { | ||
if (require.main === module) { | ||
init.parse(pjson.version, args, argv, function (err, data) { | ||
if (err) { | ||
@@ -45,3 +45,3 @@ utils.fail(err, {}, true); | ||
if (data.configFile) { | ||
info.makeConfig(argv); | ||
info.makeConfig(); | ||
} | ||
@@ -56,84 +56,20 @@ }); | ||
*/ | ||
module.exports.reload = function (arg) { | ||
module.exports.reload = require("./public/reload")(browserSync); | ||
function emitReload(path) { | ||
browserSync.events.emit("file:changed", { | ||
path: path | ||
}); | ||
} | ||
function emitBrowserReload() { | ||
browserSync.events.emit("browser:reload"); | ||
} | ||
if (typeof arg === "string") { | ||
return emitReload(arg); | ||
} | ||
if (Array.isArray(arg)) { | ||
return arg.forEach(emitReload); | ||
} | ||
if (arg && arg.stream === true) { | ||
// Handle Streams here... | ||
var emitted = false; | ||
var once = arg.once || false; | ||
var Transform = require("stream").Transform; | ||
var reload = new Transform({objectMode:true}); | ||
reload._transform = function(file, encoding, next) { | ||
if (once === true && !emitted) { | ||
emitBrowserReload(); | ||
emitted = true; | ||
this.push(file); | ||
return next(); | ||
} else { | ||
if (once === true && emitted) { | ||
return; | ||
} | ||
if (file.path) { | ||
emitted = true; | ||
emitReload(file.path); | ||
} | ||
} | ||
this.push(file); | ||
next(); | ||
}; | ||
return reload; | ||
} | ||
return emitBrowserReload(); | ||
}; | ||
/** | ||
* @param {string} msg | ||
* Exposed helper method for browser notifications | ||
* @param {String} msg | ||
*/ | ||
module.exports.notify = function (msg) { | ||
if (msg) { | ||
browserSync.events.emit("browser:notify", { | ||
message: msg | ||
}); | ||
} | ||
}; | ||
module.exports.notify = require("./public/notify")(browserSync); | ||
/** | ||
* Handle External usage. | ||
* @param {Array} [userFiles] | ||
* @param {Object} [userConfig] | ||
* Handle External API usage. | ||
* @param {Object} [config] | ||
* @param {Function} [cb] | ||
* @returns {exports.EventEmitter} | ||
* @returns {BrowserSync} | ||
*/ | ||
module.exports.init = function (userFiles, userConfig, cb) { | ||
var config = _.merge(defaultConfig, userConfig, function (a, b) { | ||
return _.isArray(a) ? _.union(a, b) : undefined; | ||
}); | ||
var files = options._mergeFilesOption(userFiles, config.exclude); | ||
config = init.mergeOptions(defaultConfig, config, init.allowedOptions); | ||
return exports.start(files, config, cb); | ||
}; | ||
module.exports.init = require("./public/init")(exports.start); | ||
/** | ||
* Allow plugins to be registered/overridden | ||
* @param {String} name | ||
@@ -147,2 +83,6 @@ * @param {Function} func | ||
/** | ||
* Export the emitter | ||
* @type {BrowserSync.events} | ||
*/ | ||
module.exports.emitter = browserSync.events; |
@@ -5,2 +5,3 @@ "use strict"; | ||
var utils = require("./utils").utils; | ||
var log = utils.log; | ||
@@ -14,31 +15,45 @@ var _ = require("lodash"); | ||
module.exports.callbacks = { | ||
"file:watching": function (options, data) { | ||
if (data.watcher._patterns) { | ||
utils.log(messages.files.watching(data.watcher._patterns), options); | ||
log("info", messages.files.watching(data.watcher._patterns), options); | ||
} | ||
}, | ||
"file:reload": function (options, data) { | ||
utils.log(messages.files.changed(utils.resolveRelativeFilePath(data.path, data.cwd)), options); | ||
utils.log(messages.browser[data.type](), options); | ||
log("info", messages.files.changed(utils.resolveRelativeFilePath(data.path, data.cwd)), options); | ||
log("info", messages.browser[data.type](), options); | ||
}, | ||
"client:connected": function (options, data) { | ||
var msg = messages.browser.connection(utils.getUaString(data.ua)); | ||
if (options.logConnections) { | ||
var msg = messages.browser.connection(utils.getUaString(data.ua)); | ||
utils.log(msg, options, false); | ||
log("info", msg, options, false); | ||
} else { | ||
log("debug", msg, options, false); | ||
} | ||
}, | ||
"open": function (options, data) { | ||
"service:running": function (options, data) { | ||
var type = data.type; | ||
var msg; | ||
if (data.tunnel) { | ||
options.urls.tunnel = data.tunnel; | ||
} | ||
if (type === "server") { | ||
msg = messages.initServer(options.host, data.port, data.baseDir); | ||
msg = messages.initServer(options); | ||
} | ||
if (type === "proxy") { | ||
msg = messages.initProxy(options.urls.local, options.urls.remote, options.proxy.target); | ||
msg = messages.initProxy(options, options.proxy.target, data.tunnel); | ||
} | ||
utils.log(msg, options, false); | ||
}, | ||
"snippet": function (options, data) { | ||
var msg = messages.init(data.ports, options); | ||
utils.log(msg, options, false); | ||
if (type === "snippet") { | ||
msg = messages.initSnippet(data.port, options); | ||
} | ||
log("info", msg, options, false); | ||
} | ||
@@ -45,0 +60,0 @@ }; |
@@ -6,15 +6,17 @@ "use strict"; | ||
var path = require("path"); | ||
var config = require("./config"); | ||
var _ = require("lodash"); | ||
var utils = require("./utils").utils; | ||
module.exports = { | ||
/** | ||
* @param {Object} ports | ||
* @param {Object} port | ||
* @param {Object} options | ||
* @returns {String} | ||
*/ | ||
init: function (ports, options) { | ||
initSnippet: function (port, options) { | ||
var template = "{green:Copy the following snippet into your website, just before the closing} </body> {green:tag}\n{:tags:}"; | ||
var params = { | ||
tags: this.scriptTags(ports, options) | ||
tags: this.scriptTags(port, options) | ||
}; | ||
@@ -24,2 +26,11 @@ | ||
}, | ||
tunnel: function (url) { | ||
var templates = [ | ||
"{green:Tunnel running...}", | ||
"{green:You can access it through the following address:}\n", | ||
">>> {magenta:{:url:}}" | ||
]; | ||
return prefixed(templates, {url: url}); | ||
}, | ||
server: { | ||
@@ -36,37 +47,24 @@ /** | ||
/** | ||
* @param {String} host | ||
* @param {String|Number} port | ||
* @param {String} baseDir | ||
* @param {Object} options | ||
* @returns {String} | ||
*/ | ||
initServer: function (host, port, baseDir) { | ||
initServer: function (options) { | ||
var output = ""; | ||
var base = baseDir; | ||
var baseDir = options.server ? options.server.baseDir : undefined; | ||
var templates = [ | ||
"{green:Server running...}", | ||
"{green:You can access it through the following addresses:}\n", | ||
"{green:Local (this machine):}", | ||
">>> {magenta:{:local:}}", | ||
"{green:External (other devices etc):}", | ||
">>> {magenta:{:remote:}}\n" | ||
]; | ||
output += this.getUrls(options.urls); | ||
var params = { | ||
local: this._makeUrl("localhost", port, "http:"), | ||
remote: this._makeUrl(host, port, "http:") | ||
}; | ||
if (baseDir) { | ||
if (Array.isArray(baseDir)) { | ||
_.each(baseDir, addBase); | ||
} else { | ||
addBase(baseDir); | ||
} | ||
} | ||
output += prefixed(templates, params); | ||
var template = "{green:Serving files from:} {magenta:{: baseDir :}}"; | ||
if (Array.isArray(baseDir)) { | ||
baseDir.forEach(function (item, i) { | ||
var prefix = (i ? "\n" : ""); | ||
output += prefix + prefixed(template, {baseDir: item}); | ||
function addBase (value) { | ||
output += prefixed("{green:Serving files from:} {magenta:{: baseDir :}}\n", { | ||
baseDir: value | ||
}); | ||
} else { | ||
output += prefixed(template, {baseDir: baseDir}); | ||
} | ||
@@ -77,31 +75,24 @@ | ||
/** | ||
* @param {String} host | ||
* @param {String|Number} port | ||
* @param {Object} options | ||
* @returns {String} | ||
*/ | ||
initProxy: function (local, external, proxyUrl) { | ||
initProxy: function (options) { | ||
var output = ""; | ||
var output = ""; | ||
var target = options.proxy.target; | ||
var templates = [ | ||
"{green:Proxying:} {:proxy:}", | ||
"{green:Now you can access your site through the following addresses:}\n", | ||
"{green:Local (this machine):}", | ||
">>> {magenta:{:local:}}", | ||
"{green:External (other devices etc):}", | ||
">>> {magenta:{:remote:}}\n" | ||
"{green:Now you can access your site through the following addresses:}\n" | ||
]; | ||
var params = { | ||
proxy: proxyUrl, | ||
local: local, | ||
remote: external | ||
}; | ||
output += prefixed(templates, {proxy: target}); | ||
output += prefixed(templates, params); | ||
output += this.getUrls(options.urls); | ||
return output; | ||
}, | ||
plugin: { | ||
error: function (name) { | ||
error: function () { | ||
return "Your plugin must be a function"; | ||
@@ -128,4 +119,3 @@ } | ||
/** | ||
* @param {String} hostIp | ||
* @param {Object} ports | ||
* @param {number} port | ||
* @param {Object} options | ||
@@ -135,20 +125,18 @@ * @param {String} [env] | ||
*/ | ||
scriptTags: function (ports, options, env) { | ||
scriptTags: function (port, options, env) { | ||
var template = [ | ||
"\n<script type='text/javascript'>//<![CDATA[\n;", | ||
"document.write(\"<script defer src='//HOST:{:socket:}/socket.io/socket.io.js'><\\/script>", | ||
"<script defer src='//HOST:{:custom:}'><\\/script>", | ||
"\".replace(/HOST/g, location.hostname));", | ||
"document.write(\"<script async src='{:custom:}'><\\/script>\".replace(/HOST/g, location.hostname));", | ||
"\n//]]></script>" | ||
]; | ||
if (env === "controlPanel") { | ||
template.splice(2, 1); | ||
var script = "//HOST:" + port + this.clientScript(options); | ||
if (options.tunnel) { | ||
script = this.clientScript(options); | ||
} | ||
var params = { | ||
socket: ports.socket, | ||
custom: ports.controlPanel + this.clientScript(options), | ||
connector: this.socketConnector(ports.socket) | ||
custom: script | ||
}; | ||
@@ -202,3 +190,3 @@ | ||
var template1 = "Config file created ({cyan:{:path:}})"; | ||
var template2 = "To use it, in the same directory run: {green:browser-sync}"; | ||
var template2 = "To use it, in the same directory run: {green:browser-sync start --config bs-config.js}"; | ||
@@ -280,8 +268,13 @@ var params = { | ||
/** | ||
* @param {String|Number} port | ||
* @param {number} port | ||
* @param {Object} options | ||
* @returns {String} | ||
*/ | ||
socketConnector: function (port) { | ||
var string = "var ___socket___ = io.connect('http://' + location.hostname + ':' + '{:port:}');"; | ||
socketConnector: function (port, options) { | ||
var string = "var ___socket___ = io.connect(location.hostname + ':{:port:}');"; | ||
var tunnel = "var ___socket___ = io.connect(location.hostname);"; | ||
var template = options.tunnel ? | ||
tunnel : string; | ||
var params = { | ||
@@ -291,3 +284,3 @@ port: port | ||
return compile(string, params); | ||
return compile(template, params); | ||
}, | ||
@@ -300,4 +293,4 @@ /** | ||
var script = "/client/browser-sync-client.js"; | ||
var template = "/client/browser-sync-client.{:version:}.js"; | ||
var script = "/browser-sync-client.js"; | ||
var template = "/browser-sync-client.{:version:}.js"; | ||
@@ -322,3 +315,25 @@ if (!options || !options.version) { | ||
return compiled; | ||
}, | ||
getUrls: function (urls) { | ||
var output = ""; | ||
_.each(urls, function (value, key) { | ||
output += prefixed("{green:{:name:}:} >>> {magenta:{:url:}}\n", { | ||
name: utils.ucfirst(key), | ||
url: value | ||
}); | ||
}); | ||
return output; | ||
}, | ||
tunnelFail: function (err) { | ||
return prefixed(["The following is a Tunnel error:", this.getErr(err)]); | ||
}, | ||
configError: function (msg) { | ||
return prefixed("{red:CONFIG ERROR: %s }".replace("%s", msg)); | ||
}, | ||
getErr: function (msg) { | ||
return "{red:%s }".replace("%s", msg); | ||
}, | ||
getDebug: function (msg) { | ||
return prefixed("{cyan:DEBUG: %s }".replace("%s", msg)); | ||
} | ||
}; |
"use strict"; | ||
var proxyModule = require("./proxy"); | ||
var messages = require("./messages"); | ||
@@ -10,2 +9,3 @@ var snippetUtils = require("./snippet").utils; | ||
var filePath = require("path"); | ||
var foxy = require("foxy"); | ||
@@ -111,3 +111,5 @@ var utils = { | ||
} else { | ||
app.use(connect.static(filePath.resolve(base), { index: index })); | ||
if ("string" === typeof base) { | ||
app.use(connect.static(filePath.resolve(base), { index: index })); | ||
} | ||
} | ||
@@ -120,3 +122,6 @@ }, | ||
addDirectory: function (app, base) { | ||
app.use(connect.directory(base, {icons:true})); | ||
if (Array.isArray(base)) { | ||
base = base[0]; | ||
} | ||
app.use(connect.directory(filePath.resolve(base), {icons:true})); | ||
} | ||
@@ -129,30 +134,48 @@ }; | ||
* @param {String} host | ||
* @param {{socket: (Number), controlPanel: (Number)}} ports | ||
* @param {Number} port | ||
* @param {Object} options | ||
* @param {socket} io | ||
* @param {string|} scripts | ||
* @returns {{staticServer: (http.Server), proxyServer: (http.Server)}|Boolean} | ||
*/ | ||
module.exports.launchServer = function (host, ports, options, io) { | ||
module.exports.launchServer = function (host, port, options, scripts) { | ||
var app; | ||
var proxy = options.proxy || false; | ||
var server = options.server || false; | ||
var snippet = false; | ||
if (!proxy && !server) { | ||
snippet = true; | ||
} | ||
var scriptTags = options.snippet = messages.scriptTags(port, options); | ||
var scriptPaths = messages.clientScript(options, true); | ||
var scriptPath = options.scriptPath = scriptPaths.versioned; | ||
var staticServer; | ||
var proxyServer; | ||
var navCallback = utils.navigateCallback(io, options); | ||
var scriptTags = options.snippet = messages.scriptTags(ports, options); | ||
var app; | ||
if (proxy) { | ||
proxyServer = proxyModule.createProxy(host, ports, options, navCallback); | ||
proxyServer = foxy.init( | ||
options.proxy, | ||
{ | ||
host: host, | ||
port: port | ||
}, | ||
snippetUtils.getRegex(scriptTags), | ||
snippetUtils.getProxyMiddleware(scripts, scriptPath) | ||
); | ||
} | ||
if (server) { | ||
if (server || snippet) { | ||
var baseDir = server.baseDir; | ||
var index = server.index || "index.html"; | ||
var directory = server.directory; | ||
var baseDir, index, directory; | ||
if (server) { | ||
baseDir = server.baseDir; | ||
index = server.index || "index.html"; | ||
directory = server.directory; | ||
} | ||
app = connect(); | ||
if (server.middleware) { | ||
if (server && server.middleware) { | ||
utils.addMiddleware(app, server.middleware); | ||
@@ -162,13 +185,18 @@ } | ||
app.use(function (req, res, next) { | ||
req = snippetUtils.isOldIe(req); | ||
snippetUtils.isOldIe(req); | ||
return next(); | ||
}) | ||
.use(navCallback) | ||
.use(snippetUtils.getSnippetMiddleware(scriptTags)); | ||
.use(scriptPath, scripts) | ||
.use(scriptPaths.path, scripts); | ||
utils.addBaseDir(app, baseDir, index); | ||
if (server) { | ||
if (directory) { | ||
utils.addDirectory(app, baseDir); | ||
if (directory) { | ||
utils.addDirectory(app, baseDir); | ||
} | ||
app.use(snippetUtils.getSnippetMiddleware(scriptTags)); | ||
utils.addBaseDir(app, baseDir, index); | ||
} | ||
@@ -175,0 +203,0 @@ |
"use strict"; | ||
var controlPanel = require("./control-panel"); | ||
var messages = require("./messages"); | ||
var api = require("./api"); | ||
var utils = require("./utils").utils; | ||
var utils = require("./utils").utils; | ||
var snippetUtils = require("./snippet").utils; | ||
@@ -17,8 +15,7 @@ /** | ||
*/ | ||
return function (ports, files, options) { | ||
return function (port, files, options) { | ||
var servers; | ||
this.options = options; | ||
this.options.port = port; | ||
this.io = this.getPlugin("socket")(ports.socket, this.clientEvents, options, this.events); | ||
// register internal events | ||
@@ -28,3 +25,3 @@ this.registerInternalEvents(options); | ||
// Set global URL options | ||
utils.setUrlOptions(ports, options); | ||
options.urls = utils.setUrlOptions(port, options); | ||
@@ -34,29 +31,16 @@ // Start file watcher | ||
// launch the server/proxy | ||
servers = this.initServer(options.host, ports, options, this.io); | ||
// Get the Client JS | ||
var clientJs = snippetUtils.getClientJs(port, options); | ||
if (!servers) { | ||
this.events.emit("snippet", {ports: ports}); | ||
} | ||
// Start the server | ||
var servers = this.servers = this.initServer( | ||
options.host, | ||
port, | ||
options, | ||
this.getPlugin("client:script")(options, clientJs, options.proxy ? "file" : "middleware") | ||
); | ||
// Always Launch the control panel (which contains client script); | ||
var snippet = messages.scriptTags(ports, options, "controlPanel"); | ||
var connector = messages.socketConnector(ports.socket); | ||
// Start the socket, needs an existing server. | ||
this.io = this.getPlugin("socket")(servers.staticServer || servers.proxyServer, this); | ||
var cpPlugin = this.getPlugin("controlpanel"); | ||
var cp; | ||
if (cpPlugin) { | ||
cp = cpPlugin(options, snippet, connector, this); | ||
} | ||
controlPanel | ||
.launchControlPanel(options, this.getPlugin("client:script")(options, connector), cp) | ||
.listen(ports.controlPanel); | ||
this.options = options; | ||
// get/emit the api | ||
this.api = api.getApi(ports, options, servers); | ||
this.events.emit("init", this); | ||
@@ -63,0 +47,0 @@ |
"use strict"; | ||
var messages = require("./messages"); | ||
var lrSnippet = require("resp-modifier"); | ||
var path = require("path"); | ||
var _ = require("lodash"); | ||
var fs = require("fs"); | ||
/** | ||
* Utils for snippet injection | ||
* @type {{excludeList: string[], bodyExists: bodyExists, isExcluded: isExcluded}} | ||
*/ | ||
@@ -41,3 +43,3 @@ var utils = { | ||
/** | ||
* @param {string} snippet | ||
* @param {String} snippet | ||
* @returns {{match: RegExp, fn: Function}} | ||
@@ -64,5 +66,22 @@ */ | ||
return lrSnippet({rules:rules}); | ||
return lrSnippet({rules: rules}); | ||
}, | ||
/** | ||
* @param {String} scripts - the clientside JS | ||
* @param {String} scriptPath - the URL to match | ||
* @returns {Function} | ||
*/ | ||
getProxyMiddleware: function (scripts, scriptPath) { | ||
return function (req, res, next) { | ||
if (req.url.indexOf(scriptPath) > -1) { | ||
res.writeHead(200, { "Content-Type": "text/javascript" }); | ||
res.write(scripts); | ||
res.end(); | ||
return next(true); | ||
} else { | ||
return next(false); | ||
} | ||
}; | ||
}, | ||
/** | ||
* @param {Object} req | ||
@@ -83,4 +102,15 @@ * @param {Array} [excludeList] | ||
return req; | ||
}, | ||
/** | ||
* @param {number} port | ||
* @param {BrowserSync.options} options | ||
* @returns {String} | ||
*/ | ||
getClientJs: function (port, options) { | ||
var js = fs.readFileSync(path.resolve(__dirname + "/public/socket.io.js"), "utf-8") + ";"; | ||
return js += messages.socketConnector(port, options); | ||
} | ||
}; | ||
module.exports.utils = utils; |
"use strict"; | ||
var socket = require("socket.io"); | ||
var socket = require("socket.io"); | ||
var Steward = require("./steward"); | ||
@@ -10,34 +11,36 @@ /** | ||
module.exports.plugin = function () { | ||
return function (port, events, options, emitter) { | ||
return exports.init(port, events, options, emitter); | ||
return function (server, bs) { | ||
return exports.init(server, bs); | ||
}; | ||
}; | ||
/** | ||
* @param client | ||
* @param event | ||
*/ | ||
module.exports.clientEvent = function (client, event) { | ||
client.on(event, function (data) { | ||
client.broadcast.emit(event, data); | ||
}); | ||
}; | ||
/** | ||
* @param {Array} events | ||
* @param {Object} options | ||
* @param {Socket} io | ||
* @param {EventEmitter} emitter | ||
* @param {http.Server} server | ||
* @param {BrowserSync} bs | ||
*/ | ||
module.exports.socketConnection = function (events, options, io, emitter) { | ||
module.exports.init = function (server, bs) { | ||
var ua; | ||
var events = bs.clientEvents; | ||
var options = bs.options; | ||
var emitter = bs.events; | ||
io.sockets.on("connection", function (client) { | ||
var io = socket.listen(server, {log: false}); | ||
var steward = new Steward(emitter); | ||
/** | ||
* Listen for new connections | ||
*/ | ||
io.sockets.on("connection", handleConnection); | ||
/** | ||
* Handle each new connection | ||
* @param {Object} client | ||
*/ | ||
function handleConnection (client) { | ||
// set ghostmode callbacks | ||
if (options.ghostMode) { | ||
events.forEach(function (evt) { | ||
exports.clientEvent(client, evt); | ||
}); | ||
addGhostMode(client); | ||
} | ||
@@ -47,26 +50,35 @@ | ||
ua = client.handshake.headers["user-agent"]; | ||
emitter.emit("client:connected", { | ||
ua: client.handshake.headers["user-agent"] | ||
}); | ||
} | ||
emitter.emit("client:connected", {ua: ua}); | ||
}); | ||
}; | ||
/** | ||
* @param {string} event | ||
* @param {Socket.client} client | ||
* @param {Object} data | ||
*/ | ||
function handleClientEvent(event, client, data) { | ||
/** | ||
* @param {Number} port | ||
* @param {Array} events | ||
* @param {Object} options | ||
* @param {EventEmitter} emitter | ||
* @returns {http.Server} | ||
*/ | ||
module.exports.init = function (port, events, options, emitter) { | ||
var io = socket.listen(port, {log: false}); | ||
io.set("log level", 0); | ||
if (options.minify) { | ||
io.set("browser client minification", true); | ||
if (process.platform !== "win32") { | ||
io.set("browser client gzip", true); | ||
if (steward.valid(client.id)) { | ||
client.broadcast.emit(event, data); | ||
} | ||
} | ||
exports.socketConnection(events, options, io, emitter); | ||
/** | ||
* @param client | ||
*/ | ||
function addGhostMode (client) { | ||
events.forEach(addEvent); | ||
function addEvent(event) { | ||
client.on(event, handleClientEvent.bind(null, event, client)); | ||
} | ||
} | ||
return io; | ||
}; |
153
lib/utils.js
"use strict"; | ||
var devIp = require("dev-ip"); | ||
@@ -9,2 +10,3 @@ var open = require("opn"); | ||
var UAParser = require("ua-parser-js"); | ||
var parser = new UAParser(); | ||
@@ -15,15 +17,14 @@ | ||
* @param {Object} options | ||
* @returns {String} - the IP address | ||
* @returns {String|boolean} - the IP address | ||
*/ | ||
getHostIp: function (options) { | ||
var fallback = "0.0.0.0"; | ||
var returnValue = devIp.getIp(null); | ||
if (options) { | ||
if (options.host) { | ||
if (options.host && options.host !== "localhost") { | ||
return options.host; | ||
} | ||
if (options.detect === false || !devIp) { | ||
return fallback; | ||
return false; | ||
} | ||
@@ -36,8 +37,8 @@ } | ||
return returnValue || fallback; | ||
return returnValue || false; | ||
}, | ||
/** | ||
* Take the path provided in options & transform into CWD for serving files | ||
* @param {string} [baseDir] | ||
* @returns {string} | ||
* @param {String} [baseDir] | ||
* @returns {String} | ||
*/ | ||
@@ -72,6 +73,13 @@ getBaseDir: function (baseDir) { | ||
*/ | ||
setUrlOptions: function (ports, opts) { | ||
setUrlOptions: function (port, opts) { | ||
var port = ports.server || ports.proxy; | ||
var urls = {}; | ||
if (!opts.online) { | ||
urls.local = "http://localhost:" + port; | ||
return urls; | ||
} | ||
var external = utils.xip(utils.getHostIp(opts), opts); | ||
var localhost = "localhost"; | ||
@@ -87,11 +95,9 @@ | ||
if (port) { | ||
opts.urls = utils.getUrls(external, local, port, opts); | ||
} | ||
return utils.getUrls(external, local, port, opts); | ||
}, | ||
/** | ||
* Append a start path if given in options | ||
* @param {string} url | ||
* @param {object} options | ||
* @returns {string} | ||
* @param {String} url | ||
* @param {Object} options | ||
* @returns {String} | ||
*/ | ||
@@ -117,13 +123,19 @@ getUrl: function (url, options) { | ||
/** | ||
* @param {string} external | ||
* @param {String} external | ||
* @param {number|string} port | ||
* @param {object} options | ||
* @param {string} local | ||
* @returns {{local: string, remote: string}} | ||
* @param {Object} options | ||
* @param {String} local | ||
* @returns {{local: string, external: string}} | ||
*/ | ||
getUrls: function (external, local, port, options) { | ||
return { | ||
local: utils.getUrl(utils._makeUrl(local, port), options), | ||
remote: utils.getUrl(utils._makeUrl(external, port), options) | ||
var urls = { | ||
local: utils.getUrl(utils._makeUrl(local, port), options) | ||
}; | ||
if (external !== local) { | ||
urls.external = utils.getUrl(utils._makeUrl(external, port), options); | ||
} | ||
return urls; | ||
}, | ||
@@ -133,3 +145,3 @@ /** | ||
* @param {Number} port | ||
* @returns {string} | ||
* @returns {String} | ||
* @private | ||
@@ -142,23 +154,17 @@ */ | ||
* Get ports | ||
* @param {object} options | ||
* @param {number} minCount | ||
* @param {Object} options | ||
* @returns {Q.promise} | ||
*/ | ||
getPorts: function (options, minCount) { | ||
getPorts: function (options) { | ||
var minPorts = (options.server || options.proxy) ? 3 : minCount; | ||
var minPortRange = options.ports && options.ports.min; | ||
var maxPortRange = options.ports && options.ports.max; | ||
var port = options.port; | ||
var ports = options.ports; // backwards compatibility | ||
var max; | ||
var names = ["socket", "controlPanel"]; | ||
if (options.server) { | ||
names.push("server"); | ||
if (ports) { | ||
port = ports.min; | ||
max = ports.max; | ||
} | ||
if (options.proxy) { | ||
names.push("proxy"); | ||
} | ||
return portScanner.getPorts(minPorts, minPortRange, maxPortRange, names); | ||
return portScanner.getPorts(1, port, max); | ||
}, | ||
@@ -173,5 +179,5 @@ /** | ||
/** | ||
* @param {string} filepath | ||
* @param {string} cwd | ||
* @returns {string} | ||
* @param {String} filepath | ||
* @param {String} cwd | ||
* @returns {String} | ||
*/ | ||
@@ -182,4 +188,4 @@ resolveRelativeFilePath: function (filepath, cwd) { | ||
/** | ||
* @param {string} path | ||
* @returns {string} | ||
* @param {String} path | ||
* @returns {String} | ||
*/ | ||
@@ -191,4 +197,4 @@ getFileExtension: function (path) { | ||
* Open the page in browser | ||
* @param {string} url | ||
* @param {object} options | ||
* @param {String} url | ||
* @param {Object} options | ||
*/ | ||
@@ -216,20 +222,60 @@ openBrowser: function (url, options) { | ||
* Log a message to the console | ||
* @param {string} msg | ||
* @param {object} options | ||
* @param {boolean} override | ||
* @param {String} level | ||
* @param {String} msg | ||
* @param {Object} options | ||
* @returns {boolean} | ||
*/ | ||
log: function (msg, options, override) { | ||
if (!options.debugInfo && !override) { | ||
log: function (level, msg, options) { | ||
var msgs = require("./messages"); | ||
/** Backwards compat **/ | ||
if (options && (options.logLevel === "silent" || options.debugInfo === false)) { | ||
return false; | ||
} | ||
return console.log(msg); | ||
if (options.logLevel === "debug") { | ||
if (level === "debug") { | ||
console.log(msgs.getDebug(msg)); | ||
} else { | ||
console.log(msg); | ||
} | ||
} else { | ||
if (level === "info") { | ||
return console.log(msg); | ||
} | ||
} | ||
}, | ||
/** | ||
* @param {Object} options | ||
* @returns {Function} | ||
*/ | ||
getDebugger: function (options) { | ||
return function (msg, vars) { | ||
utils.log("debug", msg.replace("%s", vars), options); | ||
}; | ||
}, | ||
/** | ||
* @param {String} msg | ||
* @param {*} vars | ||
* @param {Object} options | ||
*/ | ||
debug: function (msg, vars, options) { | ||
utils.log("debug", msg.replace("%s", vars), options); | ||
}, | ||
/** | ||
* @param {String} msg | ||
* @param {*} vars | ||
* @param {Object} options | ||
*/ | ||
warn: function (msg, vars, options) { | ||
utils.log("warn", msg.replace("%s", vars), options); | ||
}, | ||
/** | ||
* @param {String} msg | ||
* @param {Object} options | ||
* @param {Boolean} kill | ||
*/ | ||
fail: function (msg, options, kill) { | ||
this.log(msg, options, false); | ||
this.log("info", msg, options); | ||
if (kill) { | ||
@@ -253,2 +299,5 @@ process.exit(1); | ||
return host; | ||
}, | ||
ucfirst: function (string) { | ||
return string.charAt(0).toUpperCase() + string.slice(1); | ||
} | ||
@@ -255,0 +304,0 @@ }; |
{ | ||
"name": "browser-sync", | ||
"description": "Live CSS Reload & Browser Syncing", | ||
"version": "0.9.1", | ||
"version": "1.0.0", | ||
"homepage": "https://github.com/shakyshane/browser-sync", | ||
@@ -31,6 +31,4 @@ "author": { | ||
"portscanner-plus": "0.1.0", | ||
"path": "~0.4.9", | ||
"url": "~0.7.9", | ||
"lodash": "~2.2.1", | ||
"socket.io": "~0.8.0", | ||
"socket.io": "1.0.4", | ||
"connect": "~2.13.0", | ||
@@ -44,10 +42,13 @@ "ua-parser-js": "~0.6.2", | ||
"resp-modifier": "0.0.4", | ||
"browser-sync-client": "^0.1.7", | ||
"browser-sync-client": "0.2.1", | ||
"commander": "~2.1.0", | ||
"browser-sync-control-panel": "0.0.5", | ||
"opn": "^0.1.1" | ||
"opn": "^0.1.1", | ||
"foxy": "0.1.2", | ||
"localtunnel": "^1.3.0", | ||
"opt-merger": "^0.1.2" | ||
}, | ||
"devDependencies": { | ||
"optimist": "~0.6.0", | ||
"socket.io-client": "~0.9.16", | ||
"socket.io-client": "1.0.4", | ||
"cli-color": "~0.2.3", | ||
@@ -54,0 +55,0 @@ "chai": "~1.8.1", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 8 instances in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
2648
4
347959
18
59
6
+ Addedfoxy@0.1.2
+ Addedlocaltunnel@^1.3.0
+ Addedopt-merger@^0.1.2
+ Addedafter@0.8.1(transitive)
+ Addedansi-regex@2.1.1(transitive)
+ Addedarraybuffer.slice@0.0.6(transitive)
+ Addedaxios@0.19.0(transitive)
+ Addedbase64-arraybuffer@0.1.2(transitive)
+ Addedbase64id@0.1.0(transitive)
+ Addedbetter-assert@1.0.2(transitive)
+ Addedblob@0.0.2(transitive)
+ Addedbrowser-sync-client@0.2.1(transitive)
+ Addedcallsite@1.0.0(transitive)
+ Addedcamelcase@3.0.0(transitive)
+ Addedcliui@3.2.0(transitive)
+ Addedcode-point-at@1.1.0(transitive)
+ Addedcommander@0.6.1(transitive)
+ Addeddebug@0.6.00.7.44.1.1(transitive)
+ Addeddecamelize@1.2.0(transitive)
+ Addedengine.io@1.2.2(transitive)
+ Addedengine.io-client@1.2.2(transitive)
+ Addedengine.io-parser@1.0.6(transitive)
+ Addederror-ex@1.3.2(transitive)
+ Addedfind-up@1.1.2(transitive)
+ Addedfollow-redirects@1.5.10(transitive)
+ Addedfoxy@0.1.2(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedget-caller-file@1.0.3(transitive)
+ Addedgraceful-fs@4.2.11(transitive)
+ Addedhas-binary-data@0.1.1(transitive)
+ Addedhas-cors@1.0.3(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedhosted-git-info@2.8.9(transitive)
+ Addedhttp-proxy@1.1.4(transitive)
+ Addedindexof@0.0.1(transitive)
+ Addedinherits@2.0.1(transitive)
+ Addedinvert-kv@1.0.0(transitive)
+ Addedis-arrayish@0.2.1(transitive)
+ Addedis-buffer@2.0.5(transitive)
+ Addedis-core-module@2.15.1(transitive)
+ Addedis-fullwidth-code-point@1.0.0(transitive)
+ Addedis-utf8@0.2.1(transitive)
+ Addedjson3@3.2.6(transitive)
+ Addedlcid@1.0.0(transitive)
+ Addedload-json-file@1.1.0(transitive)
+ Addedlocaltunnel@1.9.2(transitive)
+ Addedms@2.1.3(transitive)
+ Addednan@0.3.2(transitive)
+ Addednormalize-package-data@2.5.0(transitive)
+ Addednumber-is-nan@1.0.1(transitive)
+ Addedobject-component@0.0.3(transitive)
+ Addedopenurl@1.1.1(transitive)
+ Addedopt-merger@0.1.3(transitive)
+ Addedoptions@0.0.6(transitive)
+ Addedos-locale@1.4.0(transitive)
+ Addedparse-json@2.2.0(transitive)
+ Addedparsejson@0.0.1(transitive)
+ Addedparseqs@0.0.2(transitive)
+ Addedparseuri@0.0.2(transitive)
+ Addedpath-exists@2.1.0(transitive)
+ Addedpath-parse@1.0.7(transitive)
+ Addedpath-type@1.1.0(transitive)
+ Addedpify@2.3.0(transitive)
+ Addedpinkie@2.0.4(transitive)
+ Addedpinkie-promise@2.0.1(transitive)
+ Addedread-pkg@1.1.0(transitive)
+ Addedread-pkg-up@1.0.1(transitive)
+ Addedrequire-directory@2.1.1(transitive)
+ Addedrequire-main-filename@1.0.1(transitive)
+ Addedresolve@1.22.8(transitive)
+ Addedresp-modifier@0.0.5(transitive)
+ Addedsemver@5.7.2(transitive)
+ Addedset-blocking@2.0.0(transitive)
+ Addedsocket.io@1.0.4(transitive)
+ Addedsocket.io-adapter@0.2.0(transitive)
+ Addedsocket.io-client@1.0.4(transitive)
+ Addedsocket.io-parser@2.1.22.2.0(transitive)
+ Addedspdx-correct@3.2.0(transitive)
+ Addedspdx-exceptions@2.5.0(transitive)
+ Addedspdx-expression-parse@3.0.1(transitive)
+ Addedspdx-license-ids@3.0.20(transitive)
+ Addedstring-width@1.0.2(transitive)
+ Addedstrip-ansi@3.0.1(transitive)
+ Addedstrip-bom@2.0.0(transitive)
+ Addedsupports-preserve-symlinks-flag@1.0.0(transitive)
+ Addedtinycolor@0.0.1(transitive)
+ Addedto-array@0.1.3(transitive)
+ Addedutf8@2.0.0(transitive)
+ Addedvalidate-npm-package-license@3.0.4(transitive)
+ Addedwhich-module@1.0.0(transitive)
+ Addedwrap-ansi@2.1.0(transitive)
+ Addedws@0.4.31(transitive)
+ Addedy18n@3.2.2(transitive)
+ Addedyargs@6.6.0(transitive)
+ Addedyargs-parser@4.2.1(transitive)
- Removedpath@~0.4.9
- Removedurl@~0.7.9
- Removedbrowser-sync-client@0.1.9(transitive)
- Removedpath@0.4.10(transitive)
- Removedpolicyfile@0.0.4(transitive)
- Removedpunycode@1.0.0(transitive)
- Removedquerystring@0.1.0(transitive)
- Removedredis@0.6.7(transitive)
- Removedsocket.io@0.8.7(transitive)
- Removedsocket.io-client@0.8.7(transitive)
- Removeduglify-js@1.0.6(transitive)
- Removedurl@0.7.9(transitive)
- Removedwebsocket-client@1.0.0(transitive)
- Removedxmlhttprequest@1.2.2(transitive)
Updatedbrowser-sync-client@0.2.1
Updatedsocket.io@1.0.4