From 53f3fd3a16c32891ff4be5048da41e835ac81fd2 Mon Sep 17 00:00:00 2001 From: Viktor Eriksson Date: Sun, 14 May 2017 17:26:35 +0200 Subject: [PATCH 1/7] Figwheel starting but not app --- build.boot | 9 +- example/.gitignore | 2 + example/app/init.js | 17 +- example/app/js/figwheel-bridge.js | 296 ++++++++++ example/app/js/figwheel-bridge_OLD.js | 304 +++++++++++ example/app/package.json | 4 +- example/app/yarn.lock | 540 +++++++++++++++---- example/boot.properties | 4 +- example/build.boot | 57 +- example/env/dev/env/dev.cljs | 3 + example/env/dev/env/index.cljs | 10 + example/env/dev/env/main.cljs | 18 + example/env/dev/user.clj | 221 ++++++++ example/src/cljsjs/react.cljs | 1 + example/src/cljsjs/react/dom/server.cljs | 1 + example/src/mattsum/simple_example/core.cljs | 20 +- 16 files changed, 1346 insertions(+), 161 deletions(-) create mode 100644 example/app/js/figwheel-bridge.js create mode 100644 example/app/js/figwheel-bridge_OLD.js create mode 100644 example/env/dev/env/dev.cljs create mode 100644 example/env/dev/env/index.cljs create mode 100644 example/env/dev/env/main.cljs create mode 100644 example/env/dev/user.clj create mode 100644 example/src/cljsjs/react.cljs create mode 100644 example/src/cljsjs/react/dom/server.cljs diff --git a/build.boot b/build.boot index 82cdc83..1ac46f4 100644 --- a/build.boot +++ b/build.boot @@ -1,4 +1,3 @@ - (set-env! :resource-paths #{"src" "resources"} :dependencies '[[pandeiro/boot-http "0.7.1-SNAPSHOT" :scope "test"] [com.cemerick/url "0.1.1"] @@ -8,14 +7,14 @@ (partial map (fn [[k v]] [k (cond-> v (#{"clojars"} k) (assoc :username (System/getenv "CLOJARS_USER"), :password (System/getenv "CLOJARS_PASS")))]))) -(def +version+ "0.3-rc1337") +(def +version+ "0.4") (task-options! - pom {:project 'boot-react-native/boot-react-native + pom {:project 'org.clojars.vikeri/boot-react-native :version +version+ :description "Boot tasks to integrate ClojureScript boot tasks (reload, repl, cljs-build) with React Native packager" - :url "https://github.com/mjmeintjes/boot-react-native" - :scm {:url "https://github.com/mjmeintjes/boot-react-native"} + :url "https://github.com/vikeri/boot-react-native" + :scm {:url "https://github.com/vikeri/boot-react-native"} :license {"Eclipse Public License" "http://www.eclipse.org/legal/epl-v10.html"}}) diff --git a/example/.gitignore b/example/.gitignore index e43b0f9..faae347 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -1 +1,3 @@ .DS_Store +.js-modules.edn +figwheel_server.log diff --git a/example/app/init.js b/example/app/init.js index b0dcf2e..5635ff4 100644 --- a/example/app/init.js +++ b/example/app/init.js @@ -1,13 +1,8 @@ -/** - * Sample React Native App - * https://github.com/facebook/react-native - */ - 'use strict'; -// global.window = {}; - -// hack: get reagent to find ReactNative.render as ReactDOM.render -global.ReactDOM = require('react-native'); - -require('./build/main.js'); \ No newline at end of file +// cljsbuild adds a preamble mentioning goog so hack around it +window.goog = { + provide() {}, + require() {}, +}; +require('./target/env/index.js'); diff --git a/example/app/js/figwheel-bridge.js b/example/app/js/figwheel-bridge.js new file mode 100644 index 0000000..04323b5 --- /dev/null +++ b/example/app/js/figwheel-bridge.js @@ -0,0 +1,296 @@ +/* + * 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 () { + console.log("RENDERING", this.state.loaded, ReactNative.View); + if (!this.state.loaded) { + var plainStyle = {flex: 1, alignItems: 'center', justifyContent: 'center'}; + return ( + + Waiting for Figwheel to load files. + + ); + } + return this.state.root; + }, + componentDidMount: function () { + console.log("DID MOUNT"); + 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; + + // callback when app is ready to get the reloadable component + var mainJs = '/env/main.js'; + evalListeners.push(function (url) { + if (url.indexOf(mainJs) > -1) { + onLoadCb(env.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'); + }); + }); + } +} + +function startApp(appName, platform, devHost) { + console.log("Regging comp", appName); + 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