Skip to content

Instantly share code, notes, and snippets.

@aputs
Created September 29, 2016 15:10
Show Gist options
  • Save aputs/2913fb9460d5e488e4ab5951054ed734 to your computer and use it in GitHub Desktop.
Save aputs/2913fb9460d5e488e4ab5951054ed734 to your computer and use it in GitHub Desktop.
re-natal reagent figwheel repl with boot-clj
#http://boot-clj.com
#Wed Sep 28 14:53:54 PHT 2016
BOOT_CLOJURE_NAME=org.clojure/clojure
BOOT_CLOJURE_VERSION=1.9.0-alpha12
BOOT_VERSION=2.6.0
(set-env!
:source-paths #{"src"}
:dependencies
'[[org.clojure/clojure "1.9.0-alpha12" :scope "provided"]
[org.clojure/clojurescript "1.9.229" :scope "provided"]
[com.cemerick/piggieback "0.2.1" :scope "test"]
[org.clojure/tools.nrepl "0.2.12" :scope "test"]
[figwheel-sidecar "0.5.8" :scope "test"]
[proto-repl "0.3.1" :scope "test"]
[org.clojure/core.async "0.2.391"]
[reagent "0.6.0" :exclusions [cljsjs/react cljsjs/react-dom cljsjs/react-dom-server]]
[datascript "0.15.3"]
[posh "0.5.4"]
(require
'clojure.tools.namespace.repl
'cemerick.piggieback
'[figwheel-sidecar.system :as sys]
'[com.stuartsierra.component :as component])
(def system (component/system-map :figwheel-system (sys/figwheel-system (sys/fetch-config))))
(deftask figwheel
[]
(repl :middleware '[cemerick.piggieback/wrap-cljs-repl]
:eval '(do
(alter-var-root #'system component/start)
(sys/cljs-repl (:figwheel-system system)))))
/*
* Originally taken from https://github.com/decker405/figwheel-react-native
*
* @providesModule figwheel-bridge
*/
var CLOSURE_UNCOMPILED_DEFINES = null;
var debugEnabled = false;
var config = {
basePath: "target/",
googBasePath: 'goog/',
serverPort: 8081
};
var React = require('react');
var ReactNative = require('react-native');
var WebSocket = require('WebSocket');
var self;
var scriptQueue = [];
var serverHost = null; // will be set dynamically
var fileBasePath = null; // will be set dynamically
var evaluate = eval; // This is needed, direct calls to eval does not work (RN packager???)
var externalModules = {};
var evalListeners = [ // Functions to be called after each js file is loaded and evaluated
function (url) {
if (url.indexOf('jsloader') > -1) {
shimJsLoader();
}
},
function (url) {
if (url.indexOf('/figwheel/client/socket') > -1) {
setCorrectWebSocketImpl();
}
}];
var figwheelApp = function (platform, devHost) {
return React.createClass({
getInitialState: function () {
return {loaded: false}
},
render: function () {
if (!this.state.loaded) {
var plainStyle = {flex: 1, alignItems: 'center', justifyContent: 'center'};
return (
<ReactNative.View style={plainStyle}>
<ReactNative.Text>Waiting for Figwheel to load files.</ReactNative.Text>
</ReactNative.View>
);
}
return this.state.root;
},
componentDidMount: function () {
var app = this;
if (typeof goog === "undefined") {
loadApp(platform, devHost, function (appRoot) {
app.setState({root: appRoot, loaded: true})
});
}
}
})
};
function logDebug(msg) {
if (debugEnabled) {
console.log(msg);
}
}
// evaluates js code ensuring proper ordering
function customEval(url, javascript, success, error) {
if (scriptQueue.length > 0) {
if (scriptQueue[0] === url) {
try {
evaluate(javascript);
logDebug('Evaluated: ' + url);
scriptQueue.shift();
evalListeners.forEach(function (listener) {
listener(url)
});
success();
} catch (e) {
console.error(e);
error();
}
} else {
setTimeout(function () {
customEval(url, javascript, success, error)
}, 5);
}
} else {
console.error('Something bad happened...');
error()
}
}
var isChrome = function () {
return typeof importScripts === "function"
};
function asyncImportScripts(url, success, error) {
logDebug('(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);
return error();
});
}
function syncImportScripts(url, success, error) {
try {
importScripts(url);
logDebug('Evaluated: ' + url);
evalListeners.forEach(function (listener) {
listener(url)
});
success();
} catch (e) {
console.error(e);
error()
}
}
// Loads js file sync if possible or async.
function importJs(src, success, error) {
if (typeof success !== 'function') {
success = function () {
};
}
if (typeof error !== 'function') {
error = function () {
};
}
var file = fileBasePath + '/' + src;
logDebug('(importJs) Importing: ' + file);
if (isChrome()) {
syncImportScripts(serverBaseUrl("localhost") + '/' + file, success, error);
} else {
asyncImportScripts(serverBaseUrl(serverHost) + '/' + file, success, error);
}
}
function interceptRequire() {
var oldRequire = window.require;
console.info("Shimming require");
window.require = function (id) {
console.info("Requiring: " + id);
if (externalModules[id]) {
return externalModules[id];
}
return oldRequire(id);
};
}
function compileWarningsToYellowBox() {
var log = window.console.log;
var compileWarningRx = /Figwheel: Compile/;
var compileExceptionRx = /Figwheel: Compile Exception/;
var errorInFileRx = /Error on file/;
var isBuffering = false;
var compileExceptionBuffer = "";
window.console.log = function (msg) {
log.apply(window.console, arguments);
if (compileExceptionRx.test(msg)) { // enter buffering mode to get all the messages for exception
isBuffering = true;
compileExceptionBuffer = msg + "\n";
} else if (errorInFileRx.test(msg) && isBuffering) { // exit buffering mode and log buffered messages to YellowBox
isBuffering = false;
console.warn(compileExceptionBuffer + msg);
compileExceptionBuffer = "";
} else if (isBuffering) { //log messages buffering mode
compileExceptionBuffer += msg + "\n";
} else if (compileWarningRx.test(msg)) {
console.warn(msg);
}
};
}
function serverBaseUrl(host) {
return "http://" + host + ":" + config.serverPort
}
function setCorrectWebSocketImpl() {
figwheel.client.socket.get_websocket_imp = function () {
return WebSocket;
};
}
function loadApp(platform, devHost, onLoadCb) {
serverHost = devHost;
fileBasePath = config.basePath + platform;
// callback when app is ready to get the reloadable component
var mainJs = '/env/' + platform + '/main.js';
evalListeners.push(function (url) {
if (url.indexOf(mainJs) > -1) {
onLoadCb(env[platform].main.root_el);
console.info('Done loading Clojure app');
}
});
if (typeof goog === "undefined") {
console.info('Loading Closure base.');
interceptRequire();
compileWarningsToYellowBox();
importJs('goog/base.js', function () {
shimBaseGoog();
importJs('cljs_deps.js');
importJs('goog/deps.js', function () {
// This is needed because of RN packager
// seriously React packager? why.
var googreq = goog.require;
googreq('figwheel.connect.' + platform);
});
});
}
}
function startApp(appName, platform, devHost) {
ReactNative.AppRegistry.registerComponent(
appName, () => figwheelApp(platform, devHost));
}
function withModules(moduleById) {
externalModules = moduleById;
return self;
}
// Goog fixes
function shimBaseGoog() {
console.info('Shimming goog functions.');
goog.basePath = 'goog/';
goog.writeScriptSrcNode = importJs;
goog.writeScriptTag_ = function (src, optSourceText) {
importJs(src);
return true;
};
}
// Figwheel fixes
// Used by figwheel - uses importScript to load JS rather than <script>'s
function shimJsLoader() {
console.info('==== Shimming jsloader ====');
goog.net.jsloader.load = function (uri, options) {
var deferred = {
callbacks: [],
errbacks: [],
addCallback: function (cb) {
deferred.callbacks.push(cb);
},
addErrback: function (cb) {
deferred.errbacks.push(cb);
},
callAllCallbacks: function () {
while (deferred.callbacks.length > 0) {
deferred.callbacks.shift()();
}
},
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);
}, 1);
return deferred;
};
}
self = {
withModules: withModules,
start: startApp
};
module.exports = self;
(defproject nativeapp "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.9.0-alpha12"]
[org.clojure/clojurescript "1.9.229"]
[org.clojure/core.async "0.2.391"]
[reagent "0.6.0" :exclusions [cljsjs/react cljsjs/react-dom cljsjs/react-dom-server]]
[datascript "0.15.3"]
[posh "0.5.4"]
:plugins [[lein-cljsbuild "1.1.4"]
[lein-figwheel "0.5.8"]]
:clean-targets ["target/" "index.ios.js" "index.android.js"]
:aliases {"prod-build" ^{:doc "Recompile code with prod profile."}
["do" "clean"
["with-profile" "prod" "cljsbuild" "once" "ios"]
["with-profile" "prod" "cljsbuild" "once" "android"]]}
:profiles {:dev {:dependencies [[figwheel-sidecar "0.5.8"]
[com.cemerick/piggieback "0.2.1"]
[org.clojure/test.check "0.9.0"]]
:source-paths ["src" "env/dev"]
:cljsbuild {:builds {:ios {:source-paths ["src" "env/dev"]
:figwheel true
:compiler {:output-to "target/ios/not-used.js"
:main "env.ios.main"
:output-dir "target/ios"
:optimizations :none}}
:android {:source-paths ["src" "env/dev"]
:figwheel true
:compiler {:output-to "target/android/not-used.js"
:main "env.android.main"
:output-dir "target/android"
:optimizations :none}}}}
:repl-options {:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}}
:prod {:cljsbuild {:builds {:ios {:source-paths ["src" "env/prod"]
:compiler {:output-to "index.ios.js"
:main "env.ios.main"
:output-dir "target/ios"
:static-fns true
:optimize-constants true
:optimizations :simple
:closure-defines {"goog.DEBUG" false}}}
:android {:source-paths ["src" "env/prod"]
:compiler {:output-to "index.android.js"
:main "env.android.main"
:output-dir "target/android"
:static-fns true
:optimize-constants true
:optimizations :simple
:closure-defines {"goog.DEBUG" false}}}}}}})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment