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.
348 lines
10 KiB
348 lines
10 KiB
#! /usr/bin/env node |
|
"use strict"; |
|
/** |
|
* @module BrowserSync |
|
*/ |
|
var pjson = require("../package.json"); |
|
var BrowserSync = require("./browser-sync"); |
|
var publicUtils = require("./public/public-utils"); |
|
var events = require("events"); |
|
var PassThrough = require("stream").PassThrough; |
|
var logger = require("eazy-logger").Logger({ |
|
useLevelPrefixes: true |
|
}); |
|
var singleton = false; |
|
var singletonPlugins = []; |
|
var instances = []; |
|
/** |
|
* @type {boolean|EventEmitter} |
|
*/ |
|
var singletonEmitter = false; |
|
module.exports = initSingleton; |
|
/** |
|
* Create a Browsersync instance |
|
* @method create |
|
* @param {String} name an identifier that can used for retrieval later |
|
*/ |
|
/** |
|
* Get a single instance by name. This is useful if you have your |
|
* build scripts in separate files |
|
* @method get |
|
* @param {String} name |
|
* @returns {Object|Boolean} |
|
*/ |
|
module.exports.get = function (name) { |
|
var instance = getSingle(name); |
|
if (instance) { |
|
return instance; |
|
} |
|
throw new Error("An instance with the name `%s` was not found.".replace("%s", name)); |
|
}; |
|
/** |
|
* Check if an instance has been created. |
|
* @method has |
|
* @param {String} name |
|
* @returns {Boolean} |
|
*/ |
|
module.exports.has = function (name) { |
|
var instance = getSingle(name); |
|
if (instance) { |
|
return true; |
|
} |
|
return false; |
|
}; |
|
/** |
|
* Start the Browsersync service. This will launch a server, proxy or start the snippet |
|
* mode depending on your use-case. |
|
* @method init |
|
* @param {Object} [config] This is the main configuration for your Browsersync instance and can contain any of the [available options]({{site.links.options}}) |
|
* If you do not pass a config an argument for configuration, Browsersync will still run; but it will be in the `snippet` mode |
|
* @param {Function} [cb] If you pass a callback function, it will be called when Browsersync has completed all setup tasks and is ready to use. This |
|
* is useful when you need to wait for information (for example: urls, port etc) or perform other tasks synchronously. |
|
* @returns {BrowserSync} |
|
*/ |
|
module.exports.init = initSingleton; |
|
/** |
|
* Register a plugin. Must implement at least a 'plugin' method that returns a |
|
* callable function. |
|
* |
|
* @method use |
|
* @param {String} name The name of the plugin |
|
* @param {Object} module The object to be `required`. |
|
* @param {Function} [cb] A callback function that will return any errors. |
|
*/ |
|
module.exports.use = function () { |
|
var args = Array.prototype.slice.call(arguments); |
|
singletonPlugins.push({ |
|
args: args |
|
}); |
|
}; |
|
/** |
|
* The `reload` method will inform all browsers about changed files and will either cause the browser to refresh, or inject the files where possible. |
|
* |
|
* @method reload |
|
* @param {String|Array|Object} [arg] The file or files to be reloaded. |
|
* @returns {*} |
|
*/ |
|
module.exports.reload = noop("reload"); |
|
/** |
|
* The `stream` method returns a transform stream and can act once or on many files. |
|
* |
|
* @method stream |
|
* @param {Object} [opts] Configuration for the stream method |
|
* @param {Object} [opts.match] Resulting files to reload. The path is from the |
|
* root of the site (not the root of your project). You can use '**' to recurse |
|
* directories. |
|
* @param {Object} [opts.once] Only reload on the first changed file in the stream. |
|
* @since 2.6.0 |
|
* @returns {*} |
|
*/ |
|
module.exports.stream = noop("stream"); |
|
/** |
|
* Helper method for browser notifications |
|
* |
|
* @method notify |
|
* @param {String|HTML} msg Can be a simple message such as 'Connected' or HTML |
|
* @param {Number} [timeout] How long the message will remain in the browser. @since 1.3.0 |
|
*/ |
|
module.exports.notify = noop("notify"); |
|
/** |
|
* This method will close any running server, stop file watching & exit the current process. |
|
* |
|
* @method exit |
|
*/ |
|
module.exports.exit = noop("exit"); |
|
/** |
|
* Stand alone file-watcher. Use this along with Browsersync to create your own, minimal build system |
|
* @method watch |
|
* @param {string} patterns Glob patterns for files to watch |
|
* @param {object} [opts] Options to be passed to Chokidar - check what's available in [their docs](https://github.com/paulmillr/chokidar#getting-started) |
|
* @param {function} [fn] Callback function for each event. |
|
* @since 2.6.0 |
|
*/ |
|
module.exports.watch = noop("watch"); |
|
/** |
|
* Method to pause file change events |
|
* |
|
* @method pause |
|
*/ |
|
module.exports.pause = noop("pause"); |
|
/** |
|
* Method to resume paused watchers |
|
* |
|
* @method resume |
|
*/ |
|
module.exports.resume = noop("resume"); |
|
/** |
|
* Add properties fo |
|
*/ |
|
Object.defineProperties(module.exports, { |
|
/** |
|
* The internal Event Emitter used by the running Browsersync instance (if there is one). |
|
* You can use this to emit your own events, such as changed files, logging etc. |
|
* |
|
* @property emitter |
|
*/ |
|
emitter: { |
|
get: function () { |
|
if (!singletonEmitter) { |
|
singletonEmitter = newEmitter(); |
|
return singletonEmitter; |
|
} |
|
return singletonEmitter; |
|
} |
|
}, |
|
/** |
|
* A simple true/false flag that you can use to determine if there's a currently-running Browsersync instance. |
|
* |
|
* @property active |
|
*/ |
|
active: { |
|
get: getSingletonValue.bind(null, "active") |
|
}, |
|
/** |
|
* A simple true/false flag to determine if the current instance is paused |
|
* |
|
* @property paused |
|
*/ |
|
paused: { |
|
get: getSingletonValue.bind(null, "paused") |
|
} |
|
}); |
|
/** |
|
* Event emitter factory |
|
* @returns {EventEmitter} |
|
*/ |
|
function newEmitter() { |
|
var emitter = new events.EventEmitter(); |
|
emitter.setMaxListeners(20); |
|
return emitter; |
|
} |
|
/** |
|
* Get the singleton's emitter, or a new one. |
|
* @returns {EventEmitter} |
|
*/ |
|
function getSingletonEmitter() { |
|
if (singletonEmitter) { |
|
return singletonEmitter; |
|
} |
|
singletonEmitter = newEmitter(); |
|
return singletonEmitter; |
|
} |
|
/** |
|
* Helper to allow methods to be called on the module export |
|
* before there's a running instance |
|
* @param {String} name |
|
* @returns {Function} |
|
*/ |
|
function noop(name) { |
|
return function () { |
|
var args = Array.prototype.slice.call(arguments); |
|
if (singleton) { |
|
return singleton[name].apply(singleton, args); |
|
} |
|
else { |
|
if (publicUtils.isStreamArg(name, args)) { |
|
return new PassThrough({ objectMode: true }); |
|
} |
|
} |
|
}; |
|
} |
|
/** |
|
* Create a single instance when module export is used directly via browserSync({}); |
|
* This is mostly for back-compatibility, for also for the nicer api. |
|
* This will never be removed to ensure we never break user-land, but |
|
* we should discourage it's use. |
|
* @returns {*} |
|
*/ |
|
function initSingleton() { |
|
var instance; |
|
if (instances.length) { |
|
instance = instances.filter(function (item) { |
|
return item.name === "singleton"; |
|
}); |
|
if (instance.length) { |
|
logger.error("{yellow:You tried to start Browsersync twice!} To create multiple instances, use {cyan:browserSync.create().init()"); |
|
return instance; |
|
} |
|
} |
|
var args = Array.prototype.slice.call(arguments); |
|
singleton = create("singleton", getSingletonEmitter()); |
|
if (singletonPlugins.length) { |
|
singletonPlugins.forEach(function (obj) { |
|
singleton.instance.registerPlugin.apply(singleton.instance, obj.args); |
|
}); |
|
} |
|
singleton.init.apply(null, args); |
|
return singleton; |
|
} |
|
/** |
|
* @param {String} prop |
|
* @returns {Object|Boolean} |
|
*/ |
|
function getSingletonValue(prop) { |
|
var single = getSingle("singleton"); |
|
if (single) { |
|
return single[prop]; |
|
} |
|
return false; |
|
} |
|
/** |
|
* Get a single instance by name |
|
* @param {String} name |
|
* @returns {Object|Boolean} |
|
*/ |
|
function getSingle(name) { |
|
if (instances.length) { |
|
var match = instances.filter(function (item) { |
|
return item.name === name; |
|
}); |
|
if (match.length) { |
|
return match[0]; |
|
} |
|
} |
|
return false; |
|
} |
|
/** |
|
* Create an instance of Browsersync |
|
* @param {String} [name] |
|
* @param {EventEmitter} [emitter] |
|
* @returns {{init: *, exit: (exit|exports), notify: *, reload: *, cleanup: *, emitter: (Browsersync.events|*), use: *}} |
|
*/ |
|
/** |
|
* Reset the state of the module. |
|
* (should only be needed for test environments) |
|
*/ |
|
module.exports.reset = function () { |
|
instances.forEach(function (item) { |
|
item.cleanup(); |
|
}); |
|
instances = []; |
|
singletonPlugins = []; |
|
singletonEmitter = false; |
|
singleton = false; |
|
}; |
|
/** |
|
* @type {Array} |
|
*/ |
|
module.exports.instances = instances; |
|
/** |
|
* Create an instance of Browsersync |
|
* @param {String} [name] |
|
* @param {EventEmitter} [emitter] |
|
* @returns {{init: *, exit: (exit|exports), notify: *, reload: *, cleanup: *, emitter: (Browsersync.events|*), use: *}} |
|
*/ |
|
module.exports.create = create; |
|
function create(name, emitter) { |
|
name = name || new Date().getTime(); |
|
emitter = emitter || newEmitter(); |
|
var browserSync = new BrowserSync(emitter); |
|
var instance = { |
|
name: name, |
|
instance: browserSync, |
|
exit: require("./public/exit")(browserSync), |
|
notify: require("./public/notify")(browserSync), |
|
pause: require("./public/pause")(browserSync), |
|
resume: require("./public/resume")(browserSync), |
|
reload: require("./public/reload")(emitter), |
|
stream: require("./public/stream")(emitter), |
|
cleanup: browserSync.cleanup.bind(browserSync), |
|
use: browserSync.registerPlugin.bind(browserSync), |
|
getOption: browserSync.getOption.bind(browserSync), |
|
emitter: browserSync.events, |
|
watch: require("./file-watcher").watch |
|
}; |
|
browserSync.publicInstance = instance; |
|
instance.init = require("./public/init")(browserSync, name, pjson); |
|
Object.defineProperty(instance, "active", { |
|
get: function () { |
|
return browserSync.active; |
|
} |
|
}); |
|
Object.defineProperty(instance, "paused", { |
|
get: function () { |
|
return browserSync.paused; |
|
} |
|
}); |
|
/** |
|
* Access to client-side socket for emitting events |
|
* |
|
* @property sockets |
|
*/ |
|
Object.defineProperty(instance, "sockets", { |
|
get: function () { |
|
if (!browserSync.active) { |
|
return { |
|
emit: function () { }, |
|
on: function () { } |
|
}; |
|
} |
|
else { |
|
return browserSync.io.sockets; |
|
} |
|
} |
|
}); |
|
instances.push(instance); |
|
return instance; |
|
} |
|
//# sourceMappingURL=index.js.map
|