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"]]