From dac3e2044dfddc79b5dedfa26cd9817be4730f41 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Art=C5=ABr=20Girenko?= <a.girenko@gmail.com>
Date: Tue, 29 May 2018 11:27:26 +0200
Subject: [PATCH] Make :preloads and :closure-defines work (#185)

* using reagent 0.8.0-alpha1

* require react-native in namespace declaration

* bump versions

* make preloads and closure defines work

* make preloads and closure defines work

* revert changes in core.cljs

* do not preload cljs-devtools it causes a warning on startup

* add empty line

* update README

* code cleanup

* bump om-next version
---
 README.md                    |   2 +-
 re-natal.coffee              |  16 ++---
 resources/advanced.profile   |   1 +
 resources/dev.profile        |   5 +-
 resources/figwheel-bridge.js | 115 +++++++++++++++++++----------------
 resources/prod.profile       |   1 +
 resources/project.clj        |   2 +-
 7 files changed, 76 insertions(+), 66 deletions(-)

diff --git a/README.md b/README.md
index 0ddcda3..2551554 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ For more ClojureScript React Native resources visit [cljsrn.org](http://cljsrn.o
 Contributions are very welcome.
 
 ## Status
-- Uses [React Native] v0.53.0
+- Uses [React Native] v0.55.4
 - Reusable codebase between iOS and Android
 - Figwheel used for REPL and live coding
   - Works in iOS (real device and simulator)
diff --git a/re-natal.coffee b/re-natal.coffee
index e17a8a1..fcdf672 100644
--- a/re-natal.coffee
+++ b/re-natal.coffee
@@ -34,8 +34,8 @@ ipAddressRx     = /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/i
 debugHostRx     = /host]\s+\?:\s+@".*";/g
 namespaceRx     = /\(ns\s+([A-Za-z0-9.-]+)/g
 jsRequireRx     = /js\/require "(.+)"/g
-rnVersion       = '0.53.0'
-rnWinVersion    = '0.53.0-rc.1'
+rnVersion       = '0.55.4'
+rnWinVersion    = '0.55.0-rc.0'
 rnPackagerPort  = 8081
 process.title   = 're-natal'
 buildProfiles     =
@@ -64,9 +64,9 @@ interfaceConf   =
     sources:
       common:  ["events.cljs", "subs.cljs", "db.cljs"]
       other:   [["reagent_dom.cljs","reagent/dom.cljs"], ["reagent_dom_server.cljs","reagent/dom/server.cljs"]]
-    deps:      ['[reagent "0.7.0" :exclusions [cljsjs/react cljsjs/react-dom cljsjs/react-dom-server cljsjs/create-react-class]]'
-                '[re-frame "0.10.4"]']
-    shims:     ["cljsjs.react", "cljsjs.react.dom", "cljsjs.react.dom.server", "cljsjs.create-react-class"]
+    deps:      ['[reagent "0.8.1" :exclusions [cljsjs/react cljsjs/react-dom cljsjs/react-dom-server cljsjs/create-react-class]]'
+                '[re-frame "0.10.5"]']
+    shims:     []
     sampleCommandNs: '(in-ns \'$PROJECT_NAME_HYPHENATED$.ios.core)'
     sampleCommand: '(dispatch [:set-greeting "Hello Native World!"])'
   'om-next':
@@ -74,7 +74,7 @@ interfaceConf   =
     sources:
       common:  ["state.cljs"]
       other:   [["support.cljs","re_natal/support.cljs"]]
-    deps:      ['[org.omcljs/om "1.0.0-beta1" :exclusions [cljsjs/react cljsjs/react-dom]]']
+    deps:      ['[org.omcljs/om "1.0.0-beta3" :exclusions [cljsjs/react cljsjs/react-dom]]']
     shims:     ["cljsjs.react", "cljsjs.react.dom"]
     sampleCommandNs: '(in-ns \'$PROJECT_NAME_HYPHENATED$.state)'
     sampleCommand: '(swap! app-state assoc :app/msg "Hello Native World!")'
@@ -131,10 +131,6 @@ ensureExecutableAvailable = (executable) ->
     exec "type #{executable}"
 
 isYarnAvailable = () ->
-  try
-    ensureExecutableAvailable('yarn')
-    true
-  catch e
     false
 
 isSomeDepsMissing = () ->
diff --git a/resources/advanced.profile b/resources/advanced.profile
index 2439cf9..e2c5172 100644
--- a/resources/advanced.profile
+++ b/resources/advanced.profile
@@ -6,4 +6,5 @@
                                                                    :static-fns    true
                                                                    :optimize-constants true
                                                                    :optimizations :advanced
+                                                                   :target :nodejs
                                                                    :closure-defines {"goog.DEBUG" false}}}
\ No newline at end of file
diff --git a/resources/dev.profile b/resources/dev.profile
index ef9856e..bd6179a 100644
--- a/resources/dev.profile
+++ b/resources/dev.profile
@@ -1,7 +1,8 @@
                                                      {:id           "$PLATFORM$"
                                                       :source-paths ["src" "env/dev"]
                                                       :figwheel     true
-                                                      :compiler     {:output-to     "target/$PLATFORM$/not-used.js"
+                                                      :compiler     {:output-to     "target/$PLATFORM$/index.js"
                                                                      :main          "env.$PLATFORM$.main"
                                                                      :output-dir    "target/$PLATFORM$"
-                                                                     :optimizations :none}}
\ No newline at end of file
+                                                                     :optimizations :none
+                                                                     :target :nodejs}}
\ No newline at end of file
diff --git a/resources/figwheel-bridge.js b/resources/figwheel-bridge.js
index 6f4e285..32d302e 100644
--- a/resources/figwheel-bridge.js
+++ b/resources/figwheel-bridge.js
@@ -4,7 +4,6 @@
  * @providesModule figwheel-bridge
  */
 
-var CLOSURE_UNCOMPILED_DEFINES = null;
 var debugEnabled = false;
 
 var config = {
@@ -33,34 +32,34 @@ function formatCompileError(msg) {
     var errorStr = "Figwheel Compile Exception: "
     var data = msg['exception-data'];
     if(data['message']) {
-   	errorStr += data['message'] + " ";
+        errorStr += data['message'] + " ";
     }
     if(data['file']) {
-   	errorStr += "in file " + data['file'] + " ";
+        errorStr += "in file " + data['file'] + " ";
     }
     if(data['line']) {
-   	errorStr += "at line " + data['line'];
+        errorStr += "at line " + data['line'];
     }
     if(data['column']) {
-   	errorStr += ", column " + data['column'];
+        errorStr += ", column " + data['column'];
     }
     return errorStr;
 }
 
-/* This is simply demonstrating that we can receive and react to 
+/* This is simply demonstrating that we can receive and react to
  * arbitrary messages from Figwheel this will enable creating a nicer
  * feedback system in the Figwheel top level React component.
  */
 function figwheelMessageHandler(msg) {
     if(msg["msg-name"] == "compile-failed") {
-	console.warn(formatCompileError(msg));
+        console.warn(formatCompileError(msg));
     }
 }
 
 function listenToFigwheelMessages() {
     if(figwheel.client.add_json_message_watch) {
-	figwheel.client.add_json_message_watch("ReactNativeMessageIntercept",
-					       figwheelMessageHandler);
+        figwheel.client.add_json_message_watch("ReactNativeMessageIntercept",
+            figwheelMessageHandler);
     }
 }
 
@@ -86,7 +85,7 @@ var figwheelApp = function (platform, devHost) {
             if (typeof goog === "undefined") {
                 loadApp(platform, devHost, function (appRoot) {
                     app.setState({root: appRoot, loaded: true});
-		    listenToFigwheelMessages();
+                    listenToFigwheelMessages();
                 });
             }
         }
@@ -103,34 +102,34 @@ var isChrome = function () {
     return typeof importScripts === "function"
 };
 
-function asyncImportScripts(url, success, error) {
+function asyncImportScripts(url, transform, success, error) {
     logDebug('(asyncImportScripts) Importing: ' + url);
     asyncImportChain =
-	asyncImportChain
-	.then(function (v) {return fetch(url);})
-        .then(function (response) {
-	    if(response.ok) 
-		return response.text();
-	    throw new Error("Failed to Fetch: " + url + " - Perhaps your project was cleaned and you haven't recompiled?")
-        })
-        .then(function (responseText) {
-	    evaluate(responseText);
-	    fireEvalListenters(url);
-            success();
-	    return true;
-        })
-        .catch(function (e) {
-            console.error(e);
-            error();
-	    return true;
-        });
+        asyncImportChain
+            .then(function (v) {return fetch(url);})
+            .then(function (response) {
+                if(response.ok)
+                    return response.text();
+                throw new Error("Failed to Fetch: " + url + " - Perhaps your project was cleaned and you haven't recompiled?")
+            })
+            .then(function (responseText) {
+                evaluate(transform(responseText));
+                fireEvalListenters(url);
+                success();
+                return true;
+            })
+            .catch(function (e) {
+                console.error(e);
+                error();
+                return true;
+            });
 }
 
 function syncImportScripts(url, success, error) {
     try {
         importScripts(url);
         logDebug('Evaluated: ' + url);
-	fireEvalListenters(url);
+        fireEvalListenters(url);
         success();
     } catch (e) {
         console.error(e);
@@ -141,13 +140,14 @@ function syncImportScripts(url, success, error) {
 // Loads js file sync if possible or async.
 function importJs(src, success, error) {
     var noop = function(){};
-    success = (typeof success == 'function') ? success : noop;
-    error   = (typeof error   == 'function') ? error   : noop;
+    var identity = function (arg){return arg};
+    var successCb = (typeof success == 'function') ? success : noop;
+    var errorCb = (typeof error   == 'function') ? error : noop;
     logDebug('(importJs) Importing: ' + src);
     if (isChrome()) {
-        syncImportScripts(src, success, error);
+        syncImportScripts(src, successCb, errorCb);
     } else {
-        asyncImportScripts(src, success, error);
+        asyncImportScripts(src, identity, successCb, errorCb);
     }
 }
 
@@ -175,16 +175,29 @@ function isUnDefined(x) {
 function assertRootElExists(platform) {
     var basicMessage = "ClojureScript project didn't compile, or didn't load correctly.";
     if(isUnDefined(env)) {
-	throw new Error("Critical Error: env namespace not defined - " + basicMessage);
+        throw new Error("Critical Error: env namespace not defined - " + basicMessage);
     } else if(isUnDefined(env[platform])) {
-	throw new Error("Critical Error: env." + platform + " namespace not defined - " + basicMessage);
+        throw new Error("Critical Error: env." + platform + " namespace not defined - " + basicMessage);
     } else if(isUnDefined(env[platform].main)) {
-	throw new Error("Critical Error: env." + platform + ".main namespace not defined - " + basicMessage);
+        throw new Error("Critical Error: env." + platform + ".main namespace not defined - " + basicMessage);
     } else if(isUnDefined(env[platform].main.root_el)) {
-	throw new Error("Critical Error: env." +
-			platform + ".main namespace doesn't define a root-el which should hold the root react node of your app.");
+        throw new Error("Critical Error: env." +
+            platform + ".main namespace doesn't define a root-el which should hold the root react node of your app.");
     }
- }
+}
+
+function importIndexJs(fileBasePath) {
+    var src = fileBasePath + '/index.js';
+    var transformFn = function(code) {
+        var defines = code.match(new RegExp ("goog.global.CLOSURE_UNCOMPILED_DEFINES.*?;"));
+        var deps = code.match(/goog.require\(.*?\);/g);
+        var transformedCode = defines.concat(deps).join('');
+        logDebug('transformed index.js: ', transformedCode);
+        return transformedCode;
+    };
+    logDebug('(importIndexJs) Importing: ' + src);
+    asyncImportScripts(src, transformFn, function(){}, function(){});
+}
 
 function loadApp(platform, devHost, onLoadCb) {
     var fileBasePath = serverBaseUrl((isChrome() ? "localhost" : devHost)) + "/" + config.basePath + platform;
@@ -193,26 +206,24 @@ function loadApp(platform, devHost, onLoadCb) {
     var mainJs = `/env/${platform}/main.js`;
     evalListeners.waitForFinalEval = function (url) {
         if (url.indexOf(mainJs) > -1) {
-	    assertRootElExists(platform);
+            assertRootElExists(platform);
             onLoadCb(env[platform].main.root_el);
             console.info('Done loading Clojure app');
-	    delete evalListeners.waitForFinalEval;
+            delete evalListeners.waitForFinalEval;
         }
     };
 
     if (typeof goog === "undefined") {
         console.info('Loading Closure base.');
         interceptRequire();
-	// need to know base path here
+
+        // need to know base path here
         importJs(fileBasePath + '/goog/base.js', function () {
             shimBaseGoog(fileBasePath);
-            importJs(fileBasePath + '/cljs_deps.js');
-            importJs(fileBasePath + '/goog/deps.js', function () {
-                // This is needed because of RN packager
-                // seriously React packager? why.
-                var googreq = goog.require;
-
-                googreq(`env.${platform}.main`);
+            importJs(fileBasePath + '/cljs_deps.js', function () {
+                importJs(fileBasePath + '/goog/deps.js', function () {
+                    importIndexJs(fileBasePath);
+                });
             });
         });
     }
@@ -230,8 +241,8 @@ function withModules(moduleById) {
 
 function figwheelImportScript(uri, callback) {
     importJs(uri.toString(),
-	     function () {callback(true);},
-	     function () {callback(false);})
+        function () {callback(true);},
+        function () {callback(false);})
 }
 
 // Goog fixes
diff --git a/resources/prod.profile b/resources/prod.profile
index 3d73078..448f289 100644
--- a/resources/prod.profile
+++ b/resources/prod.profile
@@ -6,4 +6,5 @@
                                                                    :static-fns    true
                                                                    :optimize-constants true
                                                                    :optimizations :simple
+                                                                   :target :nodejs
                                                                    :closure-defines {"goog.DEBUG" false}}}
\ No newline at end of file
diff --git a/resources/project.clj b/resources/project.clj
index e032a11..afbf978 100644
--- a/resources/project.clj
+++ b/resources/project.clj
@@ -4,7 +4,7 @@
             :license {:name "Eclipse Public License"
                       :url  "http://www.eclipse.org/legal/epl-v10.html"}
             :dependencies [[org.clojure/clojure "1.9.0"]
-                           [org.clojure/clojurescript "1.9.946"]
+                           [org.clojure/clojurescript "1.10.238"]
                            $INTERFACE_DEPS$]
             :plugins [[lein-cljsbuild "1.1.4"]
                       [lein-figwheel "0.5.14"]]