├── examples
└── re-frame
│ ├── uiexplorer
│ ├── src
│ │ ├── cljsjs
│ │ │ ├── react.cljs
│ │ │ ├── react
│ │ │ │ ├── dom.cljs
│ │ │ │ └── dom
│ │ │ │ │ └── server.cljs
│ │ │ └── create_react_class.cljs
│ │ ├── uiexplorer
│ │ │ ├── subs.cljs
│ │ │ ├── db.cljs
│ │ │ ├── core.cljs
│ │ │ ├── scenes
│ │ │ │ └── login.cljs
│ │ │ ├── react_requires.cljs
│ │ │ ├── events.cljs
│ │ │ └── routing.cljs
│ │ └── reagent
│ │ │ ├── dom
│ │ │ └── server.cljs
│ │ │ └── dom.cljs
│ ├── .babelrc
│ ├── .projectile
│ ├── env
│ │ ├── prod
│ │ │ └── env
│ │ │ │ └── main.cljs
│ │ └── dev
│ │ │ ├── env
│ │ │ └── main.cljs
│ │ │ ├── externs.clj
│ │ │ └── user.clj
│ ├── assets
│ │ ├── icons
│ │ │ ├── app.png
│ │ │ └── loading.png
│ │ └── images
│ │ │ ├── cljs.png
│ │ │ ├── cljs@2x.png
│ │ │ └── cljs@3x.png
│ ├── .gitignore
│ ├── package.json
│ ├── README.md
│ ├── app.json
│ ├── project.clj
│ ├── js
│ │ └── figwheel-bridge.js
│ └── LICENSE
│ └── expo-example
│ ├── src
│ ├── cljsjs
│ │ ├── react.cljs
│ │ ├── react
│ │ │ ├── dom.cljs
│ │ │ └── dom
│ │ │ │ └── server.cljs
│ │ └── create_react_class.cljs
│ ├── expo_example
│ │ ├── subs.cljs
│ │ ├── db.cljs
│ │ ├── handlers.cljs
│ │ └── core.cljs
│ └── reagent
│ │ ├── dom
│ │ └── server.cljs
│ │ └── dom.cljs
│ ├── .babelrc
│ ├── .projectile
│ ├── env
│ ├── prod
│ │ └── env
│ │ │ └── main.cljs
│ └── dev
│ │ ├── env
│ │ └── main.cljs
│ │ ├── externs.clj
│ │ └── user.clj
│ ├── assets
│ ├── icons
│ │ ├── app.png
│ │ └── loading.png
│ └── images
│ │ ├── cljs.png
│ │ ├── cljs@2x.png
│ │ └── cljs@3x.png
│ ├── .gitignore
│ ├── package.json
│ ├── app.json
│ ├── readme.md
│ ├── build.boot
│ ├── project.clj
│ ├── js
│ └── figwheel-bridge.js
│ └── LICENSE
├── CHANGELOG.md
├── doc
└── intro.md
├── .gitignore
├── test
└── cljs_react_navigation
│ └── core_test.clj
├── project.clj
├── LICENSE
├── src
└── cljs_react_navigation
│ ├── reagent.cljs
│ ├── re_frame.cljs
│ └── base.cljs
└── README.md
/examples/re-frame/uiexplorer/src/cljsjs/react.cljs:
--------------------------------------------------------------------------------
1 | (ns cljsjs.react)
2 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/src/cljsjs/react.cljs:
--------------------------------------------------------------------------------
1 | (ns cljsjs.react)
2 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/src/cljsjs/react/dom.cljs:
--------------------------------------------------------------------------------
1 | (ns cljsjs.react.dom)
2 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/src/cljsjs/react/dom.cljs:
--------------------------------------------------------------------------------
1 | (ns cljsjs.react.dom)
2 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["babel-preset-expo"]
3 | }
4 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["babel-preset-expo"]
3 | }
4 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | ## [0.1.1] - 2017-05-15
3 | ### Changed
4 | - Initial check-in
5 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/src/cljsjs/react/dom/server.cljs:
--------------------------------------------------------------------------------
1 | (ns cljsjs.react.dom.server)
2 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/src/cljsjs/create_react_class.cljs:
--------------------------------------------------------------------------------
1 | (ns cljsjs.create-react-class)
2 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/src/cljsjs/react/dom/server.cljs:
--------------------------------------------------------------------------------
1 | (ns cljsjs.react.dom.server)
2 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/src/cljsjs/create_react_class.cljs:
--------------------------------------------------------------------------------
1 | (ns cljsjs.create-react-class)
2 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/.projectile:
--------------------------------------------------------------------------------
1 | -/node_modules
2 | -/target
3 | -/.git
4 | -/.exponent
5 | -/figwheel_server.log
6 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/.projectile:
--------------------------------------------------------------------------------
1 | -/node_modules
2 | -/target
3 | -/.git
4 | -/.exponent
5 | -/figwheel_server.log
6 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/env/prod/env/main.cljs:
--------------------------------------------------------------------------------
1 | (ns env.main
2 | (:require [expo-example.core :as core]))
3 |
4 | (core/init)
5 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/env/prod/env/main.cljs:
--------------------------------------------------------------------------------
1 | (ns env.main
2 | (:require [uiexplorer.core :as core]))
3 |
4 | (core/init)
5 |
--------------------------------------------------------------------------------
/doc/intro.md:
--------------------------------------------------------------------------------
1 | # Introduction to cljs-react-navigation
2 |
3 | TODO: write [great documentation](http://jacobian.org/writing/what-to-write/)
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /target
2 | /classes
3 | /checkouts
4 | pom.xml
5 | pom.xml.asc
6 | *.jar
7 | *.class
8 | /.lein-*
9 | /.nrepl-port
10 | .hgignore
11 | .hg/
12 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/assets/icons/app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seantempesta/cljs-react-navigation/HEAD/examples/re-frame/uiexplorer/assets/icons/app.png
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/assets/icons/app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seantempesta/cljs-react-navigation/HEAD/examples/re-frame/expo-example/assets/icons/app.png
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/assets/images/cljs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seantempesta/cljs-react-navigation/HEAD/examples/re-frame/uiexplorer/assets/images/cljs.png
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/assets/images/cljs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seantempesta/cljs-react-navigation/HEAD/examples/re-frame/expo-example/assets/images/cljs.png
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/assets/icons/loading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seantempesta/cljs-react-navigation/HEAD/examples/re-frame/uiexplorer/assets/icons/loading.png
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/assets/images/cljs@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seantempesta/cljs-react-navigation/HEAD/examples/re-frame/uiexplorer/assets/images/cljs@2x.png
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/assets/images/cljs@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seantempesta/cljs-react-navigation/HEAD/examples/re-frame/uiexplorer/assets/images/cljs@3x.png
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/assets/icons/loading.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seantempesta/cljs-react-navigation/HEAD/examples/re-frame/expo-example/assets/icons/loading.png
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/assets/images/cljs@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seantempesta/cljs-react-navigation/HEAD/examples/re-frame/expo-example/assets/images/cljs@2x.png
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/assets/images/cljs@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/seantempesta/cljs-react-navigation/HEAD/examples/re-frame/expo-example/assets/images/cljs@3x.png
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/src/uiexplorer/subs.cljs:
--------------------------------------------------------------------------------
1 | (ns uiexplorer.subs
2 | (:require [re-frame.core :refer [reg-sub]]))
3 |
4 | (reg-sub
5 | :get-greeting
6 | (fn [db _]
7 | (:greeting db)))
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/src/expo_example/subs.cljs:
--------------------------------------------------------------------------------
1 | (ns expo-example.subs
2 | (:require [re-frame.core :refer [reg-sub]]))
3 |
4 | (reg-sub
5 | :get-greeting
6 | (fn [db _]
7 | (:greeting db)))
8 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/src/reagent/dom/server.cljs:
--------------------------------------------------------------------------------
1 | (ns reagent.dom.server)
2 | ;; Shimmed namespace to make reagent 0.6.0 work with react native packager
3 |
4 | (defn render-to-string [_])
5 |
6 | (defn render-to-static-markup [_])
7 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/src/reagent/dom/server.cljs:
--------------------------------------------------------------------------------
1 | (ns reagent.dom.server)
2 | ;; Shimmed namespace to make reagent 0.6.0 work with react native packager
3 |
4 | (defn render-to-string [_])
5 |
6 | (defn render-to-static-markup [_])
7 |
--------------------------------------------------------------------------------
/test/cljs_react_navigation/core_test.clj:
--------------------------------------------------------------------------------
1 | (ns cljs-react-navigation.core-test
2 | (:require [clojure.test :refer :all]
3 | [cljs-react-navigation.core :refer :all]))
4 |
5 | (deftest a-test
6 | (testing "FIXME, I fail."
7 | (is (= 0 1))))
8 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/src/reagent/dom.cljs:
--------------------------------------------------------------------------------
1 | (ns reagent.dom)
2 | ;; Shimmed namespace to make reagent 0.6.0 work with react native packager
3 |
4 | (defn render
5 | ([_ _])
6 | ([_ _ _]))
7 | (defn unmount-component-at-node [_])
8 |
9 | (defn dom-node [_])
10 |
11 | (defn force-update-all [])
12 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/src/reagent/dom.cljs:
--------------------------------------------------------------------------------
1 | (ns reagent.dom)
2 | ;; Shimmed namespace to make reagent 0.6.0 work with react native packager
3 |
4 | (defn render
5 | ([_ _])
6 | ([_ _ _]))
7 | (defn unmount-component-at-node [_])
8 |
9 | (defn dom-node [_])
10 |
11 | (defn force-update-all [])
12 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/src/expo_example/db.cljs:
--------------------------------------------------------------------------------
1 | (ns expo-example.db
2 | (:require [clojure.spec.alpha :as s]))
3 |
4 | ;; spec of app-db
5 | (s/def ::greeting string?)
6 | (s/def ::app-db
7 | (s/keys :req-un [::greeting]))
8 |
9 | ;; initial state of app-db
10 | (def app-db {:greeting "Hello Clojurescript in Expo!"})
11 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/src/uiexplorer/db.cljs:
--------------------------------------------------------------------------------
1 | (ns uiexplorer.db
2 | (:require [clojure.spec.alpha :as s]))
3 |
4 | ;; spec of app-db
5 | (s/def ::greeting string?)
6 | (s/def ::app-db
7 | (s/keys :req-un [::greeting]))
8 |
9 | ;; initial state of app-db
10 | (def app-db {:greeting "Hello Clojure in iOS and Android!"})
11 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | /target
5 | /classes
6 | /checkouts
7 | pom.xml
8 | pom.xml.asc
9 | *.jar
10 | *.class
11 | /.lein-*
12 | /.nrepl-port
13 | .hgignore
14 | .hg/
15 | figwheel_server.log
16 | main.js
17 | .js-modules.edn
18 | /env/dev/env/dev.cljs
19 | /env/dev/env/index.cljs
20 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/**/*
2 | .expo/*
3 | npm-debug.*
4 | /target
5 | /classes
6 | /checkouts
7 | pom.xml
8 | pom.xml.asc
9 | *.jar
10 | *.class
11 | /.lein-*
12 | /.nrepl-port
13 | .hgignore
14 | .hg/
15 | figwheel_server.log
16 | main.js
17 | .js-modules.edn
18 | /env/dev/env/dev.cljs
19 | /env/dev/env/index.cljs
20 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "expo-example",
3 | "version": "0.0.1",
4 | "description": "",
5 | "author": "",
6 | "private": true,
7 | "main": "main.js",
8 | "dependencies": {
9 | "expo": "^22.0.0",
10 | "react": "16.0.0-beta.5",
11 | "react-native": "https://github.com/expo/react-native/archive/sdk-22.0.1.tar.gz",
12 | "create-react-class": "15.6.0",
13 | "react-navigation": "1.0.0-beta.12"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "uiexplorer",
3 | "version": "0.0.1",
4 | "description": "",
5 | "author": "",
6 | "private": true,
7 | "main": "main.js",
8 | "dependencies": {
9 |
10 |
11 | "expo": "^22.0.0",
12 | "react": "16.0.0-beta.5",
13 | "react-native": "https://github.com/expo/react-native/archive/sdk-22.0.1.tar.gz",
14 |
15 |
16 |
17 | "create-react-class": "15.6.0",
18 |
19 |
20 | "@expo/vector-icons": "6.1.0",
21 |
22 | "react-navigation": "^1.0.0-beta.12"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/env/dev/env/main.cljs:
--------------------------------------------------------------------------------
1 | (ns ^:figwheel-no-load env.main
2 | (:require [reagent.core :as r]
3 | [uiexplorer.core :as core]
4 | [figwheel.client :as figwheel :include-macros true]
5 | [env.dev]))
6 |
7 | (enable-console-print!)
8 |
9 | (def cnt (r/atom 0))
10 | (defn reloader [] @cnt [core/app-root])
11 | (def root-el (r/as-element [reloader]))
12 |
13 | (figwheel/watch-and-reload
14 | :websocket-url (str "ws://" env.dev/ip ":3449/figwheel-ws")
15 | :heads-up-display false
16 | :jsload-callback #(swap! cnt inc))
17 |
18 | (core/init)
19 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/env/dev/env/main.cljs:
--------------------------------------------------------------------------------
1 | (ns ^:figwheel-no-load env.main
2 | (:require [reagent.core :as r]
3 | [expo-example.core :as core]
4 | [figwheel.client :as figwheel :include-macros true]
5 | [env.dev]))
6 |
7 | (enable-console-print!)
8 |
9 | (def cnt (r/atom 0))
10 | (defn reloader [] @cnt [core/app-root])
11 | (def root-el (r/as-element [reloader]))
12 |
13 | (figwheel/watch-and-reload
14 | :websocket-url (str "ws://" env.dev/ip ":3449/figwheel-ws")
15 | :heads-up-display false
16 | :jsload-callback #(swap! cnt inc))
17 |
18 | (core/init)
19 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/README.md:
--------------------------------------------------------------------------------
1 | ## Re-frame demo of cljs-react-navigation
2 |
3 | ### To run
4 |
5 | #### Install [Lein](http://leiningen.org/#install)
6 |
7 | #### Install [Expo cli client](https://docs.expo.io/versions/latest/introduction/installation.html)
8 | ``` shell
9 | yarn global add exp
10 | ```
11 |
12 | #### Install npm modules
13 |
14 | ``` shell
15 | yarn install
16 | ```
17 |
18 | #### Start the figwheel server and cljs repl
19 | ``` shell
20 | lein figwheel
21 | ```
22 |
23 | #### In a new console tab, run expo
24 | ``` shell
25 | exp start --host lan --ios
26 | # or
27 | exp start --host lan --android
28 | ```
29 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/src/uiexplorer/core.cljs:
--------------------------------------------------------------------------------
1 | (ns uiexplorer.core
2 | (:require [reagent.core :as r :refer [atom]]
3 | [re-frame.core :refer [subscribe dispatch dispatch-sync]]
4 | [uiexplorer.react-requires :refer [Expo]]
5 | [uiexplorer.routing :as routing]
6 | [uiexplorer.events]
7 | [uiexplorer.subs]))
8 |
9 | (def app-root routing/app-root)
10 |
11 | (defn init []
12 | (aset js/console "disableYellowBox" true)
13 | (dispatch-sync [:initialize-db])
14 | (.registerRootComponent Expo (r/reactify-component routing/app-root))
15 | ;; (.registerComponent AppRegistry "UIExplorer" #(r/reactify-component routing/app-root))
16 | )
17 |
--------------------------------------------------------------------------------
/project.clj:
--------------------------------------------------------------------------------
1 | (defproject cljs-react-navigation "0.1.3"
2 | :description "CLJS Wrappers for react-navigation"
3 | :url "https://github.com/seantempesta/cljs-react-navigation"
4 | :license {:name "MIT"
5 | :url "https://opensource.org/licenses/MIT"}
6 | :dependencies [[org.clojure/clojure "1.9.0"]
7 | [org.clojure/clojurescript "1.9.946"]
8 | [reagent "0.7.0" :exclusions [cljsjs/react
9 | cljsjs/react-dom
10 | cljsjs/react-dom-server
11 | cljsjs/create-react-class]]
12 | [re-frame "0.10.4"]]
13 | :plugins [[lein-codox "0.10.3"]]
14 | :codox {:language :clojurescript}
15 | :source-paths ["src"])
16 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "uiexplorer",
4 | "description": "No description",
5 | "slug": "uiexplorer",
6 | "sdkVersion": "22.0.0",
7 | "version": "1.0.0",
8 | "orientation": "portrait",
9 | "primaryColor": "#cccccc",
10 | "privacy": "public",
11 | "icon": "./assets/icons/app.png",
12 | "notification": {
13 | "icon": "./assets/icons/loading.png",
14 | "color": "#000000"
15 | },
16 | "loading": {
17 | "icon": "https://s3.amazonaws.com/exp-brand-assets/ExponentEmptyManifest_192.png",
18 | "hideExponentText": false
19 | },
20 | "packagerOpts": {
21 | "assetExts": [
22 | "ttf",
23 | "otf"
24 | ],
25 | "nonPersistent": ""
26 | },
27 | "ios": {
28 | "supportsTablet": true
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "expo": {
3 | "name": "expo-example",
4 | "description": "No description",
5 | "slug": "expo-example",
6 | "sdkVersion": "22.0.0",
7 | "version": "1.0.0",
8 | "orientation": "portrait",
9 | "primaryColor": "#cccccc",
10 | "privacy": "public",
11 | "icon": "./assets/icons/app.png",
12 | "notification": {
13 | "icon": "./assets/icons/loading.png",
14 | "color": "#000000"
15 | },
16 | "loading": {
17 | "icon": "https://s3.amazonaws.com/exp-brand-assets/ExponentEmptyManifest_192.png",
18 | "hideExponentText": false
19 | },
20 | "packagerOpts": {
21 | "assetExts": [
22 | "ttf",
23 | "otf"
24 | ],
25 | "nonPersistent": ""
26 | },
27 | "ios": {
28 | "supportsTablet": true
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2017 Sean Tempesta
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/src/expo_example/handlers.cljs:
--------------------------------------------------------------------------------
1 | (ns expo-example.handlers
2 | (:require
3 | [re-frame.core :refer [reg-event-db ->interceptor]]
4 | [clojure.spec.alpha :as s]
5 | [expo-example.db :as db :refer [app-db]]))
6 |
7 | ;; -- Interceptors ----------------------------------------------------------
8 | ;;
9 | ;; See https://github.com/Day8/re-frame/blob/develop/docs/Interceptors.md
10 | ;;
11 | (defn check-and-throw
12 | "Throw an exception if db doesn't have a valid spec."
13 | [spec db]
14 | (when-not (s/valid? spec db)
15 | (let [explain-data (s/explain-data spec db)]
16 | (throw (ex-info (str "Spec check failed: " explain-data) explain-data)))))
17 |
18 | (def validate-spec
19 | (if goog.DEBUG
20 | (->interceptor
21 | :id :validate-spec
22 | :after (fn [context]
23 | (let [db (-> context :effects :db)]
24 | (check-and-throw ::db/app-db db)
25 | context)))
26 | ->interceptor))
27 |
28 | ;; -- Handlers --------------------------------------------------------------
29 |
30 | (reg-event-db
31 | :initialize-db
32 | [validate-spec]
33 | (fn [_ _]
34 | app-db))
35 |
36 | (reg-event-db
37 | :set-greeting
38 | [validate-spec]
39 | (fn [db [_ value]]
40 | (assoc db :greeting value)))
41 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/src/expo_example/core.cljs:
--------------------------------------------------------------------------------
1 | (ns expo-example.core
2 | (:require [reagent.core :as r :refer [atom]]
3 | [re-frame.core :refer [subscribe dispatch dispatch-sync]]
4 | [expo-example.handlers]
5 | [expo-example.subs]
6 | [cljs-react-navigation.base :as base]))
7 |
8 | (def ReactNative (js/require "react-native"))
9 | (def ReactNavigation (js/require "react-navigation"))
10 |
11 | (def app-registry (.-AppRegistry ReactNative))
12 | (def text (r/adapt-react-class (.-Text ReactNative)))
13 | (def view (r/adapt-react-class (.-View ReactNative)))
14 | (def image (r/adapt-react-class (.-Image ReactNative)))
15 | (def touchable-highlight (r/adapt-react-class (.-TouchableHighlight ReactNative)))
16 | (def Alert (.-Alert ReactNative))
17 |
18 | (defn alert [title]
19 | (.alert Alert title))
20 |
21 | (defn app-root []
22 | (let [greeting (subscribe [:get-greeting])]
23 | (fn []
24 | [view {:style {:flex-direction "column" :margin 40 :align-items "center"}}
25 | [image {:source (js/require "./assets/images/cljs.png")
26 | :style {:width 200
27 | :height 200}}]
28 | [text {:style {:font-size 30 :font-weight "100" :margin-bottom 20 :text-align "center"}} @greeting]
29 | [touchable-highlight {:style {:background-color "#999" :padding 10 :border-radius 5}
30 | :on-press #(alert "HELLO!")}
31 | [text {:style {:color "white" :text-align "center" :font-weight "bold"}} "press me!"]]])))
32 |
33 | (defn init []
34 | (dispatch-sync [:initialize-db])
35 | (.registerComponent app-registry "main" #(r/reactify-component app-root)))
36 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/readme.md:
--------------------------------------------------------------------------------
1 | ## expo-example
2 |
3 | ### Usage
4 |
5 | #### Install Expo [XDE and mobile client](https://docs.expo.io/versions/v15.0.0/introduction/installation.html)
6 | If you don't want to use XDE (not IDE, it stands for Expo Development Tools), you can use [exp CLI](https://docs.expo.io/versions/v15.0.0/guides/exp-cli.html).
7 |
8 | ``` shell
9 | yarn global add exp
10 | ```
11 |
12 | #### Install [Lein](http://leiningen.org/#install) or [Boot](https://github.com/boot-clj/boot)
13 |
14 | #### Install npm modules
15 |
16 | ``` shell
17 | yarn install
18 | ```
19 |
20 | #### Signup using exp CLI
21 |
22 | ``` shell
23 | exp signup
24 | ```
25 |
26 | #### Start the figwheel server and cljs repl
27 |
28 | ##### leiningen users
29 | ``` shell
30 | lein figwheel
31 | ```
32 |
33 | ##### boot users
34 | ``` shell
35 | boot dev
36 |
37 | ;; then input (cljs-repl) in the connected clojure repl to connect to boot cljs repl
38 | ```
39 |
40 | #### Start Exponent server (Using `exp`)
41 |
42 | ##### Also connect to Android device
43 |
44 | ``` shell
45 | exp start -a --lan
46 | ```
47 |
48 | ##### Also connect to iOS Simulator
49 |
50 | ``` shell
51 | exp start -i --lan
52 | ```
53 |
54 | ### Add new assets or external modules
55 | 1. `require` module:
56 |
57 | ``` clj
58 | (def cljs-logo (js/require "./assets/images/cljs.png"))
59 | (def FontAwesome (js/require "@expo/vector-icons/FontAwesome"))
60 | ```
61 | 2. Reload simulator or device
62 |
63 | ### Make sure you disable live reload from the Developer Menu, also turn off Hot Module Reload.
64 | Since Figwheel already does those.
65 |
66 | ### Production build (generates js/externs.js and main.js)
67 |
68 | #### leiningen users
69 | ``` shell
70 | lein prod-build
71 | ```
72 |
73 | #### boot users
74 | ``` shell
75 | boot prod
76 | ```
77 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/src/uiexplorer/scenes/login.cljs:
--------------------------------------------------------------------------------
1 | (ns uiexplorer.scenes.login
2 | (:require [uiexplorer.react-requires :refer [ActivityIndicator Platform Button TouchableOpacity Ionicons InteractionManager View ScrollView Text TouchableHighlight]]
3 | [cljs-react-navigation.re-frame :refer [stack-navigator tab-navigator stack-screen tab-screen router]]
4 | [reagent.core :as r]
5 | [re-frame.core :refer [subscribe dispatch dispatch-sync]]))
6 |
7 | (def static-navigationOptions {:headerTitle "Login"
8 | :headerRight (fn []
9 | [:> Button {:title "Sign In"
10 | :onPress #(dispatch [:login])}])})
11 |
12 | (defn dynamic-navigationOptions [{:keys [navigation] :as props}]
13 | (let [navigate (:navigate navigation)]
14 | {:headerTitle "Login"
15 | :headerRight (fn []
16 | [:> Button {:title "Sign In"
17 | :onPress #(do (dispatch [:login])
18 | (navigate "Loading"))}])}))
19 |
20 | (defn login1 [{:keys [screenProps navigation] :as props}]
21 | (let [navigate (:navigate navigation)]
22 | (fn [props]
23 | [:> View {:style {:flex 1
24 | :alignItems "center"
25 | :justifyContent "center"}}
26 | [:> Button {:style {:fontSize 17}
27 | :onPress #(do (dispatch [:login])
28 | (navigate "Loading"))
29 | :title "Click to Login!"}]])))
30 |
31 | (defn loading [props]
32 | (fn [props]
33 | [:> View {:style {:flex 1
34 | :backgroundColor "#333333"
35 | :alignItems "center"
36 | :justifyContent "center"}}
37 | [:> ActivityIndicator
38 | {:animating true
39 | :style {:alignItems "center"
40 | :justifyContent "center"
41 | :height 80}
42 | :size "large"}]]))
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/build.boot:
--------------------------------------------------------------------------------
1 | (set-env!
2 | :source-paths #{"src" "env/dev"}
3 | :dependencies '[[ajchemist/boot-figwheel "0.5.4-6" :scope "test"] ;; latest release
4 | [org.clojure/tools.nrepl "0.2.12" :scope "test"]
5 | [com.cemerick/piggieback "0.2.1" :scope "test"]
6 | [figwheel-sidecar "0.5.4-7" :scope "test"]
7 | [react-native-externs "0.0.2-SNAPSHOT" :scope "test"]
8 |
9 | [org.clojure/clojure "1.9.0-alpha16"]
10 | [org.clojure/clojurescript "1.9.542"]
11 | [org.clojure/core.async "0.3.442"]
12 | [reagent "0.6.1" :exclusions [cljsjs/react cljsjs/react-dom cljsjs/react-dom-server]]
13 | [re-frame "0.9.3"]])
14 |
15 | (require
16 | '[boot-figwheel :refer [figwheel cljs-repl]]
17 | '[cljs.build.api :as b]
18 | '[user :as user]
19 | '[externs :as externs])
20 |
21 | (require 'boot.repl)
22 | (swap! boot.repl/*default-middleware*
23 | conj 'cemerick.piggieback/wrap-cljs-repl)
24 |
25 | (deftask dev
26 | "boot dev, then input (cljs-repl)"
27 | []
28 | (user/prepare)
29 |
30 | (comp
31 | (figwheel
32 | :build-ids ["main"]
33 | :all-builds [{:id "main"
34 | :source-paths ["src" "env/dev"]
35 | :figwheel true
36 | :compiler {:output-to "not-used.js"
37 | :main "env.main"
38 | :optimizations :none
39 | :output-dir "."}}]
40 | :figwheel-options {:open-file-command "emacsclient"
41 | :validate-config false})
42 | (repl)))
43 |
44 | (deftask prod
45 | []
46 | (externs/-main)
47 |
48 | (println "Start to compile clojurescript ...")
49 | (let [start (System/nanoTime)]
50 | (b/build ["src" "env/prod"]
51 | {:output-to "main.js"
52 | :main "env.main"
53 | :output-dir "target"
54 | :static-fns true
55 | :externs ["js/externs.js"]
56 | :parallel-build true
57 | :optimize-constants true
58 | :optimizations :advanced
59 | :closure-defines {"goog.DEBUG" false}})
60 | (println "... done. Elapsed" (/ (- (System/nanoTime) start) 1e9) "seconds")))
61 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/src/uiexplorer/react_requires.cljs:
--------------------------------------------------------------------------------
1 | (ns uiexplorer.react-requires)
2 |
3 | ; react-native
4 | (set! js/ReactNative (js/require "react-native"))
5 | (defonce Modal (.-Modal js/ReactNative))
6 | (defonce Animated ^js/ReactNative.Animated (.-Animated js/ReactNative))
7 | (defonce AnimatedValue ^js/ReactNative.Animated.Value (.-Value Animated))
8 | (defonce AnimatedImage (aget Animated "Image"))
9 | (defonce Dimensions (aget js/ReactNative "Dimensions"))
10 | (defonce ListView (aget js/ReactNative "ListView"))
11 | (defonce DataSource (aget ListView "DataSource"))
12 | (defonce Image (aget js/ReactNative "Image"))
13 | (defonce AppRegistry (aget js/ReactNative "AppRegistry"))
14 | (defonce InteractionManager (aget js/ReactNative "InteractionManager"))
15 | (defonce Platform (aget js/ReactNative "Platform"))
16 | (defonce Linking (aget js/ReactNative "Linking"))
17 | (defonce LayoutAnimation (aget js/ReactNative "LayoutAnimation"))
18 | (defonce Keyboard (aget js/ReactNative "Keyboard"))
19 | (defonce KeyboardAvoidingView (aget js/ReactNative "KeyboardAvoidingView"))
20 | (defonce Picker (aget js/ReactNative "Picker"))
21 | (defonce PickerItem (aget Picker "Item"))
22 | (defonce Text (aget js/ReactNative "Text"))
23 | (defonce TextInput (aget js/ReactNative "TextInput"))
24 | (defonce Button (aget js/ReactNative "Button"))
25 | (defonce View (aget js/ReactNative "View"))
26 | (defonce ScrollView (aget js/ReactNative "ScrollView"))
27 | (defonce Image (aget js/ReactNative "Image"))
28 | (defonce AnimatedImage (aget js/ReactNative "AnimatedImage"))
29 | (defonce TouchableOpacity (aget js/ReactNative "TouchableOpacity"))
30 | (defonce TouchableHighlight (aget js/ReactNative "TouchableHighlight"))
31 | (defonce AsyncStorage (aget js/ReactNative "AsyncStorage"))
32 | (defonce ListView (aget js/ReactNative "ListView"))
33 | (defonce TouchableOpacity (aget js/ReactNative "TouchableOpacity"))
34 | (defonce Alert (aget js/ReactNative "Alert"))
35 | (defonce AppState ^js/ReactNative.AppState (.-AppState js/ReactNative))
36 | (defonce ActivityIndicator (aget js/ReactNative "ActivityIndicator"))
37 | (defonce VirtualizedList (.-VirtualizedList js/ReactNative))
38 | (defonce DatePickerIOS (aget js/ReactNative "DatePickerIOS"))
39 | (defonce DatePickerAndroid (aget js/ReactNative "DatePickerAndroid"))
40 | (defonce Expo (js/require "expo"))
41 |
42 | ; react-native-vector-icons
43 | (defonce Ionicons (.-Ionicons (js/require "@expo/vector-icons")))
44 |
45 | ; react-navigation
46 | (defonce ReactNavigation (js/require "react-navigation"))
47 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/project.clj:
--------------------------------------------------------------------------------
1 | (defproject expo-example "0.1.0-SNAPSHOT"
2 | :description "FIXME: write description"
3 | :url "http://example.com/FIXME"
4 | :license {:name "Eclipse Public License"
5 | :url "http://www.eclipse.org/legal/epl-v10.html"}
6 | :dependencies [[org.clojure/clojure "1.9.0-alpha16"]
7 | [org.clojure/clojurescript "1.9.854"]
8 | [reagent "0.7.0" :exclusions [cljsjs/react cljsjs/react-dom cljsjs/react-dom-server cljsjs/create-react-class]]
9 | [re-frame "0.9.3"]
10 | [react-native-externs "0.1.0"]]
11 | :plugins [[lein-cljsbuild "1.1.4"]
12 | [lein-figwheel "0.5.11"]]
13 | :clean-targets ["target/" "main.js"]
14 | :aliases {"figwheel" ["run" "-m" "user" "--figwheel"]
15 | "externs" ["do" "clean"
16 | ["run" "-m" "externs"]]
17 | "rebuild-modules" ["run" "-m" "user" "--rebuild-modules"]
18 | "prod-build" ^{:doc "Recompile code with prod profile."}
19 | ["externs"
20 | ["with-profile" "prod" "cljsbuild" "once" "main"]]}
21 | :jvm-opts ["--add-modules" "java.xml.bind"]
22 | :profiles {:dev {:dependencies [[figwheel-sidecar "0.5.10"]
23 | [com.cemerick/piggieback "0.2.1"]]
24 | :source-paths ["src" "env/dev"]
25 | :cljsbuild {:builds [{:id "main"
26 | :source-paths ["src" "env/dev" "../../../src/"]
27 | :figwheel true
28 | :compiler {:output-to "target/not-used.js"
29 | :main "env.main"
30 | :output-dir "target"
31 | :optimizations :none}}]}
32 | :repl-options {:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}}
33 | :prod {:cljsbuild {:builds [{:id "main"
34 | :source-paths ["src" "env/prod" "../../../src/"]
35 | :compiler {:output-to "main.js"
36 | :main "env.main"
37 | :output-dir "target"
38 | :static-fns true
39 | :externs ["js/externs.js"]
40 | :parallel-build true
41 | :optimize-constants true
42 | :optimizations :advanced
43 | :closure-defines {"goog.DEBUG" false}}}]}}})
44 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/project.clj:
--------------------------------------------------------------------------------
1 | (defproject uiexplorer "0.1.0-SNAPSHOT"
2 | :description "FIXME: write description"
3 | :url "http://example.com/FIXME"
4 | :license {:name "Eclipse Public License"
5 | :url "http://www.eclipse.org/legal/epl-v10.html"}
6 | :dependencies [[org.clojure/clojure "1.9.0-alpha16"]
7 | [org.clojure/clojurescript "1.9.854"]
8 | [reagent "0.7.0" :exclusions [cljsjs/react cljsjs/react-dom cljsjs/react-dom-server cljsjs/create-react-class]]
9 | [re-frame "0.9.3"]
10 | [cljs-react-navigation "0.1.0"]
11 | [react-native-externs "0.1.0"]]
12 | :plugins [[lein-cljsbuild "1.1.4"]
13 | [lein-figwheel "0.5.11"]]
14 | :clean-targets ["target/" "main.js"]
15 | :aliases {"figwheel" ["run" "-m" "user" "--figwheel"]
16 | "externs" ["do" "clean"
17 | ["run" "-m" "externs"]]
18 | "rebuild-modules" ["run" "-m" "user" "--rebuild-modules"]
19 | "prod-build" ^{:doc "Recompile code with prod profile."}
20 | ["externs"
21 | ["with-profile" "prod" "cljsbuild" "once" "main"]]}
22 |
23 | :jvm-opts ["--add-modules" "java.xml.bind"]
24 |
25 | :profiles {:dev {:dependencies [[figwheel-sidecar "0.5.10"]
26 | [com.cemerick/piggieback "0.2.1"]]
27 | :source-paths ["src" "env/dev"]
28 | :cljsbuild {:builds [{:id "main"
29 | :source-paths ["src" "env/dev"]
30 | :figwheel true
31 | :compiler {:output-to "target/not-used.js"
32 | :main "env.main"
33 | :output-dir "target"
34 | :optimizations :none}}]}
35 | :repl-options {:nrepl-middleware [cemerick.piggieback/wrap-cljs-repl]}}
36 | :prod {:cljsbuild {:builds [{:id "main"
37 | :source-paths ["src" "env/prod"]
38 | :compiler {:output-to "main.js"
39 | :main "env.main"
40 | :output-dir "target"
41 | :static-fns true
42 | :externs ["js/externs.js"]
43 | :parallel-build true
44 | :optimize-constants true
45 | :optimizations :advanced
46 | :closure-defines {"goog.DEBUG" false}}}]}}})
47 |
--------------------------------------------------------------------------------
/src/cljs_react_navigation/reagent.cljs:
--------------------------------------------------------------------------------
1 | (ns cljs-react-navigation.reagent
2 | (:require [cljs-react-navigation.base :as base]
3 | [reagent.core :as r]
4 | [reagent.impl.component :as ric]
5 | [cljs.spec.alpha :as s :include-macros true]))
6 |
7 |
8 | (defn react-component?
9 | "Same as base, but now accepts a reagent component fn"
10 | [c]
11 | (cond
12 | (ric/react-class? c) c
13 | (fn? c) (r/reactify-component
14 | (fn [props & children]
15 | [c (js->clj props :keywordize-keys true) children]))
16 | :else :cljs.spec.alpha/invalid))
17 |
18 | (defn react-element?
19 | "Same as base, but now accepts a reagent component fn"
20 | [e]
21 | (cond
22 | (base/isValidElement e) e
23 | (ric/react-class? e) (r/create-element e)
24 | (fn? e) (r/create-element
25 | (r/reactify-component
26 | (fn [props & children]
27 | [e (js->clj props :keywordize-keys true) children])))
28 | :else :cljs.spec.alpha/invalid))
29 |
30 | (defn fn-or-react-component?
31 | "Same as base, but now *expects* a reagent component if a fn is supplied"
32 | [fn-or-c]
33 | (cond
34 | (ric/react-class? fn-or-c) fn-or-c
35 | (fn? fn-or-c) (fn [props & children]
36 | (let [clj-props (js->clj props :keywordize-keys true)]
37 | (r/reactify-component (fn-or-c clj-props children))))
38 | :else :cljs.spec.alpha/invalid))
39 |
40 | (defn fn-or-react-element?
41 | "Same as base, but now *expects* a reagent component if a fn is supplied"
42 | [fn-or-e]
43 | (cond
44 | (base/isValidElement fn-or-e) fn-or-e
45 | (ric/react-class? fn-or-e) (r/create-element fn-or-e)
46 | (fn? fn-or-e) (fn [props & children]
47 | (let [clj-props (js->clj props :keywordize-keys true)]
48 | (r/as-element [fn-or-e clj-props children])))
49 | :else :cljs.spec.alpha/invalid))
50 |
51 | (defn string-or-react-element? [s-or-e]
52 | (cond
53 | (base/isValidElement s-or-e) s-or-e
54 | (ric/react-class? s-or-e) (r/create-element s-or-e)
55 | (fn? s-or-e) (r/as-element [(fn [props & children]
56 | (let [clj-props (js->clj props :keywordize-keys true)]
57 | [s-or-e clj-props children]))])
58 | (string? s-or-e) s-or-e
59 | :else :cljs.spec.alpha/invalid))
60 |
61 | ;; Spec overrides for Reagent Components
62 | (s/def :react/component (s/conformer react-component?))
63 | (s/def :react/element (s/conformer react-element?))
64 | (s/def :react-navigation.navigationOptions/headerTitle (s/conformer string-or-react-element?))
65 | (s/def :react-navigation.navigationOptions/headerLeft (s/conformer string-or-react-element?))
66 | (s/def :react-navigation.navigationOptions/headerRight (s/conformer string-or-react-element?))
67 | (s/def :react-navigation.navigationOptions/tabBarIcon (s/conformer fn-or-react-element?))
68 | (s/def :react-navigation.RouteConfigs.route/screen (s/conformer fn-or-react-component?))
69 |
70 | ;; API
71 | (def NavigationActionsMap base/NavigationActionsMap)
72 | (def stack-screen base/stack-screen)
73 | (def tab-screen base/tab-screen)
74 | (def drawer-component base/drawer-component)
75 | (def stack-navigator base/stack-navigator)
76 | (def tab-navigator base/tab-navigator)
77 | (def drawer-navigator base/drawer-navigator)
78 | (def switch-navigator base/switch-navigator)
79 |
--------------------------------------------------------------------------------
/src/cljs_react_navigation/re_frame.cljs:
--------------------------------------------------------------------------------
1 | (ns cljs-react-navigation.re-frame
2 | (:require [cljs-react-navigation.base :as base]
3 | [cljs-react-navigation.reagent :as reagent]
4 | [reagent.core :as r]
5 | [re-frame.core :refer [subscribe dispatch dispatch-sync reg-event-db trim-v reg-sub]]))
6 |
7 | (def ref-getStateForAction (atom nil)) ;; HACK
8 |
9 | (reg-event-db
10 | ::swap-routing-state
11 | [trim-v]
12 | (fn [app-db [new-routes]]
13 | (assoc app-db :routing new-routes)))
14 |
15 | (reg-event-db
16 | ::dispatch
17 | [trim-v]
18 | (fn [app-db [dispatch-args]]
19 | (let [routing-state (get app-db :routing)
20 | type (aget dispatch-args "type")
21 | action-fn (get reagent/NavigationActionsMap type)
22 | action (action-fn dispatch-args)
23 | new-state (@ref-getStateForAction action routing-state)]
24 | (assoc app-db :routing new-state))))
25 |
26 | (reg-event-db
27 | ::navigate
28 | [trim-v]
29 | (fn [app-db [routeName params]]
30 | (let [routing-state (get app-db :routing)
31 | action-fn (get reagent/NavigationActionsMap "Navigation/NAVIGATE")
32 | action (action-fn #js {:routeName routeName :params params})
33 | new-state (@ref-getStateForAction action routing-state)]
34 | (assoc app-db :routing new-state))))
35 |
36 |
37 | (reg-event-db
38 | ::goBack
39 | [trim-v]
40 | (fn [app-db [routeName]]
41 | (let [routing-state (get app-db :routing)
42 | action-fn (get reagent/NavigationActionsMap "Navigation/BACK")
43 | action (action-fn #js {:routeName routeName})
44 | new-state (@ref-getStateForAction action routing-state)]
45 | (assoc app-db :routing new-state))))
46 |
47 | (reg-sub
48 | ::routing-state
49 | (fn [app-db]
50 | (get-in app-db [:routing])))
51 |
52 |
53 | ;; API
54 | (def stack-screen reagent/stack-screen)
55 | (def tab-screen reagent/tab-screen)
56 | (def drawer-component reagent/drawer-component)
57 | (def stack-navigator reagent/stack-navigator)
58 | (def tab-navigator reagent/tab-navigator)
59 | (def drawer-navigator reagent/drawer-navigator)
60 | (def switch-navigator reagent/switch-navigator)
61 |
62 | (def init-state
63 | (fn [main key]
64 | (-> main
65 | .-router
66 | (as-> router
67 | (.getStateForAction router
68 | (.getActionForPathAndParams router (name key)))))))
69 |
70 | (def nil-fn (fn [_]))
71 |
72 | (defn router [{:keys [root-router init-route-name add-listener]
73 | :or {add-listener nil-fn init-route-name :start-route}
74 | :as props}]
75 | (let [routing-sub (subscribe [::routing-state])
76 | getStateForAction (aget root-router "router" "getStateForAction")]
77 | (reset! ref-getStateForAction getStateForAction)
78 | (fn [props]
79 | (let [routing-state (or @routing-sub
80 | (init-state root-router init-route-name))]
81 | [:> root-router {:navigation
82 | (addNavigationHelpers
83 | (clj->js {:state routing-state
84 | :addListener add-listener
85 | :dispatch (fn [action]
86 | (let [next-state (getStateForAction action routing-state)]
87 | (dispatch [::swap-routing-state next-state])))}))}]))))
88 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/src/uiexplorer/events.cljs:
--------------------------------------------------------------------------------
1 | (ns uiexplorer.events
2 | (:require
3 | [re-frame.core :refer [reg-event-db after dispatch]]
4 | [clojure.spec.alpha :as s]
5 | [uiexplorer.db :as db :refer [app-db]]))
6 |
7 | ;; -- Interceptors ------------------------------------------------------------
8 | ;;
9 | ;; See https://github.com/Day8/re-frame/blob/master/docs/Interceptors.md
10 | ;;
11 | (defn check-and-throw
12 | "Throw an exception if db doesn't have a valid spec."
13 | [spec db [event]]
14 | (when-not (s/valid? spec db)
15 | (let [explain-data (s/explain-data spec db)]
16 | (throw (ex-info (str "Spec check after " event " failed: " explain-data) explain-data)))))
17 |
18 | (def validate-spec
19 | (if goog.DEBUG
20 | (after (partial check-and-throw ::db/app-db))
21 | []))
22 |
23 | ;; -- Handlers --------------------------------------------------------------
24 |
25 | (reg-event-db
26 | :initialize-db
27 | validate-spec
28 | (fn [_ _]
29 | app-db))
30 |
31 | (reg-event-db
32 | :reset-routing-state
33 | validate-spec
34 | (fn [db _]
35 | (assoc db :routing (clj->js {:index 1,
36 | :routes [{:routes [{:index 0,
37 | :routes [{:routeName "Home", :key "HomeInit"}],
38 | :key "HomeTab",
39 | :routeName "HomeTab"}
40 | {:index 0,
41 | :routes [{:routeName "Search", :key "SearchInit"}],
42 | :key "SearchTabInit",
43 | :routeName "SearchTab"}],
44 | :index 0,
45 | :key "InitTabs",
46 | :routeName "Tabs"}
47 | {:index 0,
48 | :routes [{:routeName "Login1", :key "Login1Init"}],
49 | :key "LoginStackInit",
50 | :routeName "LoginStack"}]}))))
51 |
52 | (reg-event-db
53 | :login
54 | validate-spec
55 | (fn [db [_ value]]
56 | (js/setTimeout #(dispatch [:login-success]) 2000)
57 | db))
58 |
59 | (reg-event-db
60 | :login-success
61 | validate-spec
62 | (fn [db [_ value]]
63 | (assoc db :routing (clj->js {:index 0,
64 | :routes [{:routes [{:index 0,
65 | :routes [{:routeName "Home", :key "HomeInit"}],
66 | :key "HomeTab",
67 | :routeName "HomeTab"}
68 | {:index 0,
69 | :routes [{:routeName "Search", :key "SearchInit"}],
70 | :key "SearchTabInit",
71 | :routeName "SearchTab"}],
72 | :index 0,
73 | :key "TabsInit",
74 | :routeName "Tabs"}]}))))
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # cljs-react-navigation
2 |
3 | This library is my attempt to unify all `cljs` `react-navigation` libraries under a shared code base. Right now it only includes `Reagent/Re-Frame` libraries, but I'm hoping other people will help me add `om-next` and `rum` libraries.
4 |
5 | 
6 |
7 | 
8 |
9 | ## Tested with
10 |
11 | Clojurescript
12 | ```clojure
13 | [org.clojure/clojurescript "1.9.854"] ;; using cljs.spec.alpha namespace
14 | [reagent "0.7.0"] ;; Import the cljs-react-navigation.reagent namespace
15 | [re-frame "0.9.3"] ;; Import the cljs-react-navigation.re-frame namespace
16 | ```
17 |
18 | Javascript
19 | ```js
20 | "react": "16.0.0-alpha.12",
21 | "react-native": "0.44.0",
22 | "react-navigation": "^1.0.0-beta.9"
23 | ```
24 |
25 | ## Do this first
26 |
27 | Add `react-navigation` to your project.
28 | ```
29 | npm install react-navigation --save
30 | ```
31 |
32 | If you're using re-natal, also add it to re-natal
33 | ```js
34 | re-natal use-component react-navigation
35 | re-natal use-figwheel
36 | ```
37 |
38 | If you're using my [cljs expo template](https://github.com/seantempesta/expo-cljs-template), make sure to require react-navigation somewhere in your code.
39 | ```clojure
40 | ; react-navigation
41 | (defonce ReactNavigation (js/require "react-navigation"))
42 | ```
43 |
44 | ## Documentation
45 |
46 | Anything `react-navigation` related is documented on [their site](https://reactnavigation.org/docs/getting-started.html). The idea for this library isn't to re-invent the wheel, but make it cljs friendly.
47 |
48 | Specifically:
49 | - Conforming whatever cljs wrapper components into the correct react components/elements
50 | - Converting props to cljs data structures to avoid `clj->js` & `js->clj`ing everything.
51 |
52 |
53 | ## Usage for base
54 |
55 | Yeah, you really don't use this directly. Try extending this set of specs and and functions. See the `reagent` version.
56 |
57 | That being said, I'm literally just spec'ing out the javascript API, with some minor tweaks:
58 | - `screen` function isn't overloaded (there's a `stack-screen` and a `tab-screen`)
59 | - `screen` functions accepts the `navigationOptions` as a second param (god knows why they insist on doing ES6 style initializations)
60 |
61 | ## Usage for reagent
62 |
63 | First import the reagent version of the library library:
64 | ```clojure
65 | (ns uiexplorer.routing
66 | (:require [cljs-react-navigation.reagent :refer [stack-navigator tab-navigator stack-screen tab-screen router]]))
67 |
68 | ```
69 |
70 | Then create reagent-components that accept props like this:
71 |
72 | ```clojure
73 | (defn home
74 | "Each Screen will receive two props:
75 | - screenProps - Extra props passed down from the router (rarely used)
76 | - navigation - The main navigation functions in a map as follows:
77 | {:state - routing state for this screen
78 | :dispatch - generic dispatch fn
79 | :goBack - pop's the current screen off the stack
80 | :navigate - most common way to navigate to the next screen
81 | :setParams - used to change the params for the current screen}"
82 | [props]
83 | (fn [{:keys [screenProps navigation] :as props}]
84 | (let [{:keys [navigate goBack]} navigation]
85 | [:> View {:style {:flex 1
86 | :alignItems "center"
87 | :justifyContent "center"}}
88 | [:> Button {:style {:fontSize 17}
89 | :onPress #(navigate "Modal")
90 | :title "Modal Me!"}]
91 | [:> Button {:style {:fontSize 17}
92 | :onPress #(goBack)
93 | :title "Go Back!"}]
94 | [:> Button {:style {:fontSize 17}
95 | :onPress #(navigate "Placeholder")}]])))
96 | ```
97 |
98 | And then you can create stacks and screens for them like this:
99 | ```clojure
100 | (def HomeStack (stack-navigator {:Home {:screen (stack-screen home {:title "Home"})}}))
101 |
102 | ```
103 |
104 | And then you can just render that Stack like a normal reagent component:
105 |
106 | ```clojure
107 | (defn app-root []
108 | (fn []
109 | [:> HomeStack {}]))
110 |
111 | (defn init []
112 | (.registerComponent AppRegistry "UIExplorer" #(r/reactify-component app-root)))
113 | ```
114 |
115 |
116 | TODO: Create an example
117 |
118 |
119 | ## Usage for re-frame
120 |
121 | Pretty much the same as the Reagent version, but you can store the routing state in re-frame's app-db (which is great for serializing state to AsyncStorage). Also, dispatch routing changes from anywhere.
122 |
123 | See the [examples folder](https://github.com/seantempesta/cljs-react-navigation/tree/master/examples/re-frame/uiexplorer).
124 |
125 | ## TODO
126 |
127 | - Finish spec'ing all functions and parameters (I think I've got most of them)
128 | - Reagent example
129 | - Rum example
130 | - Om-Next example
131 |
132 |
133 | ## License
134 |
135 | Copyright © 2017 Sean Tempesta
136 |
137 | Distributed under the MIT license.
138 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/src/uiexplorer/routing.cljs:
--------------------------------------------------------------------------------
1 | (ns uiexplorer.routing
2 | (:require [uiexplorer.react-requires :refer [Platform Button TouchableOpacity Ionicons InteractionManager View ScrollView Text TouchableHighlight]]
3 | [uiexplorer.scenes.login :as login]
4 | [cljs-react-navigation.re-frame :refer [stack-navigator tab-navigator stack-screen tab-screen router] :as nav]
5 | [reagent.core :as r]
6 | [re-frame.core :refer [subscribe dispatch dispatch-sync]]))
7 |
8 | ;; Colors
9 | ;;
10 | (def darkGrey "#484848")
11 | (def blue "#348BFE")
12 |
13 | (defn home
14 | "Each Screen will receive two props:
15 | - screenProps - Extra props passed down from the router (rarely used)
16 | - navigation - The main navigation functions in a map as follows:
17 | {:state - routing state for this screen
18 | :dispatch - generic dispatch fn
19 | :goBack - pop's the current screen off the stack
20 | :navigate - most common way to navigate to the next screen
21 | :setParams - used to change the params for the current screen}"
22 | [props]
23 | (fn [{:keys [screenProps navigation] :as props}]
24 | (let [{:keys [navigate goBack]} navigation]
25 | [:> View {:style {:flex 1
26 | :alignItems "center"
27 | :justifyContent "center"}}
28 | [:> Button {:style {:fontSize 17}
29 | :onPress #(navigate "Modal")
30 | :title "Modal Me!"}]
31 | [:> Button {:style {:fontSize 17}
32 | :onPress #(goBack)
33 | :title "Go Back!"}]
34 | [:> Button {:style {:fontSize 17}
35 | :onPress #(navigate "Placeholder")
36 | :title "Push Placeholder"}]
37 | [:> Button {:style {:fontSize 17}
38 | :onPress #(dispatch [:reset-routing-state])
39 | :title "Logout"}]])))
40 |
41 | (defn search [props]
42 | (fn [{:keys [screenProps navigation] :as props}]
43 | (let [{:keys [state setParams]} navigation
44 | {:keys [params]} state]
45 | [:> View {:style {:flex 1
46 | :alignItems "center"
47 | :justifyContent "center"}}
48 | [:> Text {} (str "Searching for " (:search params))]
49 |
50 | [:> Button {:style {:fontSize 17}
51 | :onPress #(setParams (clj->js {:search (rand-int 100)}))
52 | :title "Search!"}]])))
53 |
54 | (defn placeholder [props]
55 | (fn [{:keys [screenProps navigation] :as props}]
56 | (let [{:keys [goBack]} navigation]
57 | [:> View {:style {:flex 1
58 | :alignItems "center"
59 | :justifyContent "center"}}
60 | [:> Text {} "Nothing to see here!"]
61 | [:> Button {:style {:fontSize 17}
62 | :onPress #(goBack)
63 | :title "Go Back!"}]])))
64 |
65 | (def home-tabBar {:tabBarLabel "Home"
66 | :tabBarIcon (fn [{:keys [tintColor focused] :as props}]
67 | [:> Ionicons {:name (if focused "ios-home" "ios-home-outline")
68 | :color (if focused blue darkGrey)
69 | :size 26}])})
70 |
71 | (def search-tabBar {:tabBarLabel "Search"
72 | :tabBarIcon (fn [{:keys [tintColor focused] :as props}]
73 | [:> Ionicons {:name (if focused "ios-search" "ios-search-outline")
74 | :color (if focused blue darkGrey)
75 | :size 26}])})
76 |
77 |
78 | (def LoginStack (stack-navigator {:Login1 {:screen (stack-screen login/login1 login/dynamic-navigationOptions)}
79 | :Loading {:screen (stack-screen login/loading {:header nil})}}))
80 | (def HomeStack (stack-navigator {:Home {:screen (stack-screen home {:title "Home"})}
81 | :Placeholder {:screen (stack-screen placeholder {:title "Placeholder"})}}))
82 | (def SearchStack (stack-navigator {:Search {:screen (stack-screen search {:title "Search"})}}))
83 |
84 | (def navbar-marginTop (if (= (aget Platform "OS") "android") 24 0))
85 | (def Tabs (tab-navigator {:HomeTab {:path "home"
86 | :screen (tab-screen HomeStack home-tabBar)}
87 | :SearchTab {:path "search"
88 | :screen (tab-screen SearchStack search-tabBar)}}
89 | {:tabBarOptions {:style {:marginTop navbar-marginTop}}}))
90 |
91 | (def AllRoutesStack (stack-navigator {:Tabs {:screen Tabs}
92 | :Modal {:screen (stack-screen placeholder {:title "Modal"})}
93 | :LoginStack {:screen LoginStack}}
94 | {:headerMode "none"
95 | :mode "modal"}))
96 |
97 | (defn app-root []
98 | (r/create-class
99 | (let [nav-state (subscribe [::nav/routing-state])]
100 | {:component-will-mount (fn []
101 | (when-not @nav-state
102 | (dispatch-sync [:reset-routing-state])))
103 | :reagent-render (fn []
104 | [router {:root-router AllRoutesStack}])})))
105 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/env/dev/externs.clj:
--------------------------------------------------------------------------------
1 | (ns externs
2 | (:require [cljs.compiler.api :as compiler]
3 | [cljs.analyzer.api :as analyzer]
4 | [cljs.analyzer :as ana]
5 | [clojure.walk :refer [prewalk]]
6 | [clojure.pprint :refer [pprint]]
7 | [clojure.java.io :as io]
8 | [clojure.string :as str]
9 | [cljs.env :as env]
10 | [clojure.tools.reader :as r]
11 | [clojure.tools.reader.reader-types :refer [string-push-back-reader]]
12 | [cljs.tagged-literals :as tags])
13 | (:import (clojure.lang LineNumberingPushbackReader)))
14 |
15 | ;; Idea from https://gist.github.com/Chouser/5796967
16 |
17 | ;; TODO (NAMESPACE/MODULE.method ...args) or NAMESPACE/MODULE.field not work
18 | ;; For example, (ui/Facebook.logInWithReadPermissionsAsync ...args)
19 | ;; or ui/Permissions.REMOTE_NOTIFICATIONS,
20 | ;; we already know logInWithReadPermissionsAsync is `invoke' op
21 | ;; and REMOTE_NOTIFICATIONS is a property, need to dig deeper to the ast
22 |
23 | ;; TODO ana/analyze is slow
24 |
25 | (defonce cenv (analyzer/empty-state))
26 |
27 | (defn compile-project
28 | [src target]
29 | (analyzer/with-state cenv
30 | (compiler/with-core-cljs
31 | (compiler/compile-root src target))))
32 |
33 | (defn get-namespaces
34 | []
35 | (:cljs.analyzer/namespaces @cenv))
36 |
37 | (defn get-namespace
38 | ([]
39 | (get-namespace ana/*cljs-ns*))
40 | ([k]
41 | (get (get-namespaces) k)))
42 |
43 | (defn get-alias
44 | [ns]
45 | (apply merge
46 | ((juxt :requires :require-macros)
47 | (get-namespace ns))))
48 |
49 | (defn print-ast [ast]
50 | (pprint ;; pprint indents output nicely
51 | (prewalk ;; rewrite each node of the ast
52 | (fn [x]
53 | (if (map? x)
54 | (select-keys x [:children :name :form :op]) ;; return selected entries of each map node
55 | x)) ;; non-map nodes are left unchanged
56 | ast)))
57 |
58 | (defn get-ns
59 | [s]
60 | (some->>
61 | (re-find #"\(ns[\s]+([^\s]+)" s)
62 | (last)
63 | (symbol)))
64 |
65 | (defn read-file
66 | [filename]
67 | (try
68 | (let [form-str (slurp filename)
69 | current-ns (get-ns form-str)
70 | reader (string-push-back-reader form-str)
71 | endof (gensym)]
72 | (binding [r/*read-eval* false
73 | r/*data-readers* tags/*cljs-data-readers*
74 | r/*alias-map* (try
75 | (get-alias (ns-name current-ns))
76 | (catch Exception e
77 | {}))]
78 | (->> #(r/read reader false endof)
79 | (repeatedly)
80 | (take-while #(not= % endof))
81 | (doall))))
82 | (catch Exception e
83 | (println e)
84 | '())))
85 |
86 | (defn file-ast
87 | "Return the ClojureScript AST for the contents of filename. Tends to
88 | be large and to contain cycles -- be careful printing at the REPL."
89 | [filename]
90 | (binding [ana/*cljs-ns* 'cljs.user ;; default namespace
91 | ana/*cljs-file* filename]
92 | (mapv
93 | (fn [form]
94 | (try (ana/no-warn (ana/analyze (ana/empty-env) form {:cache-analysis true}))
95 | (catch Exception e
96 | (prn filename e))))
97 | (read-file filename))))
98 |
99 | (defn flatten-ast [ast]
100 | (mapcat #(tree-seq :children :children %) ast))
101 |
102 | (defn get-interop-used
103 | "Return a set of symbols representing the method and field names
104 | used in interop forms in the given sequence of AST nodes."
105 | [flat-ast]
106 | (keep #(let [ret (and (map? %)
107 | (when-let [sym (some % [:method :field])]
108 | (when-not (str/starts-with? sym "cljs")
109 | sym)))]
110 | (if ret
111 | ret
112 | nil)) flat-ast))
113 |
114 | (defn externs-for-interop [syms]
115 | (apply str
116 | "var DummyClass={};\n"
117 | (map #(str "DummyClass." % "=function(){};\n")
118 | syms)))
119 |
120 | (defn var-defined?
121 | "Returns true if the given fully-qualified symbol is known by the
122 | ClojureScript compiler to have been defined, based on its mutable set
123 | of namespaces."
124 | [sym]
125 | (contains? (let [ns (get (get-namespaces) (symbol (namespace sym)))]
126 | (merge (:defs ns)
127 | (:macros ns)))
128 | (symbol (name sym))))
129 |
130 | (defn get-vars-used
131 | "Return a set of symbols representing all vars used or referenced in
132 | the given sequence of AST nodes."
133 | [requires flat-ast]
134 | (->> flat-ast
135 | (filter #(let [ns (-> % :info :ns)]
136 | (and (= (:op %) :var)
137 | ns
138 | (not= ns 'js))))
139 | (map #(let [sym (-> % :info :name)
140 | sym-namespace (get requires (symbol (namespace sym)))
141 | sym-name (name sym)]
142 | (if sym-namespace
143 | (symbol (str sym-namespace) sym-name)
144 | sym)))))
145 |
146 | (defn extern-for-var [[str-namespace symbols]]
147 | (let [symbols-str (->> symbols
148 | (map (fn [sym] (format "%s.%s={};\n" (namespace sym) (name sym))))
149 | (apply str))]
150 | (format "var %s={};\n%s"
151 | str-namespace symbols-str)))
152 |
153 | (defn externs-for-vars [grouped-syms]
154 | (apply str (map extern-for-var grouped-syms)))
155 |
156 | (defn get-undefined-vars [requires flat-ast]
157 | (->> (get-vars-used requires flat-ast)
158 | (remove var-defined?)))
159 |
160 | (defn get-undefined-vars-and-interop-used [file]
161 | (let [ast (file-ast file)
162 | ns-name (:name (first ast))
163 | ns-requires (:requires (first ast))
164 | flat-ast (flatten-ast ast)]
165 | [(get-undefined-vars ns-requires flat-ast)
166 | (get-interop-used flat-ast)]))
167 |
168 | ;; copy from https://github.com/ejlo/lein-externs/blob/master/src/leiningen/externs.clj
169 | (defn cljs-file?
170 | "Returns true if the java.io.File represents a normal Clojurescript source
171 | file."
172 | [^java.io.File file]
173 | (and (.isFile file)
174 | (.endsWith (.getName file) ".cljs")))
175 |
176 | (defn get-source-paths [build-type builds]
177 | (or
178 | (when build-type
179 | (:source-paths
180 | (or ((keyword build-type) builds)
181 | (first (filter #(= (name (:id %)) build-type) builds)))))
182 | ["src" "cljs"]))
183 |
184 | (defn -main
185 | "Generate an externs file"
186 | []
187 | ;; TODO configurable
188 | (println "Start to generate externs...")
189 | (compile-project (io/file "src") (io/file "target"))
190 |
191 | (let [source-paths ["src" "env/prod"]
192 |
193 | files (->> source-paths
194 | (map io/file)
195 | (mapcat file-seq)
196 | (filter cljs-file?))
197 | col (apply concat (doall (pmap get-undefined-vars-and-interop-used files)))
198 | vars (->> (take-nth 2 col)
199 | (remove empty?)
200 | (flatten)
201 | (set)
202 | (sort)
203 | (group-by namespace)
204 | ;; remove goog dependencies, need to dig deeper(TODO)
205 | (remove (fn [[ns _]] (str/starts-with? ns "goog")))
206 | (externs-for-vars))
207 | interop (->> (take-nth 2 (rest col))
208 | (remove empty?)
209 | (flatten)
210 | (set)
211 | (sort)
212 | (externs-for-interop))
213 | result (str vars interop)]
214 | (spit "js/externs.js" result)
215 | (println "Generated externs to js/externs.js")
216 |
217 | ;; prevent jvm hang after this task, maybe Clojurescript uses pmap for parallel compilation.
218 | (shutdown-agents)))
219 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/env/dev/externs.clj:
--------------------------------------------------------------------------------
1 | (ns externs
2 | (:require [cljs.compiler.api :as compiler]
3 | [cljs.analyzer.api :as analyzer]
4 | [cljs.analyzer :as ana]
5 | [clojure.walk :refer [prewalk]]
6 | [clojure.pprint :refer [pprint]]
7 | [clojure.java.io :as io]
8 | [clojure.string :as str]
9 | [cljs.env :as env]
10 | [clojure.tools.reader :as r]
11 | [clojure.tools.reader.reader-types :refer [string-push-back-reader]]
12 | [cljs.tagged-literals :as tags])
13 | (:import (clojure.lang LineNumberingPushbackReader)))
14 |
15 | ;; Idea from https://gist.github.com/Chouser/5796967
16 |
17 | ;; TODO (NAMESPACE/MODULE.method ...args) or NAMESPACE/MODULE.field not work
18 | ;; For example, (ui/Facebook.logInWithReadPermissionsAsync ...args)
19 | ;; or ui/Permissions.REMOTE_NOTIFICATIONS,
20 | ;; we already know logInWithReadPermissionsAsync is `invoke' op
21 | ;; and REMOTE_NOTIFICATIONS is a property, need to dig deeper to the ast
22 |
23 | ;; TODO ana/analyze is slow
24 |
25 | (defonce cenv (analyzer/empty-state))
26 |
27 | (defn compile-project
28 | [src target]
29 | (analyzer/with-state cenv
30 | (compiler/with-core-cljs
31 | (compiler/compile-root src target))))
32 |
33 | (defn get-namespaces
34 | []
35 | (:cljs.analyzer/namespaces @cenv))
36 |
37 | (defn get-namespace
38 | ([]
39 | (get-namespace ana/*cljs-ns*))
40 | ([k]
41 | (get (get-namespaces) k)))
42 |
43 | (defn get-alias
44 | [ns]
45 | (apply merge
46 | ((juxt :requires :require-macros)
47 | (get-namespace ns))))
48 |
49 | (defn print-ast [ast]
50 | (pprint ;; pprint indents output nicely
51 | (prewalk ;; rewrite each node of the ast
52 | (fn [x]
53 | (if (map? x)
54 | (select-keys x [:children :name :form :op]) ;; return selected entries of each map node
55 | x)) ;; non-map nodes are left unchanged
56 | ast)))
57 |
58 | (defn get-ns
59 | [s]
60 | (some->>
61 | (re-find #"\(ns[\s]+([^\s]+)" s)
62 | (last)
63 | (symbol)))
64 |
65 | (defn read-file
66 | [filename]
67 | (try
68 | (let [form-str (slurp filename)
69 | current-ns (get-ns form-str)
70 | reader (string-push-back-reader form-str)
71 | endof (gensym)]
72 | (binding [r/*read-eval* false
73 | r/*data-readers* tags/*cljs-data-readers*
74 | r/*alias-map* (try
75 | (get-alias (ns-name current-ns))
76 | (catch Exception e
77 | {}))]
78 | (->> #(r/read reader false endof)
79 | (repeatedly)
80 | (take-while #(not= % endof))
81 | (doall))))
82 | (catch Exception e
83 | (println e)
84 | '())))
85 |
86 | (defn file-ast
87 | "Return the ClojureScript AST for the contents of filename. Tends to
88 | be large and to contain cycles -- be careful printing at the REPL."
89 | [filename]
90 | (binding [ana/*cljs-ns* 'cljs.user ;; default namespace
91 | ana/*cljs-file* filename]
92 | (mapv
93 | (fn [form]
94 | (try (ana/no-warn (ana/analyze (ana/empty-env) form {:cache-analysis true}))
95 | (catch Exception e
96 | (prn filename e))))
97 | (read-file filename))))
98 |
99 | (defn flatten-ast [ast]
100 | (mapcat #(tree-seq :children :children %) ast))
101 |
102 | (defn get-interop-used
103 | "Return a set of symbols representing the method and field names
104 | used in interop forms in the given sequence of AST nodes."
105 | [flat-ast]
106 | (keep #(let [ret (and (map? %)
107 | (when-let [sym (some % [:method :field])]
108 | (when-not (str/starts-with? sym "cljs")
109 | sym)))]
110 | (if ret
111 | ret
112 | nil)) flat-ast))
113 |
114 | (defn externs-for-interop [syms]
115 | (apply str
116 | "var DummyClass={};\n"
117 | (map #(str "DummyClass." % "=function(){};\n")
118 | syms)))
119 |
120 | (defn var-defined?
121 | "Returns true if the given fully-qualified symbol is known by the
122 | ClojureScript compiler to have been defined, based on its mutable set
123 | of namespaces."
124 | [sym]
125 | (contains? (let [ns (get (get-namespaces) (symbol (namespace sym)))]
126 | (merge (:defs ns)
127 | (:macros ns)))
128 | (symbol (name sym))))
129 |
130 | (defn get-vars-used
131 | "Return a set of symbols representing all vars used or referenced in
132 | the given sequence of AST nodes."
133 | [requires flat-ast]
134 | (->> flat-ast
135 | (filter #(let [ns (-> % :info :ns)]
136 | (and (= (:op %) :var)
137 | ns
138 | (not= ns 'js))))
139 | (map #(let [sym (-> % :info :name)
140 | sym-namespace (get requires (symbol (namespace sym)))
141 | sym-name (name sym)]
142 | (if sym-namespace
143 | (symbol (str sym-namespace) sym-name)
144 | sym)))))
145 |
146 | (defn extern-for-var [[str-namespace symbols]]
147 | (let [symbols-str (->> symbols
148 | (map (fn [sym] (format "%s.%s={};\n" (namespace sym) (name sym))))
149 | (apply str))]
150 | (format "var %s={};\n%s"
151 | str-namespace symbols-str)))
152 |
153 | (defn externs-for-vars [grouped-syms]
154 | (apply str (map extern-for-var grouped-syms)))
155 |
156 | (defn get-undefined-vars [requires flat-ast]
157 | (->> (get-vars-used requires flat-ast)
158 | (remove var-defined?)))
159 |
160 | (defn get-undefined-vars-and-interop-used [file]
161 | (let [ast (file-ast file)
162 | ns-name (:name (first ast))
163 | ns-requires (:requires (first ast))
164 | flat-ast (flatten-ast ast)]
165 | [(get-undefined-vars ns-requires flat-ast)
166 | (get-interop-used flat-ast)]))
167 |
168 | ;; copy from https://github.com/ejlo/lein-externs/blob/master/src/leiningen/externs.clj
169 | (defn cljs-file?
170 | "Returns true if the java.io.File represents a normal Clojurescript source
171 | file."
172 | [^java.io.File file]
173 | (and (.isFile file)
174 | (.endsWith (.getName file) ".cljs")))
175 |
176 | (defn get-source-paths [build-type builds]
177 | (or
178 | (when build-type
179 | (:source-paths
180 | (or ((keyword build-type) builds)
181 | (first (filter #(= (name (:id %)) build-type) builds)))))
182 | ["src" "cljs"]))
183 |
184 | (defn -main
185 | "Generate an externs file"
186 | []
187 | ;; TODO configurable
188 | (println "Start to generate externs...")
189 | (compile-project (io/file "src") (io/file "target"))
190 |
191 | (let [source-paths ["src" "env/prod"]
192 |
193 | files (->> source-paths
194 | (map io/file)
195 | (mapcat file-seq)
196 | (filter cljs-file?))
197 | col (apply concat (doall (pmap get-undefined-vars-and-interop-used files)))
198 | vars (->> (take-nth 2 col)
199 | (remove empty?)
200 | (flatten)
201 | (set)
202 | (sort)
203 | (group-by namespace)
204 | ;; remove goog dependencies, need to dig deeper(TODO)
205 | (remove (fn [[ns _]] (str/starts-with? ns "goog")))
206 | (externs-for-vars))
207 | interop (->> (take-nth 2 (rest col))
208 | (remove empty?)
209 | (flatten)
210 | (set)
211 | (sort)
212 | (externs-for-interop))
213 | result (str vars interop)]
214 | (spit "js/externs.js" result)
215 | (println "Generated externs to js/externs.js")
216 |
217 | ;; prevent jvm hang after this task, maybe Clojurescript uses pmap for parallel compilation.
218 | (shutdown-agents)))
219 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/env/dev/user.clj:
--------------------------------------------------------------------------------
1 | (ns user
2 | (:require [figwheel-sidecar.repl-api :as ra]
3 | [clojure.java.io :as io]
4 | [clojure.string :as str]
5 | [hawk.core :as hawk]
6 | [clojure.tools.reader.edn :as edn]
7 | [clojure.set :as set]))
8 | ;; This namespace is loaded automatically by nREPL
9 |
10 | (defn get-cljs-builds
11 | []
12 | (let [project-config (->> "project.clj"
13 | slurp
14 | read-string
15 | (drop 1)
16 | (apply hash-map))
17 | profiles (:profiles project-config)]
18 | (get-in profiles [:dev :cljsbuild :builds])))
19 |
20 | (defn enable-source-maps
21 | []
22 | (println "Source maps enabled.")
23 | (let [path "node_modules/metro-bundler/src/Server/index.js"]
24 | (spit path
25 | (str/replace (slurp path) "/\\.map$/" "/main.map$/"))))
26 |
27 | (defn write-main-js
28 | []
29 | (-> "'use strict';\n\n// cljsbuild adds a preamble mentioning goog so hack around it\nwindow.goog = {\n provide() {},\n require() {},\n};\nrequire('./target/env/index.js');\n"
30 | ((partial spit "main.js"))))
31 |
32 | (defn get-lan-ip
33 | []
34 | (cond
35 | (= "Mac OS X" (System/getProperty "os.name"))
36 | (.getHostAddress (java.net.InetAddress/getLocalHost))
37 |
38 | :else
39 | (->> (java.net.NetworkInterface/getNetworkInterfaces)
40 | (enumeration-seq)
41 | (filter #(not (or (str/starts-with? (.getName %) "docker")
42 | (str/starts-with? (.getName %) "vboxnet")
43 | (str/starts-with? (.getName %) "br-"))))
44 | (map #(.getInterfaceAddresses %))
45 | (map
46 | (fn [ip]
47 | (seq (filter #(instance?
48 | java.net.Inet4Address
49 | (.getAddress %))
50 | ip))))
51 | (remove nil?)
52 | (first)
53 | (filter #(instance?
54 | java.net.Inet4Address
55 | (.getAddress %)))
56 | (first)
57 | (.getAddress)
58 | (.getHostAddress))))
59 |
60 | (defn write-env-dev
61 | []
62 | (let [hostname (.getHostName (java.net.InetAddress/getLocalHost))
63 | ip (get-lan-ip)]
64 | (-> "(ns env.dev)\n(def hostname \"%s\")\n(def ip \"%s\")"
65 | (format
66 | hostname
67 | ip)
68 | ((partial spit "env/dev/env/dev.cljs")))))
69 |
70 | (defn rebuild-env-index
71 | [js-modules]
72 | (let [modules (->> (file-seq (io/file "assets"))
73 | (filter #(and (not (re-find #"DS_Store" (str %)))
74 | (.isFile %)))
75 | (map (fn [file] (when-let [path (str file)]
76 | (str "../../" path))))
77 | (concat js-modules ["react" "react-native" "expo" "create-react-class"])
78 | (distinct))
79 | modules-map (zipmap
80 | (->> modules
81 | (map #(str "\""
82 | (if (str/starts-with? % "../../assets")
83 | (-> %
84 | (str/replace "../../" "./")
85 | (str/replace "@2x" "")
86 | (str/replace "@3x" ""))
87 | %)
88 | "\"")))
89 | (->> modules
90 | (map #(format "(js/require \"%s\")"
91 | (-> %
92 | (str/replace "@2x" "")
93 | (str/replace "@3x" ""))))))]
94 | (try
95 | (-> "(ns env.index\n (:require [env.dev :as dev]))\n\n;; undo main.js goog preamble hack\n(set! js/window.goog js/undefined)\n\n(-> (js/require \"figwheel-bridge\")\n (.withModules %s)\n (.start \"main\"))\n"
96 | (format
97 | (str "#js " (with-out-str (println modules-map))))
98 | ((partial spit "env/dev/env/index.cljs")))
99 |
100 | (catch Exception e
101 | (println "Error: " e)))))
102 |
103 | ;; Each file maybe corresponds to multiple modules.
104 | (defn watch-for-external-modules
105 | []
106 | (let [path ".js-modules.edn"]
107 | (hawk/watch! [{:paths ["src"]
108 | :filter hawk/file?
109 | :handler (fn [ctx {:keys [kind file] :as event}]
110 | (let [m (edn/read-string (slurp path))
111 | file-name (-> (.getPath file)
112 | (str/replace (str (System/getProperty "user.dir") "/") ""))]
113 |
114 | ;; file is deleted
115 | (when (= :delete kind)
116 | (let [new-m (dissoc m file-name)]
117 | (spit path new-m)
118 | (rebuild-env-index (flatten (vals new-m)))))
119 |
120 | (when (.exists file)
121 | (let [content (slurp file)
122 | js-modules (some->>
123 | content
124 | (re-seq #"\(js/require \"([^\"]+)\"\)")
125 | (map last)
126 | (vec))
127 | commented-modules (some->>
128 | content
129 | (re-seq #"[;]+[\s]*\(js/require \"([^\"]+)\"\)")
130 | (map last)
131 | (set))
132 | js-modules (if commented-modules
133 | (vec (remove commented-modules js-modules))
134 | js-modules)]
135 | (let [old-js-modules (get m file-name)]
136 | (when (not= old-js-modules js-modules)
137 | (let [new-m (if (seq js-modules)
138 | (assoc m file-name js-modules)
139 | (dissoc m file-name))]
140 | (spit path new-m)
141 |
142 | (rebuild-env-index (flatten (vals new-m)))))))))
143 | ctx)}])))
144 |
145 | (defn rebuild-modules
146 | []
147 | (let [path ".js-modules.edn"
148 | m (atom {})]
149 | ;; delete path
150 | (when (.exists (java.io.File. path))
151 | (clojure.java.io/delete-file path))
152 |
153 | (doseq [file (file-seq (java.io.File. "src"))]
154 | (when (.isFile file)
155 | (let [file-name (-> (.getPath file)
156 | (str/replace (str (System/getProperty "user.dir") "/") ""))
157 | content (slurp file)
158 | js-modules (some->>
159 | content
160 | (re-seq #"\(js/require \"([^\"]+)\"\)")
161 | (map last)
162 | (vec))
163 | commented-modules (some->>
164 | content
165 | (re-seq #"[;]+[\s]*\(js/require \"([^\"]+)\"\)")
166 | (map last)
167 | (set))
168 | js-modules (if commented-modules
169 | (vec (remove commented-modules js-modules))
170 | js-modules)]
171 | (if js-modules
172 | (swap! m assoc file-name (vec js-modules))))))
173 | (spit path @m)
174 | (rebuild-env-index (flatten (vals @m)))))
175 |
176 | (defn init-external-modules
177 | []
178 | (rebuild-modules))
179 |
180 | ;; Lein
181 | (defn start-figwheel
182 | "Start figwheel for one or more builds"
183 | [& build-ids]
184 | (init-external-modules)
185 | (enable-source-maps)
186 | (write-main-js)
187 | (write-env-dev)
188 | (watch-for-external-modules)
189 | (ra/start-figwheel!
190 | {:figwheel-options {}
191 | :build-ids (if (seq build-ids)
192 | build-ids
193 | ["main"])
194 | :all-builds (get-cljs-builds)})
195 | (ra/cljs-repl))
196 |
197 | (defn stop-figwheel
198 | "Stops figwheel"
199 | []
200 | (ra/stop-figwheel!))
201 |
202 | (defn -main
203 | [args]
204 | (case args
205 | "--figwheel"
206 | (start-figwheel)
207 |
208 | "--rebuild-modules"
209 | (rebuild-modules)
210 |
211 | (prn "You can run lein figwheel or lein rebuild-modules.")))
212 |
213 | ;; Boot
214 | (defn prepare
215 | []
216 | (init-external-modules)
217 | (enable-source-maps)
218 | (write-main-js)
219 | (write-env-dev)
220 | (watch-for-external-modules))
221 |
--------------------------------------------------------------------------------
/examples/re-frame/expo-example/env/dev/user.clj:
--------------------------------------------------------------------------------
1 | (ns user
2 | (:require [figwheel-sidecar.repl-api :as ra]
3 | [clojure.java.io :as io]
4 | [clojure.string :as str]
5 | [hawk.core :as hawk]
6 | [clojure.tools.reader.edn :as edn]
7 | [clojure.set :as set]))
8 | ;; This namespace is loaded automatically by nREPL
9 |
10 | (defn get-cljs-builds
11 | []
12 | (let [project-config (->> "project.clj"
13 | slurp
14 | read-string
15 | (drop 1)
16 | (apply hash-map))
17 | profiles (:profiles project-config)]
18 | (get-in profiles [:dev :cljsbuild :builds])))
19 |
20 | (defn enable-source-maps
21 | []
22 | (println "Source maps enabled.")
23 | (let [path "node_modules/metro-bundler/src/Server/index.js"]
24 | (spit path
25 | (str/replace (slurp path) "/\\.map$/" "/main.map$/"))))
26 |
27 | (defn write-main-js
28 | []
29 | (-> "'use strict';\n\n// cljsbuild adds a preamble mentioning goog so hack around it\nwindow.goog = {\n provide() {},\n require() {},\n};\nrequire('./target/env/index.js');\n"
30 | ((partial spit "main.js"))))
31 |
32 | (defn get-lan-ip
33 | []
34 | (cond
35 | (= "Mac OS X" (System/getProperty "os.name"))
36 | (.getHostAddress (java.net.InetAddress/getLocalHost))
37 |
38 | :else
39 | (->> (java.net.NetworkInterface/getNetworkInterfaces)
40 | (enumeration-seq)
41 | (filter #(not (or (str/starts-with? (.getName %) "docker")
42 | (str/starts-with? (.getName %) "vboxnet")
43 | (str/starts-with? (.getName %) "br-"))))
44 | (map #(.getInterfaceAddresses %))
45 | (map
46 | (fn [ip]
47 | (seq (filter #(instance?
48 | java.net.Inet4Address
49 | (.getAddress %))
50 | ip))))
51 | (remove nil?)
52 | (first)
53 | (filter #(instance?
54 | java.net.Inet4Address
55 | (.getAddress %)))
56 | (first)
57 | (.getAddress)
58 | (.getHostAddress))))
59 |
60 | (defn write-env-dev
61 | []
62 | (let [hostname (.getHostName (java.net.InetAddress/getLocalHost))
63 | ip (get-lan-ip)]
64 | (-> "(ns env.dev)\n(def hostname \"%s\")\n(def ip \"%s\")"
65 | (format
66 | hostname
67 | ip)
68 | ((partial spit "env/dev/env/dev.cljs")))))
69 |
70 | (defn rebuild-env-index
71 | [js-modules]
72 | (let [modules (->> (file-seq (io/file "assets"))
73 | (filter #(and (not (re-find #"DS_Store" (str %)))
74 | (.isFile %)))
75 | (map (fn [file] (when-let [path (str file)]
76 | (str "../../" path))))
77 | (concat js-modules ["react" "react-native" "expo" "create-react-class"])
78 | (distinct))
79 | modules-map (zipmap
80 | (->> modules
81 | (map #(str "\""
82 | (if (str/starts-with? % "../../assets")
83 | (-> %
84 | (str/replace "../../" "./")
85 | (str/replace "@2x" "")
86 | (str/replace "@3x" ""))
87 | %)
88 | "\"")))
89 | (->> modules
90 | (map #(format "(js/require \"%s\")"
91 | (-> %
92 | (str/replace "@2x" "")
93 | (str/replace "@3x" ""))))))]
94 | (try
95 | (-> "(ns env.index\n (:require [env.dev :as dev]))\n\n;; undo main.js goog preamble hack\n(set! js/window.goog js/undefined)\n\n(-> (js/require \"figwheel-bridge\")\n (.withModules %s)\n (.start \"main\"))\n"
96 | (format
97 | (str "#js " (with-out-str (println modules-map))))
98 | ((partial spit "env/dev/env/index.cljs")))
99 |
100 | (catch Exception e
101 | (println "Error: " e)))))
102 |
103 | ;; Each file maybe corresponds to multiple modules.
104 | (defn watch-for-external-modules
105 | []
106 | (let [path ".js-modules.edn"]
107 | (hawk/watch! [{:paths ["src"]
108 | :filter hawk/file?
109 | :handler (fn [ctx {:keys [kind file] :as event}]
110 | (let [m (edn/read-string (slurp path))
111 | file-name (-> (.getPath file)
112 | (str/replace (str (System/getProperty "user.dir") "/") ""))]
113 |
114 | ;; file is deleted
115 | (when (= :delete kind)
116 | (let [new-m (dissoc m file-name)]
117 | (spit path new-m)
118 | (rebuild-env-index (flatten (vals new-m)))))
119 |
120 | (when (.exists file)
121 | (let [content (slurp file)
122 | js-modules (some->>
123 | content
124 | (re-seq #"\(js/require \"([^\"]+)\"\)")
125 | (map last)
126 | (vec))
127 | commented-modules (some->>
128 | content
129 | (re-seq #"[;]+[\s]*\(js/require \"([^\"]+)\"\)")
130 | (map last)
131 | (set))
132 | js-modules (if commented-modules
133 | (vec (remove commented-modules js-modules))
134 | js-modules)]
135 | (let [old-js-modules (get m file-name)]
136 | (when (not= old-js-modules js-modules)
137 | (let [new-m (if (seq js-modules)
138 | (assoc m file-name js-modules)
139 | (dissoc m file-name))]
140 | (spit path new-m)
141 |
142 | (rebuild-env-index (flatten (vals new-m)))))))))
143 | ctx)}])))
144 |
145 | (defn rebuild-modules
146 | []
147 | (let [path ".js-modules.edn"
148 | m (atom {})]
149 | ;; delete path
150 | (when (.exists (java.io.File. path))
151 | (clojure.java.io/delete-file path))
152 |
153 | (doseq [file (file-seq (java.io.File. "src"))]
154 | (when (.isFile file)
155 | (let [file-name (-> (.getPath file)
156 | (str/replace (str (System/getProperty "user.dir") "/") ""))
157 | content (slurp file)
158 | js-modules (some->>
159 | content
160 | (re-seq #"\(js/require \"([^\"]+)\"\)")
161 | (map last)
162 | (vec))
163 | commented-modules (some->>
164 | content
165 | (re-seq #"[;]+[\s]*\(js/require \"([^\"]+)\"\)")
166 | (map last)
167 | (set))
168 | js-modules (if commented-modules
169 | (vec (remove commented-modules js-modules))
170 | js-modules)]
171 | (if js-modules
172 | (swap! m assoc file-name (vec js-modules))))))
173 | (spit path @m)
174 | (rebuild-env-index (flatten (vals @m)))))
175 |
176 | (defn init-external-modules
177 | []
178 | (rebuild-modules))
179 |
180 | ;; Lein
181 | (defn start-figwheel
182 | "Start figwheel for one or more builds"
183 | [& build-ids]
184 | (init-external-modules)
185 | (enable-source-maps)
186 | (write-main-js)
187 | (write-env-dev)
188 | (watch-for-external-modules)
189 | (ra/start-figwheel!
190 | {:figwheel-options {}
191 | :build-ids (if (seq build-ids)
192 | build-ids
193 | ["main"])
194 | :all-builds (get-cljs-builds)})
195 | (ra/cljs-repl))
196 |
197 | (defn stop-figwheel
198 | "Stops figwheel"
199 | []
200 | (ra/stop-figwheel!))
201 |
202 | (defn -main
203 | [args]
204 | (case args
205 | "--figwheel"
206 | (start-figwheel)
207 |
208 | "--rebuild-modules"
209 | (rebuild-modules)
210 |
211 | (prn "You can run lein figwheel or lein rebuild-modules.")))
212 |
213 | ;; Boot
214 | (defn prepare
215 | []
216 | (init-external-modules)
217 | (enable-source-maps)
218 | (write-main-js)
219 | (write-env-dev)
220 | (watch-for-external-modules))
221 |
--------------------------------------------------------------------------------
/examples/re-frame/uiexplorer/js/figwheel-bridge.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Originally taken from https://github.com/decker405/figwheel-react-native
3 | *
4 | * @providesModule figwheel-bridge
5 | */
6 |
7 | var CLOSURE_UNCOMPILED_DEFINES = null;
8 | var debugEnabled = false;
9 |
10 | var config = {
11 | basePath: "target/",
12 | googBasePath: 'goog/',
13 | serverPort: 19001
14 | };
15 |
16 | var React = require('react');
17 | var ReactNative = require('react-native');
18 | var WebSocket = require('WebSocket');
19 | var createReactClass = require('create-react-class');
20 | var self;
21 | var scriptQueue = [];
22 | var serverHost = null; // will be set dynamically
23 | var fileBasePath = null; // will be set dynamically
24 | var evaluate = eval; // This is needed, direct calls to eval does not work (RN packager???)
25 | var externalModules = {};
26 | var evalListeners = [ // Functions to be called after each js file is loaded and evaluated
27 | function (url) {
28 | if (url.indexOf('jsloader') > -1) {
29 | shimJsLoader();
30 | }
31 | },
32 | function (url) {
33 | if (url.indexOf('/figwheel/client/socket') > -1) {
34 | setCorrectWebSocketImpl();
35 | }
36 | }];
37 |
38 | var figwheelApp = function (platform, devHost) {
39 | return createReactClass({
40 | getInitialState: function () {
41 | return {loaded: false}
42 | },
43 | render: function () {
44 | if (!this.state.loaded) {
45 | var plainStyle = {flex: 1, alignItems: 'center', justifyContent: 'center'};
46 | return (
47 |
48 | Waiting for Figwheel to load files.
49 |
50 | );
51 | }
52 | return this.state.root;
53 | },
54 | componentDidMount: function () {
55 | var app = this;
56 | if (typeof goog === "undefined") {
57 | var url = this.props.url ||
58 | this.props.exp.manifest.bundleUrl;
59 | var hostPort = url.split('/')[2].split(':');
60 | devHost = hostPort[0];
61 |
62 | if (hostPort[1]) {
63 | config.serverPort = hostPort[1];
64 | }
65 |
66 | loadApp(platform, devHost, function (appRoot) {
67 | app.setState({root: appRoot, loaded: true})
68 | });
69 | }
70 | }
71 | })
72 | };
73 |
74 | function logDebug(msg) {
75 | if (debugEnabled) {
76 | console.log(msg);
77 | }
78 | }
79 |
80 | // evaluates js code ensuring proper ordering
81 | function customEval(url, javascript, success, error) {
82 | if (scriptQueue.length > 0) {
83 | if (scriptQueue[0] === url) {
84 | try {
85 | evaluate(javascript);
86 | logDebug('Evaluated: ' + url);
87 | scriptQueue.shift();
88 | evalListeners.forEach(function (listener) {
89 | listener(url)
90 | });
91 | success();
92 | } catch (e) {
93 | console.error(e);
94 | error();
95 | }
96 | } else {
97 | setTimeout(function () {
98 | customEval(url, javascript, success, error)
99 | }, 5);
100 | }
101 | } else {
102 | console.error('Something bad happened...');
103 | error()
104 | }
105 | }
106 |
107 | var isChrome = function () {
108 | return typeof importScripts === "function"
109 | };
110 |
111 | function asyncImportScripts(url, success, error) {
112 | logDebug('(asyncImportScripts) Importing: ' + url);
113 | scriptQueue.push(url);
114 | fetch(url)
115 | .then(function (response) {
116 | return response.text()
117 | })
118 | .then(function (responseText) {
119 | return customEval(url, responseText, success, error);
120 | })
121 | .catch(function (error) {
122 | console.error(error);
123 | return error();
124 | });
125 | }
126 |
127 | function syncImportScripts(url, success, error) {
128 | try {
129 | importScripts(url);
130 | logDebug('Evaluated: ' + url);
131 | evalListeners.forEach(function (listener) {
132 | listener(url)
133 | });
134 | success();
135 | } catch (e) {
136 | console.error(e);
137 | error()
138 | }
139 | }
140 |
141 | // Loads js file sync if possible or async.
142 | function importJs(src, success, error) {
143 | if (typeof success !== 'function') {
144 | success = function () {
145 | };
146 | }
147 | if (typeof error !== 'function') {
148 | error = function () {
149 | };
150 | }
151 |
152 | var file = fileBasePath + '/' + src;
153 |
154 | logDebug('(importJs) Importing: ' + file);
155 | if (isChrome()) {
156 | syncImportScripts(serverBaseUrl("localhost") + '/' + file, success, error);
157 | } else {
158 | asyncImportScripts(serverBaseUrl(serverHost) + '/' + file, success, error);
159 | }
160 | }
161 |
162 | function interceptRequire() {
163 | var oldRequire = window.require;
164 | console.info("Shimming require");
165 | window.require = function (id) {
166 | console.info("Requiring: " + id);
167 | if (externalModules[id]) {
168 | return externalModules[id];
169 | }
170 | return oldRequire(id);
171 | };
172 | }
173 |
174 | function compileWarningsToYellowBox() {
175 | var log = window.console.log;
176 | var compileWarningRx = /Figwheel: Compile/;
177 | var compileExceptionRx = /Figwheel: Compile Exception/;
178 | var errorInFileRx = /Error on file/;
179 | var isBuffering = false;
180 | var compileExceptionBuffer = "";
181 | window.console.log = function (msg) {
182 | log.apply(window.console, arguments);
183 | if (compileExceptionRx.test(msg)) { // enter buffering mode to get all the messages for exception
184 | isBuffering = true;
185 | compileExceptionBuffer = msg + "\n";
186 | } else if (errorInFileRx.test(msg) && isBuffering) { // exit buffering mode and log buffered messages to YellowBox
187 | isBuffering = false;
188 | console.warn(compileExceptionBuffer + msg);
189 | compileExceptionBuffer = "";
190 | } else if (isBuffering) { //log messages buffering mode
191 | compileExceptionBuffer += msg + "\n";
192 | } else if (compileWarningRx.test(msg)) {
193 | console.warn(msg);
194 | }
195 | };
196 | }
197 |
198 | function serverBaseUrl(host) {
199 | return "http://" + host + ":" + config.serverPort
200 | }
201 |
202 | function setCorrectWebSocketImpl() {
203 | figwheel.client.socket.get_websocket_imp = function () {
204 | return WebSocket;
205 | };
206 | }
207 |
208 | function loadApp(platform, devHost, onLoadCb) {
209 | serverHost = devHost;
210 | fileBasePath = config.basePath;
211 |
212 | // callback when app is ready to get the reloadable component
213 | var mainJs = '/env/main.js';
214 | evalListeners.push(function (url) {
215 | if (url.indexOf(mainJs) > -1) {
216 | onLoadCb(env.main.root_el);
217 | console.info('Done loading Clojure app');
218 | }
219 | });
220 |
221 | if (typeof goog === "undefined") {
222 | console.info('Loading Closure base.');
223 | interceptRequire();
224 | compileWarningsToYellowBox();
225 | importJs('goog/base.js', function () {
226 | shimBaseGoog();
227 | importJs('cljs_deps.js');
228 | importJs('goog/deps.js', function () {
229 | // This is needed because of RN packager
230 | // seriously React packager? why.
231 | var googreq = goog.require;
232 |
233 | googreq('figwheel.connect.build_main');
234 | });
235 | });
236 | }
237 | }
238 |
239 | function startApp(appName, platform, devHost) {
240 | ReactNative.AppRegistry.registerComponent(
241 | appName, () => figwheelApp(platform, devHost));
242 | }
243 |
244 | function withModules(moduleById) {
245 | externalModules = moduleById;
246 | return self;
247 | }
248 |
249 | // Goog fixes
250 | function shimBaseGoog() {
251 | console.info('Shimming goog functions.');
252 | goog.basePath = 'goog/';
253 | goog.writeScriptSrcNode = importJs;
254 | goog.writeScriptTag_ = function (src, optSourceText) {
255 | importJs(src);
256 | return true;
257 | };
258 | }
259 |
260 | // Figwheel fixes
261 | // Used by figwheel - uses importScript to load JS rather than