Fork me on GitHub
#cljsrn
<
2019-02-22
>
thheller09:02:38

hello everyone. I'm adding support for react-native in shadow-cljs and could use some help testing things done by people that do actual react-native development and know the platform. Support is already pretty good (I think) and less manual than re-natal (I think) so all feedback is welcome. https://www.reddit.com/r/Clojure/comments/at8wkd/react_native_expo_with_shadowcljs/

🎉 5
thheller09:02:42

only tried with expo so far but I want plain react-native support as well. I think everything should be setup to make that work already but I'm not sure

vikeri09:02:24

@thheller Great! Could you provide some brief motivations for why someone should switch from re-natal?

thheller09:02:03

well the primary focus of shadow-cljs has been to make life easier and integrate with npm

thheller09:02:36

I want that to apply to react-native builds as well. I have never done any re-natal development but it seems to require working around a bunch of stuff and calling manual commands to use certain npm packages and stuff

thheller09:02:23

so none of the extra commands are required

thheller09:02:15

I also heard that you can't use the latest react-native/expo version and are stuck on older ones? not sure if true but given that this requires zero hacks on the .js side a version upgrade is never a problem

thheller09:02:42

eg. the demos were created by expo init ... which is the latest version I believe

vikeri09:02:48

I’m not using expo so I couldn’t testify to that

vikeri09:02:47

Since the metro bundler solves the npm bundling that value is arguably less than for web browser when shadow-cljs seems like a huge improvement. Our main issues are (first commit in project March 2016): - Forgetting externs that then causes problems - Bundling with metro taking ages - Very hard to get sourcemaps to work for prod build (needs integration with metro)

thheller09:02:40

so in the past I tried finding ways to work around metro so that is doesn't process the generated CLJS output but it doesn't seem setup in a way that would allow that

thheller09:02:15

source maps I did not get to work properly either. again looks like a metro issue?

vikeri09:02:07

Yeah, I was digging very deep into the metro bundler trying to get sourcemaps to work, but it wasn’t straightforward and I gave up when other stuff had to be done

thheller09:02:09

I haven't looked intro metro much. maybe there are options that would be useful?

vikeri09:02:47

The problem I had was that when I looked at it they had just switched to metro from RN Packager so the codebase was changing dramatically every release

thheller09:02:08

there is this which makes it sounds like its primarily a performance problem https://github.com/facebook/metro/issues/104

vikeri09:02:19

Yes that’s exactly it!

vikeri09:02:30

So, they invented a new source-map format at facebook. Good for them. Explains why I had a hard time understanding it facepalm

thheller09:02:14

in create-react-app builds it is possible to supply a .babelrc to ignore all generated code and skip its processing

thheller09:02:30

not sure if that is also possible. not sure if babel is even used.

thheller09:02:49

ok it is used but completely bypassing the babel step doesn't work. so I guess one would just need to find the minimal set of babel plugins to run

vikeri09:02:07

What would be VERY nice that I think shadow-cljs is in a unique position to do is to bypass the entire metro-bundler for prod builds.

vikeri09:02:55

Compile the external libs with babel-react-native and then add the js wrapper that metro generates around the other code.

vikeri09:02:12

That would be a dream come true

thheller09:02:20

I don't think that is possible given their "ram" bundles and stuff

vikeri09:02:33

ram bundles?

thheller09:02:35

but yes I explored this approach before. let metro bundle all the JS stuff + assets and then merge the CLJS code into that after the fact

thheller09:02:04

that worked well to some extent but any update in the expo tools broke it

thheller09:02:29

since I had to reverse engineer the client<->server interaction so I wouldn't do that again

vikeri09:02:11

Ok, that’s unfortunate.

vikeri09:02:43

Another hack could be to bundle everything with a simple js file that just requires all the deps and then in the final bundle replace the bundled js-file with the compiled cljs.

thheller09:02:47

yeah that would be nice but is there a hook to do that?

vikeri09:02:02

Nope, just marking the beginning of the js file with a console.log("STARTFILE") and the end with console.log("ENDFILE") and then just do a brute text replace of everything inbetween 😛

vikeri09:02:51

But the best way would be to support compile-to-js languages in metro. But since ReasonML compiles more straightforwardly to js they don’t need it and they already support flow and typescript natively in metro.

vikeri09:02:19

So I doubt fb will go through any effort to help us out there.

thheller09:02:39

I still have no clue how this stuff actually ends up in the native app part since I have only used expo so far

thheller09:02:51

my primary concern is that the more hacks you add the more things break in later versions

thheller09:02:12

the approach I took will basically never break since it looks like normal .js to whatever metro/expo see

vikeri09:02:41

Yep that’s true

thheller09:02:09

would be nice if there was a way to just create a babel preset that does nothing but process the source maps correctly

vikeri09:02:10

And with advancced compilation it doesn’t take too long to compile it even though babel goes over it

thheller09:02:07

hmm I'll look at how the typescript support works. maybe something in there could be re-used.

vikeri09:02:59

Possibly, I’m afraid it might be similar to Reason though, one .ts -> one .js, and that is what metro seems to be optimized for.

vikeri09:02:01

Another cool idea would be to have a cpu heavy tool like this not be written in node. Would be interesting to see how fast it could be if it was written in Java, Rust, OCaml or similar.

thheller09:02:04

that was easy

thheller09:02:35

.babelrc in the app directory

{
    overrides:[
        { plugins: [] }
    ]
}

thheller09:02:52

[10:54:47] Finished building JavaScript bundle in 5098ms.

vikeri09:02:42

That’s amazing.

thheller09:02:48

hmm wait .. there has to be some cache involved somewhere

thheller09:02:03

[10:58:28] Finished building JavaScript bundle in 1646ms. this can't be right

thheller10:02:50

ok but at least it seems possible to override the plugins used. so we just need one that handles source maps properly

vikeri10:02:14

That’s ideal, and then you cache the compilation of the npm deps with babel so you only have to compile cljs?

thheller10:02:14

hmm AFAICT the default behaviour is already good enough

thheller10:02:28

once the cache is warm [11:20:44] Finished building JavaScript bundle in 1930ms.

vikeri10:02:45

For a prod build? That’s awesome

thheller10:02:51

no dev build

thheller10:02:26

Building JavaScript bundle: finished in 3281ms. consuming an :advanced compiled build

thheller10:02:29

seems reasonable

thheller10:02:45

but its just the basic test build I have setup which does basically nothing

thheller10:02:56

not sure an actual app would take

thheller10:02:25

also still using yarn start. not the slightest clue how I'd make a release build with expo 😛

mdhaney15:02:36

To make a release build with Expo, first create an account with them (free). Then run ‘expo login’ to store your credentials (only have to do this once). Once setup, to do a release just build your CLJS file first, then run ‘expo publish’. When it’s done, you can install the Expo app on your phone, login to your account, and you will see your app listed to run. I’m still working on porting everything over to shadow-cljs. Should be done later tonight or tomorrow (I have a couple of appointments today, not sure how productive the day will be). I’ll also report on the publish times, since I noticed they jumped dramatically from when I had a skeleton app (5 mins, maybe less) to where we are now, which takes about 25-30 minutes.

vikeri10:02:18

Ok, something very interesting would be to compare the build times for a bigger app like status: https://github.com/status-im/status-react

thheller10:02:11

ah good idea. I'll see if I can get that to build

thheller10:02:58

hmm I'm totally lost in that repo. there is no package.json but there are both deps.edn and project.clj. no idea how any of it works together. I'll check it out later if I find some time.

5
yenda17:02:35

The package.json is in mobile_files dir because we also build for react-native-desktop with different deps

yenda17:02:39

You can ping me as well if you have questions. Check the makefile if you are looking for an entry point. 'make prepare-android' for instance then 'make watch-android-avd' and 'make run-android' with an emulator running and you have a figwheel repl with hot reload.

yenda17:02:21

Also the project is powered by clj-rn not re-natal

vikeri11:02:10

Maybe @rasom or @andre could answer how to navigate the repo 🙂