diff --git a/README.md b/README.md index 4df7eca..48fdc32 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,34 @@ remotedev --hostname=localhost --port=8000 Change `hostname` and `port` to the values you want. +### Inject to React Native local server + +##### Add in your React Native app's `package.json`: + +``` +"scripts": { + "remotedev": "remotedev --hostname=localhost --port=8000 --injectserver=reactnative" +} +``` + +The `injectserver` value can be `reactnative` or `desktop` ([react-native-desktop](https://github.com/ptmt/react-native-desktop)), it used `reactnative` by default. + +Then, we can start React Native server and RemoteDev server with one command: + +![Inject server](https://cloud.githubusercontent.com/assets/3001525/16925822/92b6b3ac-4d58-11e6-9f36-d57dac8892c4.png) + +##### Revert the injection + +Add in your React Native app's `package.json`: + +``` +"scripts": { + "remotedev-revert": "remotedev --revert=reactnative" +} +``` + +Or just run `$(npm bin)/remotedev --revert`. + ### Connect from Android device or emulator If you're running an Android 5.0+ device connected via USB or an Android emulator, use [adb command line tool](http://developer.android.com/tools/help/adb.html) to setup port forwarding from the device to your computer: diff --git a/bin/getOptions.js b/bin/getOptions.js new file mode 100644 index 0000000..21e7e79 --- /dev/null +++ b/bin/getOptions.js @@ -0,0 +1,12 @@ +module.exports = function getOptions(argv) { + return { + host: argv.hostname || process.env.npm_package_remotedev_hostname || null, + port: Number(argv.port || process.env.npm_package_remotedev_port) || 8000, + protocol: argv.protocol || process.env.npm_package_remotedev_protocol || 'http', + protocolOptions: !(argv.protocol === 'https') ? null : { + key: argv.key || process.env.npm_package_remotedev_key || null, + cert: argv.cert || process.env.npm_package_remotedev_cert || null, + passphrase: argv.passphrase || process.env.npm_package_remotedev_passphrase || null + } + }; +} diff --git a/bin/injectServer.js b/bin/injectServer.js new file mode 100644 index 0000000..5236338 --- /dev/null +++ b/bin/injectServer.js @@ -0,0 +1,57 @@ +var fs = require('fs'); +var path = require('path'); + +var name = 'remotedev-server'; +var startFlag = '/* ' + name + ' start */'; +var endFlag = '/* ' + name + ' end */'; +var serverFlag = ' _server(argv, config, resolve, reject);'; + +exports.dir = 'local-cli/server'; +exports.file = 'server.js'; +exports.fullPath = path.join(exports.dir, exports.file); + +exports.inject = function(modulePath, options) { + var filePath = path.join(modulePath, exports.fullPath); + if (!fs.existsSync(filePath)) return false; + + var code = [ + startFlag, + ' require("' + name + '")(' + JSON.stringify(options) + ')', + ' .then(_remotedev =>', + ' _remotedev.on("ready", () => {', + ' if (!_remotedev.portAlreadyUsed) console.log("-".repeat(80));', + ' ' + serverFlag, + ' })', + ' );', + endFlag, + ].join('\n'); + + var serverCode = fs.readFileSync(filePath, 'utf-8'); + var start = serverCode.indexOf(startFlag); // already injected ? + var end = serverCode.indexOf(endFlag) + endFlag.length; + if (start === -1) { + start = serverCode.indexOf(serverFlag); + end = start + serverFlag.length; + } + fs.writeFileSync( + filePath, + serverCode.substr(0, start) + code + serverCode.substr(end, serverCode.length) + ); + return true; +}; + +exports.revert = function(modulePath) { + var filePath = path.join(modulePath, exports.fullPath); + if (!fs.existsSync(filePath)) return false; + + var serverCode = fs.readFileSync(filePath, 'utf-8'); + var start = serverCode.indexOf(startFlag); // already injected ? + var end = serverCode.indexOf(endFlag) + endFlag.length; + if (start !== -1) { + fs.writeFileSync( + filePath, + serverCode.substr(0, start) + serverFlag + serverCode.substr(end, serverCode.length) + ); + } + return true; +}; \ No newline at end of file diff --git a/bin/remotedev.js b/bin/remotedev.js index 7788057..d16df6f 100755 --- a/bin/remotedev.js +++ b/bin/remotedev.js @@ -2,6 +2,9 @@ var fs = require('fs'); var path = require('path'); var argv = require('minimist')(process.argv.slice(2)); +var chalk = require('chalk'); +var getOptions = require('./getOptions'); +var injectServer = require('./injectServer'); function readFile(filePath) { return fs.readFileSync(path.resolve(process.cwd(), filePath), 'utf-8'); @@ -12,4 +15,42 @@ if (argv.protocol === 'https') { argv.cert = argv.cert ? readFile(argv.cert) : null; } +function log(pass, msg) { + var prefix = pass ? chalk.green.bgBlack('PASS') : chalk.red.bgBlack('FAIL'); + var color = pass ? chalk.blue : chalk.red; + console.log(prefix, color(msg)); +}; + +function getModuleName(type) { + switch (type) { + case 'desktop': + return 'react-native-desktop'; + case 'reactnative': + default: + return 'react-native'; + } +} + +function getModulePath(type) { + var moduleName = getModuleName(type); + return path.join(process.cwd(), 'node_modules', moduleName); +} + +if (argv.revert) { + var pass = injectServer.revert(getModulePath(argv.revert)); + var msg = 'Revert injection of RemoteDev server from React Native local server'; + log(pass, msg + (!pass ? ', the file `' + injectServer.fullPath + '` not found.' : '.')); + + process.exit(pass ? 0 : 1); +} + +if (argv.injectserver) { + var options = getOptions(argv); + var pass = injectServer.inject(getModulePath(argv.injectserver), options); + var msg = 'Inject RemoteDev server into React Native local server'; + log(pass, msg + (pass ? '.' : ', the file `' + injectServer.fullPath + '` not found.')); + + process.exit(pass ? 0 : 1); +} + require('./server')(argv); diff --git a/bin/server.js b/bin/server.js index cff255f..62ad5a3 100644 --- a/bin/server.js +++ b/bin/server.js @@ -1,16 +1,27 @@ +var assign = require('object-assign'); +var repeat = require('repeat-string'); +var getOptions = require('./getOptions'); +var getPort = require('getport'); + module.exports = function(argv) { var SocketCluster = require('socketcluster').SocketCluster; - - return new SocketCluster({ - host: argv.hostname || process.env.npm_package_remotedev_hostname || null, - port: Number(argv.port || process.env.npm_package_remotedev_port) || 8000, + var options = assign(getOptions(argv), { workerController: __dirname + '/worker.js', - allowClientPublish: false, - protocol: argv.protocol || process.env.npm_package_remotedev_protocol || 'http', - protocolOptions: !(argv.protocol === 'https') ? null : { - key: argv.key || process.env.npm_package_remotedev_key || null, - cert: argv.cert || process.env.npm_package_remotedev_cert || null, - passphrase: argv.passphrase || process.env.npm_package_remotedev_passphrase || null - } + allowClientPublish: false + }); + var port = options.port; + return new Promise(function(resolve) { + // Check port already used + getPort(port, function(err, p) { + if (err) return console.error(err); + if (port !== p) { + console.log('[RemoveDev] Server port ' + port + ' is already used.'); + resolve({ portAlreadyUsed: true, on: function(status, cb) { cb(); } }); + } else { + console.log('[RemoveDev] Start server...'); + console.log(repeat('-', 80) + '\n'); + resolve(new SocketCluster(options)); + } + }); }); }; diff --git a/package.json b/package.json index be767ff..3fd2170 100644 --- a/package.json +++ b/package.json @@ -26,10 +26,14 @@ "homepage": "https://github.com/zalmoxisus/remotedev-server", "dependencies": { "body-parser": "^1.15.0", + "chalk": "^1.1.3", "cors": "^2.7.1", "ejs": "^2.4.1", "express": "^4.13.3", + "getport": "^0.1.0", "minimist": "^1.2.0", + "object-assign": "^4.1.0", + "repeat-string": "^1.5.4", "socketcluster": "^4.3.1" } }