Skip to content

Instantly share code, notes, and snippets.

@shark0der
Forked from axemclion/browser-sync.js
Last active June 20, 2018 17:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shark0der/72dff94b51ebf0660930574b552e74c8 to your computer and use it in GitHub Desktop.
Save shark0der/72dff94b51ebf0660930574b552e74c8 to your computer and use it in GitHub Desktop.
Using browser-sync with Cordova
// Browser-Sync support for Cordova projects
// To use this, add the following snippet as a after_run hook using something like
// <hook type="after_prepare" src="hooks/browser-sync.js" />
// Add under default-src ws: 'unsafe-inline' to the CSP in index.html
// Add under script-src * (you can whitelist the host for livereload, but this is a shortcut).
// Don't forget to remove them in prod!
// Then run: cordova run -- --live-reload
// Changing anything in www/ will live-reload the cordova app on emulator/device
module.exports = function(context) {
if (typeof context.opts.options["--browser-sync-mode"] !== 'undefined') {
// Prepare was called by this script, so don't run the script again
return;
}
if (context.opts.options.argv.indexOf('--live-reload') === -1) {
// --live-reload switch was not provided
return;
}
var path = require('path');
var fs = require('fs');
var Url = require('url');
var debug = console.log.bind(console);
var npm = context.requireCordovaModule('npm');
var Q = context.requireCordovaModule('q');
var glob = context.requireCordovaModule('glob')
var et = context.requireCordovaModule('elementtree');
function parseXml(filename) {
return new et.ElementTree(et.XML(fs.readFileSync(filename, "utf-8").replace(/^\uFEFF/, "")));
}
// Installs browser-sync and other packages locally
function installDependencies() {
return Q();
debug('Starting npm');
return Q.ninvoke(npm, 'load').then(function() {
debug('Installing dependencies');
return Q.ninvoke(npm.commands, 'install', ['browser-sync']);
});
}
/**
* Cordova is usually served from index.html on the device. This function serves changes that to be served from a server instead
* @param configLocation - The place where platform specific config.xml is located, relative to platforms folder
* @param hostedPage - Location from where the www/index.html file should be served, relative to platforms folder
**/
function changeHost(hostedPage, configLocation) {
var cwd = path.join(context.opts.projectRoot, 'platforms', configLocation);
debug('Searching for config files at', cwd);
return configs = glob.sync('**/config.xml', {
cwd: cwd
}).map(function(filename) {
debug(`Found config.xml: ${filename}`);
var filename = path.join(cwd, filename);
debug('Changing ', filename);
configXml = parseXml(filename);
var contentTag = configXml.find('content[@src]');
if (contentTag) {
contentTag.attrib.src = hostedPage;
}
// Also add allow nav in case of
var allowNavTag = et.SubElement(configXml.find('.'), 'allow-navigation');
allowNavTag.set('href', '*');
fs.writeFileSync(filename, configXml.write({
indent: 4
}), "utf-8");
return filename;
});
}
/**
* Starts the browser sync server, and when files are changed, does the reload
* @param location - where to watch
* @returns location where files are served from
*/
function browserSyncServer(location) {
debug('Starting browser-sync server');
location = location + '**/*.*'
return Q.promise(function(resolve, reject, notify) {
var bs = require('browser-sync').create();
bs.watch(location, function(event, files) {
if (event !== 'change') {
return;
}
// TODO Prepare only the platform that was run
context.cordova.prepare({
options: { "--browser-sync-mode": true } // to indicate who is calling prepare
});
bs.reload(files);
});
bs.init({
server: {
baseDir: context.opts.projectRoot,
directory: true
},
files: location,
open: false,
snippetOptions: {
rule: {
match: /<\/body>/i,
fn: function(snippet, match) {
return '<script>window.__karma__=true</script>' + snippet + match;
}
}
},
minify: false
}, function(err, bs) {
var server = bs.options.getIn(['urls', 'external']);
resolve(Url.resolve(server, 'platforms'));
});
});
}
// Main workfow
return installDependencies().then(function() {
const projectRoot = path.join(context.opts.projectRoot, 'www/');
return browserSyncServer(projectRoot);
}).then(function(server) {
// TODO - Change host based on platform
changeHost(server + '/android/assets/www/index.html', 'android/res/xml');
changeHost(server + '/ios/www/index.html', 'ios');
});
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment