{"id":13760971,"url":"https://github.com/bhauman/react-native-figwheel-bridge","last_synced_at":"2025-06-11T04:41:46.294Z","repository":{"id":33822670,"uuid":"162190013","full_name":"bhauman/react-native-figwheel-bridge","owner":"bhauman","description":"Enables React Native projects written in ClojureScript to use Figwheel's live reloading and REPL.","archived":false,"fork":false,"pushed_at":"2021-12-06T13:17:27.000Z","size":82,"stargazers_count":79,"open_issues_count":9,"forks_count":11,"subscribers_count":8,"default_branch":"master","last_synced_at":"2024-05-02T00:05:30.467Z","etag":null,"topics":["clojure","clojurescript","figwheel","figwheel-main","npm-module","react-native"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bhauman.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["bhauman"]}},"created_at":"2018-12-17T21:07:08.000Z","updated_at":"2023-08-09T13:17:06.000Z","dependencies_parsed_at":"2022-08-07T23:16:28.740Z","dependency_job_id":null,"html_url":"https://github.com/bhauman/react-native-figwheel-bridge","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhauman%2Freact-native-figwheel-bridge","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhauman%2Freact-native-figwheel-bridge/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhauman%2Freact-native-figwheel-bridge/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bhauman%2Freact-native-figwheel-bridge/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bhauman","download_url":"https://codeload.github.com/bhauman/react-native-figwheel-bridge/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247785864,"owners_count":20995641,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","clojurescript","figwheel","figwheel-main","npm-module","react-native"],"created_at":"2024-08-03T13:01:30.048Z","updated_at":"2025-04-08T05:33:21.317Z","avatar_url":"https://github.com/bhauman.png","language":"JavaScript","funding_links":["https://github.com/sponsors/bhauman"],"categories":["JavaScript"],"sub_categories":[],"readme":"# React Native Figwheel Bridge\n\nEnables React Native projects written in ClojureScript to use\nFigwheel's live reloading and REPL.\n\nThe things discovered here will inform changes to Figwheel-main and\nperhaps the ClojureScript compiler.\n\nThe ultimate goal is to eliminate the need for this library in the\nfirst place and be able to support React Native directly from\nfigwheel-main or even the ClojureScript compiler.\n\nBecause of this, this library is going to primarily be compatible with\n`figwheel-main` for now as I'm not going to be make incremental\nimprovements to both `figwheel-main` and `lein figwheel` during this\nperiod of discovery.\n\nI do advise that you use this library as it represents a very\nstraightforward way to use React Native along with Figwheel.\n\n## Notes on the React Native build environment\n\nWhen you run `npx react-native run-ios` it launches the metro bundler\nwhich basically runs a `babel` based watcher/compiler process with\nsome specific React Native presets. This compiles the `index.js` file\nto a bundle that is loaded by React Native framework code that is\nwritten in Objective-C.\n\nYou can see the Native code that loads the bundle in\n`ios/MyAwesomeProject/AppDelegate.m`.\n\n\u003e The important thing to note about this, is that in terms of relating\n\u003e to ClojureScript and its tools, a React Native project is simply\n\u003e JavaScript that gets loaded into a React Native host environment.\n\nOur goal is to get our compiled ClojureScript into the RN host\nenvironment and establish a REPL connection so that we can get\nreloading, editor integration, etc.\n\nSo this is not the hardest problem but there are a few tricky parts\nand that's where this library comes in.\n\nOne of the tricky parts is the use of `require`. `require` is not just\nused to include JavaScript libraries in React Native projects it's\nalso used to pull in assets like images, data etc. However unlike\nnode-js `require` doesn't actually exist in the JavaScript Core\nruntime environment. The React Native metro bundler process resolves\nand handles all `require`s in JavaScript code at compile time.\n\nHowever, this doesn't work for hot-reloaded compiled ClojureScript\ncode which doesn't get processed by the Metro bundler. So `(js/require\n\"images/splash-logo.png\")` won't work in hot-reloaded code without\nsome sort of intervention.\n\nThe other tricky part for ClojureScript code is to support the\nrequiring of of `npm` modules like `react` and `react-native` in\nClojureScript ns forms like this:\n\n```clojure\n(ns example.main\n  (:require \n    [react :as react]\n    [react-native :as rn]))\n\t\n;; now rn/Text is available here\t\n```\n\nSo there will need to be an intervention for this as well.\n\nWe need to make `require`s available in a global object in the\n`index.js` so that they are available to ClojureScript at\nruntime. ClojureScript helps us here with it's new `:bundle`\ntarget. When using the `:bundle` target the CLJS compiler collects all\nthese npm dependency requires and generates an `npm_deps.js` file which\ncan be processed by the metro bundler.\n\nThe content of the `npm_deps.js` file typically looks like this: \n\n```\nmodule.exports = {\n  npmDeps: {\n    \"react-native\": require('react-native'),\n    \"react\": require('react')  }\n};\n```\n\nFinally, there is one more sticking point when integrating an\noptimizations `:none` ClojureScript build into a React Native tooling\nenvironment.\n\nWhen React Native loads the Metro Compiled bundle it expects the root\nof the React Native component to be registered synchronously when the\nbundle initially loads. Unfortunately right now it is faster and simpler to\nbootstrap and load the ClojureScript application code\nasynchronously. So we have to register a proxy component before the\napplication code loads. This proxy in turn renders your actual\napplication when the application code actually loads.\n\nThis `react-native-figwheel-bridge` library addresses these problems\nand I encourage you to read it and understand it. Reading the code\nshould eliminate much of the mystery and empower you to make your own\ndecisions about how you want to load and run your ClojureScript\napplication.\n\n## Initial setup\n\nFirst you will need to make sure you have React Native and its\ndependencies installed.\n\nOn the https://reactnative.dev/docs/environment-setup page you will\nwant to choose either the `React Native CLI` or the `Expo CLI`.  I\nprefer to start with the React Native CLI as there is less tooling to\ndeal with so its easier to figure out what is going on when you use\nit.\n\nInstall your CLI of choice according to the instructions on that page.\n\nOnce things are installed you can then follow the instructions below\nto get an ClojureScript project setup for Figwheel development.\n\n## Create React Native project\n\n\nInitialize a project:\n\nFor `React Native CLI` do:\n\n```shell\n$ npx react-native init MyAwesomeProject\n```\n\nFor `Expo CLI` do:\n\n```shell\n$ npx expo init MyAwesomeProject\n```\n\nThis will create an initial React Native project. Before you go any\nfurther you will want to ensure that everything is setup so that you can\nlaunch and run your application in a simulator.\n\nChange in into the `MyAwesomeProject` directory and launch a simulator like so:\n\n```shell\n$ npx react-native run-ios # or run-android\n```\n\nIf everything is set up correctly this should launch a phone simulator\nwith the RN application defined in `App.js`.\n\n## Troubleshooting\n\nIf you have any problems with setting up an application please consult\nthe React Native documentation. I really recommend reading all of the\nReact Native Documentation as it is well written and will more than\nlikely save you lots of headaches.\n\nIf everything is up and running go ahead an close everything so that\nwe can setup a ClojureScript application that uses `figwheel-main` to\nsupport hot reloading and a REPL.\n\n## Integrating the ClojureScript and Figwheel \n\nFirst we need to add the `react-native-figwheel-bridge` to our npm\ndependencies:\n\n```shell\n$ yarn add react-native-figwheel-bridge\n```\n\nNow we'll start setting up a basic\n[figwheel.main](https://figwheel.org) project.\n\nCreate a `deps.edn` file in the `MyAwesomeProject` directory:\n\n```clojure\n{:deps {org.clojure/clojurescript {:mvn/version \"1.10.764\"}\n        com.bhauman/figwheel-main {:mvn/version \"0.2.5\"}}}\n```\n\nCreate a `ios.cljs.edn` file in the `MyAwesomeProject` directory:\n\n```clojure\n^{:open-url false\n  :cljs-devtools false}\n{:main awesome.main\n :target :bundle}\n```\n\nCreate a `src/awesome/main.cljs` file in the `MyAwesomeProject` directory:\n\n```clojure\n(ns awesome.main\n  (:require [react]\n            [react-native :as rn]))\n\n(def \u003c\u003e react/createElement)\n\n(defn renderfn [props]\n  (\u003c\u003e rn/View\n      #js {:style #js {:backgroundColor \"#FFFFFF\"\n                       :flex 1\n                       :justifyContent \"center\"}}\n      (\u003c\u003e rn/Text\n          #js {:style #js {:color \"black\"\n                           :textAlign \"center\"}}\n          (str \"HELLO\"))))\n\n;; the function figwheel-rn-root must be provided. It will be called by \n;; react-native-figwheel-bridge to render your application. \n;; You can configure the name of this function with config.renderFn\n(defn figwheel-rn-root []\n  (renderfn {}))\n```\n\nNext we need to create the index file to start our Clojurescript\napplication this file will be different depending on which CLI tool we\nare using.\n\nThe index file is the file that will be bundled by React Native\ntooling.\n\n## React Native CLI Index.js\n\nEdit the `index.js` file in the `MyAwesomeProject` directory:\n\n```javascript\nimport {AppRegistry} from 'react-native';\nimport {name as appName} from './app.json';\nimport {npmDeps} from \"./target/public/cljs-out/ios/npm_deps.js\";\n\n// you can add other items to npmDeps here\n// npmDeps[\"./assets/logo.png\"]= require(\"./assets/logo.png\");\n\n// this url points to a file generated by the cljs compiler in the output-dir of your app\nvar options = {optionsUrl: \"http://localhost:19001/target/public/cljs-out/ios/cljsc_opts.json\"};\n\nvar figBridge = require(\"react-native-figwheel-bridge\");\nfigBridge.shimRequire(npmDeps);\nAppRegistry.registerComponent(appName,\n                              () =\u003e figBridge.createBridgeComponent(options));\n```\n\nNow we are ready to launch our ClojureScript application:\n\nFirst we will start the `figwheel-main` process to watch and compile\nand create a Websocket for REPL communication.\n\n```shell\n$ clj -m figwheel.main -b ios -r\n```\n\nThe in another terminal window change into the `MyAwesomeProject`\ndirectory and start `react-native` \n\n```shell\n$ npx react-native run-ios\n```\n\nWhen using `figwheel-main` figwheel bridge will take care of auto\nrefreshing the application for you when figwheel reloads code.\n\nYou can see this behavior by editing the `src/awesome/main.cljs`\nfile. Try changing the `\"HELLO\"` to `\"HELLO THERE\"`. You should see\nthe application change when you save `src/awesome/main.cljs`.\n\n## Expo CLI Index.js\n\nCreate an `index.js` file in the `MyAwesomeProject` directory:\n\n```javascript\nimport { registerRootComponent } from 'expo';\nimport {npmDeps} from \"./target/public/cljs-out/ios/npm_deps.js\";\n\nvar options = {optionsUrl: \"http://localhost:19001/target/public/cljs-out/ios/cljsc_opts.json\"};\n\nvar figBridge = require(\"react-native-figwheel-bridge\");\nfigBridge.shimRequire(npmDeps);\nregisterRootComponent(figBridge.createBridgeComponent(options));\n```\n\nNow we have to **expo** that we want to use this `index.js` as the\nentry point to our application.\n\nEdit `package.json` and change `\"main\": \"node_modules/expo/AppEntry.js\"` to\n`\"main\": \"index.js\"`.\n\nNow we are ready to launch our ClojureScript application:\n\nFirst we will start the `figwheel-main` process to watch and compile\nand create a Websocket for REPL communication.\n\n```shell\n$ clj -m figwheel.main -b ios -r\n```\n\nThe in another terminal window change into the `MyAwesomeProject`\ndirectory and start `expo` \n\n```shell\n$ yarn ios\n```\n\nWhen using `figwheel-main` figwheel bridge will take care of auto\nrefreshing the application for you when figwheel reloads code.\n\nYou can see this behavior by editing the `src/awesome/main.cljs`\nfile. Try changing the `\"HELLO\"` to `\"HELLO THERE\"`. You should see\nthe application change when you save `src/awesome/main.cljs`.\n\n## Configuration options\n\nThese are the options that you can pass in the configuration Object to\n`start`.\n\n`appName`: (required for react-native) the name that you created your React Native\nproject with.\n\n`optionsUrl`: (optional) a url that will resolve to a\n`cljsc_opts.json` file. I modified figwheel-main to output this file as\na JSON version of the `cljsc_opts.edn` file that the ClojureScript\ncompiler outputs. This contains all the information needed to\neffectively boostrap and load a ClojureScript application. If a\n`optionsUrl` is not supplied you will need to supply the `asset-path`,\n`main`, `preloads`, and `closure-defines` options directly.\n\n`renderFn`: (optional) the JS munged name of the function that returns\nthe React elements for your application - defaults to\n`figwheel_rn_root`\n\n`asset-path`: (optional) this a url that resolves to the base of the\n`:output-dir` in most cases this is\n`\"http://localhost:8081/target/public/cljs-out/[[build-name]]\"` and in\nthe current example this would be\n`\"http://localhost:8081/target/public/cljs-out/ios\"`\n\n`main`: (optional) the JS munged namespaces string of your root application\nnamespace ie. `\"my_example.core\"`\n\n`preloads`: (optional) an array of JS munged namespace strings to load\nbefore the `main` ns is loaded.\n\n`closure-defines`: (optional) a JavaScript Object literal that\nprovides custom values for your `goog-defines`. Most importantly this\nshould contain a `figwheel.repl.connect_url` so that `figwheel-main`\nknows where to connect.\n\n## Controlling Reload\n\nAfter everything is loaded a `figwheelBridgeRefresh` function is registered on `goog`. \nYou can call this function to force the root element to reload.\n\nSo for the above example you could set the `autoRefresh` option to false.\n\nIn `index.js` this looks like:\n\n```javascript\nfigBridge.start({appName:   \"MyAwesomeProject\",\n                 optionsUrl: \"http://localhost:8081/target/public/cljs-out/ios/cljsc_opts.json\",\n                 autoRefresh: false // \u003c-- setting auto refresh to false\n                 });\n```\n\nand control reloading via `figwheel.main`'s [reload hooks](https://figwheel.org/docs/hot_reloading.html#reload-hooks)\n\nin `src/awesome/main.cljs` this looks like:\n\n```clojure\n(ns ^:figwheel-hooks awesome.main\n  (:require [react]\n            [react-native :as rn]))\n\n(def \u003c\u003e react/createElement)\n\n(defn renderfn [props]\n  (\u003c\u003e rn/View\n      #js {:style #js {:backgroundColor \"#FFFFFF\"\n                       :flex 1\n                       :justifyContent \"center\"}}\n      (\u003c\u003e rn/Text\n          #js {:style #js {:color \"black\"\n                           :textAlign \"center\"}}\n          (str \"HELLO\"))))\n\n(defn figwheel-rn-root []\n  (renderfn {}))\n\n;; adding the reload hook here\n(defn ^:after-load on-reload [] (goog/figwheelBridgeRefresh))\n```\n\n## Based on previous work\n\nThis code heavily modified from the `figwheel-bridge.js` file in\n`https://github.com/drapanjanas/re-natal` which in turn was taken from\nthe now non-existent\n`https://github.com/decker405/figwheel-react-native`.\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbhauman%2Freact-native-figwheel-bridge","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbhauman%2Freact-native-figwheel-bridge","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbhauman%2Freact-native-figwheel-bridge/lists"}