make Figwheel work without the need of Debug in Chrome

- solution by https://github.com/decker405/figwheel-react-native
- remove use-reload command.
- adoptions to figwheel-bridge.js
This commit is contained in:
Artur Girenko 2015-12-05 23:53:27 +01:00
parent 91eac6fd2c
commit 927b5de7fe
4 changed files with 159 additions and 90 deletions

View File

@ -20,10 +20,10 @@ Generated project works in iOS and Android devices.
## State
- Same codebase for iOS and Android
- Figwheel used for REPL and live coding.
- Only works in "Debug in Chrome" mode
- Works in iOS (tested using simulator).
- Works in Android (tested on real device, encountered connection problem using Android simulator genymotion)
- Works in Android (tested on real device, does not work on simulator yet)
- You can reload app any time, no problem.
- "Debug in Chrome" is not required anymore.
- Optimizations :simple is used to compile "production" index.ios.js and index.android.js
- [Unified way of using static images of rn 0.14](https://facebook.github.io/react-native/docs/images.html) works
@ -62,6 +62,7 @@ and then run your app from Xcode normally.
To run in Android, run your simulator first or connect device and:
```
$ adb reverse tcp:8081 tcp:8081
$ react-native run-android
```
@ -70,21 +71,13 @@ are compiled with `optimizations :simple`.
Development in such mode is not fun because of slow compilation and long reload time.
Luckily, this can be improved by compiling with `optimizations :none` and using
figwheel.
Figwheel.
To start development in `optimizations :none` mode you have to start "Debug in Chrome"
in your React Native application.
Then execute commands:
To start development mode execute commands:
```
$ re-natal use-figwheel
$ lein figwheel ios
```
or for usage without figwheel:
```
$ re-natal use-reload
$ lein cljsbuild auto android
```
This will generate index.ios.js and index.android.js which works with compiler mode`optimizations :none`.
@ -119,11 +112,17 @@ Do this with command:
$ lein prod-build
```
It will clean and rebuild index.ios.js and index.android.js with `optimizations :simple`
After this you can reload the app and exit "Debug in Chrome".
Having index.ios.js and index.android.js build this way, you should be able to
follow the RN docs to proceed with the release.
## Problems with Android simulator
Using Figwheel with android simulator is not working out of the box yet.
Looks like the main reason for that is that requests to http://localhost:8081 fails because
"localhost" is simulators own loopback interface and not the one of the host machine.
According to [Emulator docs](http://developer.android.com/tools/devices/emulator.html#networkaddresses)
instead of "localhost" a special IP: 10.0.2.2 should be used.
## Tips
- Having `rlwrap` installed is optional but highly recommended since it makes
the REPL a much nicer experience with arrow keys.

View File

@ -377,12 +377,12 @@ getDeviceUuids = ->
getDeviceList().map (line) -> line.match(/\[(.+)\]/)[1]
generateDevScripts = (method) ->
generateDevScripts = () ->
try
fs.statSync '.re-natal'
fs.writeFileSync 'index.ios.js', "require('react-native');require('figwheel-bridge')."+method+"('ios');"
appName = readConfig().name
fs.writeFileSync 'index.ios.js', "require('figwheel-bridge').start('" + appName + "','ios');"
log 'index.ios.js was regenerated'
fs.writeFileSync 'index.android.js', "require('react-native');require('figwheel-bridge')."+method+"('android');"
fs.writeFileSync 'index.android.js', "require('figwheel-bridge').start('" + appName + "','android');"
log 'index.android.js was regenerated'
catch {message}
logErr \
@ -485,12 +485,7 @@ cli.command 'deps'
cli.command 'use-figwheel'
.description 'generate index.ios.js and index.android.js for development with figwheel'
.action ->
generateDevScripts("figwheel")
cli.command 'use-reload'
.description 'generate index.ios.js and index.android.js for development using app reload'
.action ->
generateDevScripts("start")
generateDevScripts()
cli.on '*', (command) ->
logErr "unknown command #{command[0]}. See re-natal --help for valid commands"

View File

@ -4,5 +4,6 @@
(enable-console-print!)
(core/init)
(core/mount-root)

View File

@ -6,124 +6,198 @@
var CLOSURE_UNCOMPILED_DEFINES = null;
var React = require('react-native');
var config = {
basePath: '',
googBasePath: 'goog/'
server: 'http://localhost:8081',
basePath: "target/",
googBasePath: 'goog/',
splash: React.createClass({
render: function () {
var plainStyle = {flex: 1, alignItems: 'center', justifyContent: 'center'};
return (
<React.View style={plainStyle}>
<React.Text>Waiting for Figwheel to load files.</React.Text>
</React.View>
);
}
})
};
// Uninstall watchman???
function importJs(src, success, error){
if(typeof success !== 'function') { success = function(){}; }
if(typeof error !== 'function') { error = function(){}; }
var scriptQueue = [];
var fileBasePath = null; // will be set dynamically
var evaluate = eval; // This is needed, direct calls to eval does not work (RN packager???)
console.log('(Figwheel Bridge) Importing: ' + config.basePath + src);
try {
importScripts(config.basePath + src);
success();
} catch(e) {
console.warn('Could not load: ' + config.basePath + src);
console.error('Import error: ' + e);
error();
// evaluates js code ensuring proper ordering
function customEval(url, javascript, success, error) {
if (scriptQueue.length > 0) {
if (scriptQueue[0] === url) {
try {
evaluate(javascript);
console.info('Evaluated: ' + url);
scriptQueue.shift();
if (url.indexOf('jsloader') > -1) {
shimJsLoader();
}
success();
} catch (e) {
console.error('Evaluation error in: ' + url);
console.error(e);
error();
}
} else {
setTimeout(function () {
customEval(url, javascript, success, error)
}, 5);
}
} else {
console.error('Something bad happened...');
error()
}
}
function asyncImportScripts(path, success, error) {
var url = config.server + '/' + path;
console.info('(asyncImportScripts) Importing: ' + url);
scriptQueue.push(url);
fetch(url)
.then(function (response) {
return response.text()
})
.then(function (responseText) {
return customEval(url, responseText, success, error);
})
.catch(function (error) {
console.error('Error loading script, please check your config setup.');
console.error(error);
return error();
});
}
// Async load of javascript files
function importJs(src, success, error) {
if (typeof success !== 'function') {
success = function () {
};
}
if (typeof error !== 'function') {
error = function () {
};
}
var filePath = fileBasePath + '/' + src;
console.info('(importJs) Importing: ' + filePath);
asyncImportScripts(filePath, success, error);
}
// Loads base goog js file then cljs_deps, goog.deps, core project cljs, and then figwheel
// Also calls the function to shim goog.require and goog.net.jsLoader.load
function loadApp(platform) {
config.basePath = "/target/" + platform + "/";
fileBasePath = config.basePath + platform;
if(typeof goog === "undefined") {
if (typeof goog === "undefined") {
console.log('Loading Closure base.');
importJs('goog/base.js');
shimBaseGoog();
fakeLocalStorageAndDocument();
importJs('cljs_deps.js');
importJs('goog/deps.js');
importJs('$PROJECT_NAME_UNDERSCORED$/'+platform+'/core.js');
importJs('goog/base.js', function () {
shimBaseGoog();
fakeLocalStorageAndDocument();
importJs('cljs_deps.js');
importJs('goog/deps.js', function () {
console.log('Done loading Clojure app');
// This is needed because of RN packager
// seriously React packager? why.
var googreq = goog.require;
googreq('figwheel.connect');
googreq('env.' + platform + '.main');
console.log('Done loading Clojure app');
});
});
}
}
function startApp(platform) {
if(typeof goog === "undefined") {
function startApp(appName, platform) {
React.AppRegistry.registerComponent(appName, () => config.splash);
if (typeof goog === "undefined") {
loadApp(platform);
}
console.log('Starting the app');
eval("$PROJECT_NAME_UNDERSCORED$."+platform+".core.init()");
}
// Loads base goog js file then cljs_deps, goog.deps, core project cljs, and then figwheel
// Also calls the function to shim goog.require and goog.net.jsLoader.load
function startWithFigwheel(platform) {
if(typeof goog === "undefined") {
startApp(platform);
}
importJs('figwheel/connect.js');
// goog.require('figwheel.connect');
// goog.require('rn_test.core');
shimJsLoader();
}
function shimBaseGoog(){
// Goog fixes
function shimBaseGoog() {
console.info('Shimming goog functions.');
goog.basePath = 'goog/';
goog.writeScriptSrcNode = importJs;
goog.writeScriptTag_ = function(src, opt_sourceText){
goog.writeScriptTag_ = function (src, optSourceText) {
importJs(src);
return true;
}
goog.inHtmlDocument_ = function(){ return true; };
};
goog.inHtmlDocument_ = function () {
return true;
};
}
function fakeLocalStorageAndDocument() {
window.localStorage = {};
window.localStorage.getItem = function(){ return 'true'; };
window.localStorage.setItem = function(){};
window.localStorage.getItem = function () {
return 'true';
};
window.localStorage.setItem = function () {
};
window.document = {};
window.document.body = {};
window.document.body.dispatchEvent = function(){};
window.document.createElement = function(){};
window.document.body.dispatchEvent = function () {
};
window.document.createElement = function () {
};
if (typeof window.location === 'undefined') {
window.location = {};
}
console.debug = console.warn;
window.addEventListener = function () {
};
}
// Figwheel fixes
// Used by figwheel - uses importScript to load JS rather than <script>'s
function shimJsLoader(){
goog.net.jsloader.load = function(uri, options) {
function shimJsLoader() {
console.info('==== Shimming jsloader ====');
goog.net.jsloader.load = function (uri, options) {
var deferred = {
callbacks: [],
errbacks: [],
addCallback: function(cb){
addCallback: function (cb) {
deferred.callbacks.push(cb);
},
addErrback: function(cb){
addErrback: function (cb) {
deferred.errbacks.push(cb);
},
callAllCallbacks: function(){
while(deferred.callbacks.length > 0){
callAllCallbacks: function () {
while (deferred.callbacks.length > 0) {
deferred.callbacks.shift()();
}
},
callAllErrbacks: function(){
while(deferred.errbacks.length > 0){
callAllErrbacks: function () {
while (deferred.errbacks.length > 0) {
deferred.errbacks.shift()();
}
}
};
// Figwheel needs this to be an async call, so that it can add callbacks to deferred
setTimeout(function(){
importJs(uri.getPath(), deferred.callAllCallbacks, deferred.callAllErrbacks);
// Figwheel needs this to be an async call,
// so that it can add callbacks to deferred
setTimeout(function () {
importJs(uri.getPath(),
deferred.callAllCallbacks,
deferred.callAllErrbacks);
}, 1);
return deferred;
}
};
}
module.exports = {
start: startApp,
figwheel : startWithFigwheel,
load: loadApp
start: startApp
};