├── .watchmanconfig ├── assets ├── icon.png ├── splash.png └── shadow-cljs.png ├── babel.config.js ├── externs └── app.txt ├── .gitignore ├── shadow-cljs.edn ├── package.json ├── app.json ├── README.md └── src └── main └── test └── app.cljs /.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thheller/fulcro-expo/HEAD/assets/icon.png -------------------------------------------------------------------------------- /assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thheller/fulcro-expo/HEAD/assets/splash.png -------------------------------------------------------------------------------- /assets/shadow-cljs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thheller/fulcro-expo/HEAD/assets/shadow-cljs.png -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | return { 4 | presets: ['babel-preset-expo'], 5 | }; 6 | }; 7 | -------------------------------------------------------------------------------- /externs/app.txt: -------------------------------------------------------------------------------- 1 | # fulcro doesn't properly type hint these since they are usually covered 2 | # by react externs. we are not processing any JS however so those are missing 3 | render 4 | props 5 | state -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/**/* 2 | .expo/* 3 | npm-debug.* 4 | *.jks 5 | *.p12 6 | *.key 7 | *.mobileprovision 8 | out/ 9 | .shadow-cljs/ 10 | .nrepl-port 11 | pom.xml 12 | .idea/ 13 | *.iml 14 | app/ 15 | -------------------------------------------------------------------------------- /shadow-cljs.edn: -------------------------------------------------------------------------------- 1 | ;; shadow-cljs configuration 2 | {:source-paths 3 | ["src/dev" 4 | "src/main" 5 | "src/test"] 6 | 7 | :dependencies 8 | [[fulcrologic/fulcro "2.8.1"]] 9 | 10 | :builds 11 | {:app 12 | {:target :react-native 13 | :init-fn test.app/init 14 | :output-dir "app" 15 | :devtools {:autoload true 16 | :preloads [shadow.expo.keep-awake]}}}} 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "node_modules/expo/AppEntry.js", 3 | "scripts": { 4 | "start": "expo start", 5 | "android": "expo start --android", 6 | "ios": "expo start --ios", 7 | "eject": "expo eject" 8 | }, 9 | "dependencies": { 10 | "expo": "^32.0.0", 11 | "react": "16.5.0", 12 | "react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz", 13 | "shadow-cljs": "^2.8.24" 14 | }, 15 | "devDependencies": { 16 | "babel-preset-expo": "^5.0.0" 17 | }, 18 | "private": true 19 | } 20 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "expo": { 3 | "name": "hello-world", 4 | "slug": "fulcro-expo", 5 | "privacy": "public", 6 | "entryPoint":"./app/index.js", 7 | "sdkVersion": "32.0.0", 8 | "platforms": [ 9 | "ios", 10 | "android" 11 | ], 12 | "version": "1.0.0", 13 | "orientation": "portrait", 14 | "icon": "./assets/icon.png", 15 | "splash": { 16 | "image": "./assets/splash.png", 17 | "resizeMode": "contain", 18 | "backgroundColor": "#ffffff" 19 | }, 20 | "updates": { 21 | "fallbackToCacheTimeout": 0 22 | }, 23 | "assetBundlePatterns": [ 24 | "**/*" 25 | ], 26 | "ios": { 27 | "supportsTablet": true 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | $ yarn 3 | $ shadow-cljs watch app 4 | ;; wait for first compile to finish or expo gets confused 5 | $ yarn start 6 | 7 | ;; production build 8 | $ shadow-cljs release app 9 | ;; no idea what to do for expo 10 | ``` 11 | 12 | ## Notes 13 | 14 | The `:app` build will create an `app/index.js`. In `release` mode that is the only file needed. In dev mode the `app` directory will contain many more `.js` files. 15 | 16 | `:init-fn` is called after all files are loaded and in the case of `expo` must render something synchronously as it will otherwise complain about a missing root component. The `shadow.expo/render-root` takes care of registration and setup. 17 | 18 | You should disable the `expo` live reload stuff and let `shadow-cljs` handle that instead as they will otherwise interfere with each other. 19 | 20 | Source maps don't seem to work properly. `metro` propably doesn't read input source maps when converting sources as things are correctly mapped to the source .js files but not their sources. 21 | 22 | Initial load in dev is quite slow since `metro` processes the generated `.js` files. 23 | -------------------------------------------------------------------------------- /src/main/test/app.cljs: -------------------------------------------------------------------------------- 1 | (ns test.app 2 | (:require 3 | ["expo" :as ex] 4 | ["react-native" :as rn] 5 | ["react" :as r] 6 | [fulcro.client :as fc] 7 | [fulcro.client.primitives :as fp :refer (defsc)] 8 | [shadow.expo :as expo] 9 | )) 10 | 11 | ;; must use defonce and must refresh full app so metro can fill these in 12 | ;; at live-reload time `require` does not exist and will cause errors 13 | ;; must use path relative to :output-dir 14 | 15 | (defonce splash-img (js/require "../assets/shadow-cljs.png")) 16 | 17 | (defonce root-ref (atom nil)) 18 | 19 | (defonce app-ref (atom nil)) 20 | 21 | (def styles 22 | ^js (-> {:container 23 | {:flex 1 24 | :backgroundColor "#fff" 25 | :alignItems "center" 26 | :justifyContent "center"} 27 | :title 28 | {:fontWeight "bold" 29 | :fontSize 24 30 | :color "blue"}} 31 | (clj->js) 32 | (rn/StyleSheet.create))) 33 | 34 | (defsc Root [this props] 35 | {:initial-state 36 | (fn [p] 37 | {::foo "hello world"}) 38 | 39 | :query 40 | [::foo]} 41 | 42 | (r/createElement rn/View #js {:style (.-container styles)} 43 | (r/createElement rn/Text #js {:style (.-title styles)} "Hello!") 44 | (r/createElement rn/Image #js {:source splash-img :style #js {:width 200 :height 200}}) 45 | (r/createElement rn/Text nil (pr-str props)))) 46 | 47 | (defn start 48 | {:dev/after-load true} 49 | [] 50 | (reset! app-ref (fc/mount @app-ref Root :i-got-no-dom-node))) 51 | 52 | (defn init [] 53 | (let [app 54 | (fc/make-fulcro-client 55 | {:client-did-mount 56 | (fn [{:keys [reconciler] :as app}]) 57 | 58 | :reconciler-options 59 | {:root-render expo/render-root 60 | :root-unmount (fn [node])}})] 61 | 62 | (reset! app-ref app) 63 | (start))) 64 | 65 | --------------------------------------------------------------------------------