The fastest way a ClojureScript coder can get started with React Native. Prove me wrong.
This is an example project using: shadow-cljs, React Native, Expo, Reagent, and re-frame.
Here follows instructions for getting started either using Calva or the command line or, and assuming you have stuff like XCode, or whatever is the Android equivalents, installed:
Open the project in VS Code. Then:
- In a Terminal pane, execute
npm install -g expo-cli
- Then
yarn
and wait for it to finish. - Run the Calva command Start a Project REPL and Connect (aka Jack-in)
- Select the project type
shadow-cljs
. - Select to start the
:app
build. - Wait for shadow to build the project.
- Select the project type
- Then Start build task. This will start Expo and the Metro
builder. Wait for it to fire up Expo DevTools in your browser.
- Start the app on your phone or in a simulator or in browser.
- In the Expo settings for your app (shake or force touch with two fingers), disable Live Reloadinhg and Hot Reloading. (Don't worry, shadow-cljs will take care of hot reloading for you, in the most beautiful way.)
- When the app is running in your phone/simulator the Calva CLJS REPL can be used.
- Hack away!
Open Emacs and a bash shell:
-
In the shell, execute
npm install -g expo-cli shadow-cljs
-
Then
yarn
and wait for it to finish. -
Then run
shadow-cljs compile :app
to perform an initial build of the app. -
In Emacs open one of the files in the project (
deps.edn
is fine) -
From that buffer, do
cider-jack-in-clojurescript
[C-c M-J] to launch a REPL. Follow the series of interactive prompts in the minibuffer:- select
shadow-cljs
as the command to launch - select
shadow
as the repl type - select
:app
as the build to connect - and optionally answer
y
orn
to the final question about opening theshadow-cljs
UI in a browser. At this pointshadow-cljs
will be watching the project folder and running new builds of the app if any files are changed. You'll also have a REPL prompt, however the REPL doesn't work because it isn't connected to anything. The app isn't running yet.
- select
-
In a shell run
yarn ios
(same asexpo start -i
). This starts the Metro bundler, perform the bundling, launch the iPhone simulator, and transmit the bundled app. Be patient at this step as it can take many seconds to complete. When the app is finally running expo will display the message:WebSocket connected! REPL init successful
-
Once you see that the REPL is initalized, you can return to Emacs and confirm the REPL is connected and functional:
cljs.user> (js/alert "hello world!")
Which should pop-up a modal alert in the simulator, confirming the app is running and the REPL is connected end to end.
Follow the steps in the Command line section below then come back here.
Open a file like src/main/example/app.cljs
in vim.
Find the nrepl port printed by the previous watch command (here 38369) and:
:Connect 38369
=>
Connected to nrepl://localhost:38369/
Scope connection to: ...
(ENTER)
Then enter into the CLJS session:
:CljEval (shadow/nrepl-select :app)
=>
To quit, type: :cljs/quit
[:selected :app]
(ENTER)
More explanations in the doc for shadow-cljs
Now enjoy fireplace commands!
For example to increment the counter add this snippet in the file (no need to save the file):
(comment
(rf/dispatch [:inc-counter]))
Place your cursor somewhere on the "rf/dispatch" and hit cpp
.
The counter should be incremented on your phone.
$ npm install -g expo-cli
$ yarn
$ yarn watch app
# wait for first compile to finish or expo gets confused
# on another terminal tab/window:
$ yarn start
This will run Expo DevTools at http://localhost:19002/
To run the app in browser using expo-web (react-native-web), press w
in the same terminal after expo devtools is started.
This should open the app automatically on your browser after the web version is built. If it does not open automatically, open http://localhost:19006/ manually on your browser.
Note that you can also run the following instead of yarn start
to run the app in browser:
# same as expo start --web
$ yarn web
# or
# same as expo start --web-only
$ yarn web-only
Then use your editor of choice to hook up the REPL and such.
Once the app is deployed and opened in phone/simulator/emulator/browser, connect to the nrepl on port printed by the watch command and run the following:
(shadow/nrepl-select :app)
(js/alert "Hello from Repl")
A production build invloves first asking shadow-cljs to build a relase, then to ask Expo to work in Production Mode.
NB: Currently there's a bug in the metro bundler that causes release builds to fail in Production Mode. This project includes a way to patch it (nicked from here). Patch by executing: patch node_modules/metro/src/JSTransformer/worker.js ./etc/metro-bundler.patch
- Kill the watch and expo tasks.
- Execute
shadow-cljs release app
- Start the expo task (as per above)
- Enable Production mode.
- Start the app.
If you get complaints about Module HMRClient is not a registered callable module*, you probably have Hot reloading enabled. Disable it and try again.
This repository provides a baseline setup for a React Native application. However newcomers may still have problems getting up in running "in 3 minutes" because of obscure dependencies on supporting tools such as the Java and Node runtimes. So while we can't definitively show every viable configuration, we can at least maintain what's known to work, especially when dependencies are bumped.
Expo SDK | 35 | 35 |
---|---|---|
clojure | 1.10.1 | 1.10.1 |
clojurescript | 1.10.520 | 1.10.597 |
expo-cli | 3.4.1 | 3.9.1 |
expo | 35.0.0 | 35.0.0 |
jdk | openjdk 1.8.0_222 | openjdk 1.8.0_222 |
node | 10.17.0 | 10.17.0 |
re-frame | 0.11.0-rc2 | 0.11.0-rc3 |
react | 16.9.0 | 16.9.0 |
react-native | 0.59.8 | 0.59.8 |
reagent | 0.9.0-rc2 | 0.9.0-rc3 |
shadow-cljs (cli) | 2.8.69 | 2.8.78 |
shadow-cljs (jar) | 2.8.69 | 2.8.78 |
yarn | 1.19.1 | 1.19.1 |
When in doubt, a script is provided in this repo (etc/toolchain-report
) to query what versions you have. This script is NOT needed for app development, building, or releasing, but may come in handy if you're having trouble getting up and running. toolchain-report
requires joker
, a portable and fast dialect of clojure implemented in go. See the joker repo on github for installation instructions.
(This project is built from this example of his: https://github.com/thheller/reagent-expo)
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.
: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.
You should disable the expo
live reload stuff and let shadow-cljs
handle that instead as they will otherwise interfere with each other.
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.
Initial load in dev is quite slow since metro
processes the generated .js
files.
reagent.core
loads reagent.dom
which will load react-dom
which we don't have or need. Including the src/main/reagent/dom.cljs
to create an empty shell. Copied from re-natal.