Fork me on GitHub
#cljsrn
<
2017-07-28
>
jeaye01:07:09

Has anyone seen a cljsjs for react native?

jeaye01:07:52

I know of @mfikes' react-native-externs, but that's it with regard to rn packages.

pesterhazy09:07:43

everyone I know uses the react native packager at the moment

pesterhazy09:07:56

which can consume npm dependencies

pesterhazy09:07:23

the alternative would be to repackage all RN packages - a monumental effort

pesterhazy09:07:43

hopefully the latest changes to the cljs compiler will make things better soon

pesterhazy13:07:15

Does anyone use any service to track bugs with RN? In particular, I'm interested in capturing Javascript exceptions.

pesterhazy14:07:52

Crashlytics....?

austinbirch15:07:36

@pesterhazy I use Sentry (https://sentry.io) and I think it’s pretty good. Haven’t tried anything else recently so don’t have much to compare it to!

austinbirch15:07:59

At the moment I use their native & JS libraries to catch exceptions. This means I end up with ‘duplicated’ exceptions in Sentry, so might move away from that setup eventually.

jdkealy15:07:17

Hey guys, I was wondering. Is re-natal the go-to cljsrn framework right now ?

jdkealy15:07:05

I'm trying to bootstrap a project. Obviously there's a lot less people talking about it than react native with javascript.

pesterhazy15:07:17

@austinbirch thanks for the link! Do they have any explicit support for react-native?

pesterhazy15:07:41

@jdkealy yeah re-natal is definitely the most popular choice

pesterhazy15:07:17

it's a solid choice these days

pesterhazy15:07:18

@jdkealy there was a good intro talk about cljsrn at euroclojure - the video should be released within the next 2 weeks: http://2017.euroclojure.org/using-clojurescript-to-launch/

austinbirch15:07:44

@pesterhazy https://docs.sentry.io/clients/react-native/ Looks like I need to upgrade though! The integration for React Native used to be JS-side (https://github.com/getsentry/raven-js/blob/master/docs/integrations/react-native.rst - this is what I’m currently using), but it seems like they are creating a native-side client that can also handle source mapping for JS exceptions as well. I won’t be upgrading yet though, getting source maps working using the JS client + CLJS + React Native was tricky enough…

jeaye16:07:34

@pesterhazy I've just recently brought in react-native-firebase, which has crash reporting.

jeaye16:07:49

I think it uses Crashylitics.

jeaye16:07:22

Are any of you running into the babel timeout issue when packaging compiled JS files?

jeaye16:07:11

With :simple optims, my JS file ends up being ~4MB and the bundling just times out while babel is trying to parse it.

manu16:07:07

Hi! someone tried the facebook login with android? I'm not able to get the access token. I followed all the instructions of this page https://developers.facebook.com/docs/facebook-login/android/ and I'm using Linking as explained in this example. But it is not working 😞 Did someone got the same problem? thanks 🙂

thheller16:07:10

@jeaye the issue is that the react-native packager tries to rewrite the code using all sorts of babel plugins

thheller16:07:28

which simply takes forever but is not needed since CLJS emits ES3

thheller16:07:48

you can add a .babelrc to disable all rewriting (if you are one 0.45+)

jeaye16:07:50

Right, we had tried using a .babelrc with {"plugins":[]} and it didn't change anything, @thheller.

jeaye16:07:55

That's what you were suggesting?

thheller16:07:10

try {"ignore": ["*.js"]}

thheller16:07:29

in the directory of your :simple output file

thheller16:07:59

plugins is weird in that once its enabled it is enabled anywhere (and RN seems to enable some by default)

jeaye16:07:39

That's great info, thank you.

jeaye16:07:34

Does that apply here?

mfikes16:07:59

FWIW, even though :simple leads to less hassle with externs, :advanced results in code that loads in JavaScriptCore more quickly (for me it shaves a second off launch time on an older device)

thheller16:07:49

@jeaye never tested .json files but probably?

pesterhazy16:07:18

yeah I'm seeing exactly that issue

thheller16:07:24

:advanced is always worth it IMHO 🙂

pesterhazy16:07:34

TransformError: /Users/me/project/index.ios.js: Cannot read property 'tokens' of undefined

jeaye16:07:05

We're also looking into :advanced, @mfikes, but that's a can of worms itself.

pesterhazy16:07:43

@thheller how did you get this to work? was it on an earlier version of the packager?

thheller16:07:13

works since 0.45+

pesterhazy16:07:15

I'm on 0.44.2

thheller16:07:35

0.42 broke the local .babelrc, 0.45 fixed it again

jeaye16:07:36

We're on 0.44.0

pesterhazy16:07:42

Ok I just tried 0.45 and it's better

pesterhazy16:07:49

This works for me:

{"presets": ["react-native"], "ignore": ["index.ios.js"]}

pesterhazy16:07:11

If I ignore all .js files, it'll fail with some node modules that use import etc.

jeaye16:07:14

Gah, gotta give that a go.

pesterhazy16:07:45

0.45 also made the whole thing drastically slower apparently - it runs out of mem without the .babelrc

mfikes16:07:58

Hah. You can see how code on ClojureScript master avoids using keywords in JavaScript object literals where they would not be legal:

(.-PanResponder (js/require "react-native"))
yields
#js {"_initializeGestureState" #object[_initializeGestureState],
     "_updateGestureStateOnMove" #object[_updateGestureStateOnMove],
     :create #object[create]}

pesterhazy16:07:04

@mfikes which keyword do you mean?

mfikes16:07:25

:_initializeGestureState would not be a legal keyword

pesterhazy16:07:51

because of the leading underscore?

mfikes16:07:16

The main benefit is working properly with things like (js-obj "foo bar" 1)

mfikes16:07:36

#js {"foo bar" 1} will be printed, which round-trips

pesterhazy16:07:16

@mfikes ah now I understand - the #js literals use string instead of keywords as keys

mfikes16:07:58

Yeah, it is extremely rare to need the feature, but it addresses a corner case in the way the literals were previously printed.

jeaye16:07:06

@pesterhazy Don't forget about Android!

jeaye16:07:22

You'll need "index.android.js" in there, too.

jeaye16:07:04

When I upgrade to 0.45.0 and add that babelrc, it takes a few minutes and then I run out of memory.

pesterhazy16:07:24

really? where did you put that file

jeaye16:07:27

I have 16GB, so that's not quite reasonable.

jeaye16:07:40

My .babelrc is in the root of the project.

pesterhazy16:07:46

yeah node doesn't get that big of a heap anyway

jeaye16:07:53

That's where the index.android.js is generated.

pesterhazy17:07:41

can you try this?

pesterhazy17:07:43

react-native bundle --reset-cache --entry-file index.ios.js --bundle-output main.jsbundle

pesterhazy17:07:25

hm that's kind of what you're doing anyway....

pesterhazy17:07:39

so that line takes 24seconds for me

pesterhazy17:07:10

can you cat .babelrc ?

jeaye17:07:15

I might have a much larger app. It's still running, but it outputted some syntax errors.

pesterhazy17:07:35

ls -l index.*

jeaye17:07:38

I have no .bundlerc

pesterhazy17:07:54

sorry babelrc

jeaye17:07:58

I have an index.android.js

pesterhazy17:07:07

$ ll index.*
-rw-r--r--  1 me  staff   2.6M Jul 28 18:57 index.ios.js

pesterhazy17:07:47

huh maybe that's what makes the difference

jeaye17:07:29

Yeah, exponential time growth relative to size.

pesterhazy17:07:37

try

node --max_old_space_size=4092 $(which react-native) bundle --reset-cache --entry-file index.ios.js --bundle-output main.jsbundle

jeaye17:07:02

Same syntax errors from babylon, but we'll see if/when it finished. The errors are: SyntaxError: 'import' and 'export' may appear only with 'sourceType: module' (3:0)

pesterhazy17:07:33

what? that shouldn't happen if you only ignore index.android.js

pesterhazy17:07:47

ok if I rerun with --dev false it OOMs, with --dev true it works

pesterhazy17:07:50

I'm guessing it's doing "whole program optimizations"

jeaye17:07:06

"whole memory optimizations"

jeaye17:07:58

Trying --dev true. Been 60s so far.

jeaye17:07:55

I've had a guy on this task for a week and we're still fighting it. Your help has been great progress though, thanks.

pesterhazy17:07:56

so moving from 0.44 -> 0.45 actually makes things worse - it doesn't bundle with --dev false anymore

jeaye17:07:26

Mk, I can try --dev false on 0.44

jeaye17:07:48

That wouldn't have the ignore though, I think.

pesterhazy17:07:51

so 0.44 with --dev false, using mx_old_space and the standard .babelrc works for me

pesterhazy17:07:10

node v8.2.1 if that matters

pesterhazy17:07:29

did --dev true complete?

jeaye17:07:31

Same here.

jeaye17:07:40

No, not on 0.45.

jeaye17:07:07

On 0.44, with all those flags, I just got Cannot read property 'tokens' of undefined

pesterhazy17:07:19

right, same for me

pesterhazy17:07:27

I need to use the stock re-natal .babelrc

jeaye17:07:54

That is just {"presets":["react-native"]}?

pesterhazy17:07:02

that should work

jeaye17:07:06

So, it we're back to 0.44 and no ignores, I'd expect just a timeout.

jeaye17:07:17

Why did it not timeout for you this time?

pesterhazy17:07:22

on 0.44 the packager doesn't timeout for me

jeaye17:07:54

Ah, likely because you have a smaller JS index.

jeaye17:07:19

I can try with --dev true, but I think 0.44 is just going to timeout for me and I need those ignores.

pesterhazy17:07:43

it would be good to know which steps actually fails, the transformation step or the full-program optimization step

pesterhazy17:07:11

it would be even better if the RN packager authors cared about this issue a bit more

jeaye17:07:42

Hell yeah it would.

jeaye17:07:48

The transform is what fails, when it times out.

jeaye17:07:45

Based on the error message: Error: TimeoutError: transforming index.android.js took longer than 301 seconds.

pesterhazy17:07:56

ah, wow I never saw that one

jeaye17:07:32

That's the initial issue that we have.

pesterhazy17:07:35

why doesn't it work for you with --dev true

pesterhazy17:07:47

that should do the trick in theory

jeaye17:07:00

Still times out.

pesterhazy17:07:17

during the transformation step?

jeaye17:07:52

I'll get the error again for you, so we can be certain.

pesterhazy17:07:12

that'd be great

pesterhazy17:07:33

maybe we should band together and create a cljsrn issue

jeaye17:07:39

To be clear, I'm on 0.44 running this: node --max_old_space_size=4092 $(which react-native) bundle --reset-cache --dev true --entry-file index.android.js --bundle-output main.jsbundle

jeaye17:07:43

Yeah, whatever it takes. We've spent a lot of time on this bug. Currently, the best approach looks like using :advanced with :infer-externs.

pesterhazy17:07:25

maybe you could strip out some cljs deps too, those that blow up your bundle size

jeaye17:07:25

Not sure of 0.46 is gonna break a lot; I know my guy looked into it for a bit and I'll need to check with him regarding where that lead.

pesterhazy17:07:47

that's not too bad

jeaye17:07:04

Ok, with 0.44 and --dev true, I get: TimeoutError: transforming index.android.js took longer than 301 seconds.

pesterhazy17:07:21

and with 0.45?

pesterhazy17:07:51

no idea why your bundle is so much bigger

pesterhazy17:07:06

i imagine you don't have 2M of clojurescript code?

jeaye17:07:59

Doubt it.

jeaye17:07:33

Only 3639 lines across all sources.

zlrth17:07:50

(sorry about the big post) I’d like to refactor/rename my views to be less repetitive. I have

[view {:style (:top-level style)}
       [view {:style (:graph style)}
        [view {:style (:svg-container style)
        ... ]]]
and it’d be nice to have
[view.toplevel
       [view.graph
        [view.svg-container
       ... ]]]
I tried
(defn view-top-level [body] ;; i get `Unexpected Token: .` when I use a `.`
  (fn [body]
    [view {:style (:top-level style)} body]))

but only the first child [view] gets rendered. I should wrap body in something to have all my child views render, yes? I can’t think of what to wrap it with. or is there a different, better way?

jeaye17:07:08

Looks like about 600K of cljs sources, @pesterhazy

pesterhazy17:07:45

that's def. more than what we have

jeaye17:07:20

0.45 with the ignores and --dev true results in an OOM.

jeaye17:07:26

@pesterhazy My guy has made an issue on the metro packager already, but it has no reply. https://github.com/facebook/metro-bundler/issues/23

jeaye17:07:24

Doesn't address the primary issue, but it was the first place we looked since the packager, when it times out, says to provide a new value for that timeout option... but then provides no way of specifying that value. Even when forking it, he's found that 30 minutes isn't long enough to finish the transformation.

jeaye17:07:34

So ignoring very much seemed like the best bet.

jeaye17:07:34

@mfm Try wrapping body like so [body].

jeaye17:07:09

@pesterhazy To complete the report, 0.45 without the ignores and with --dev true also just times out.

jeaye17:07:26

So, no ignores == timeout, ignores == OOM

zlrth17:07:28

@jeaye when I do

(defn view-top-level [body]
  (fn [body]
    [view {:style (:top-level style)} [body]]))
i get Error rendering component--i assume because there’s no (defn body [] ...) component

pesterhazy17:07:35

I think a simple repro repo would help

pesterhazy17:07:38

Re-natal , a bunch of deps and the resulting cljs compiler output committed to the repo

pesterhazy17:07:09

That was the developers could have a look

zlrth17:07:43

sorry @pesterhazy are you talking to me?

jeaye17:07:11

@mfm body is just a function you're passing in. Try using (fn [] and only having body come in through view-top-level.

jeaye17:07:23

@mfm He's talking to me.

pesterhazy17:07:29

No sorry I was still taking about the packager

jeaye17:07:27

Let me know if that works for you; I think it should.

zlrth17:07:57

with this:

(defn view-top-level [body]
  (fn []
    [view {:style (:top-level style)} body]))
i got strange output: half of the top component rendered. nothing from the rest of body. with this:
(defn view-top-level [body]
  (fn []
    [view {:style (:top-level style)} [body]]))
i got Error rendering component

jeaye17:07:00

@pesterhazy Yeah, sounds like that might be needed. Hopefully we can get the :advanced build working as well.

jeaye17:07:20

@mfm What're you passing to view-top-level?

jeaye17:07:46

Whether or not you use [] around body depends on if it's a fn or a vector already.

zlrth17:07:07

a bunch of nested views

jeaye17:07:32

As functions, or [view ...]?

zlrth17:07:43

as [view ...]

jeaye17:07:54

Ok, then you don't want [body] since it's already a vector.

zlrth17:07:59

makes sense

zlrth17:07:25

i wonder why the rest of the views don’t show up

jeaye17:07:38

So you're using this like so: [view-top-level [view ...]]?

zlrth17:07:42

like

[view-top-level
 [view ...
  [view ...
 [view ..
etc
i.e. there are multiple views passed to view-top-level

jeaye17:07:56

You're giving it multiple bodies.

zlrth17:07:03

i am. i should not?

jeaye17:07:16

Your view-top-level expects one param. One view.

jeaye17:07:20

You're giving it multiple.

jeaye17:07:48

So you could wrap all of those params in one view or your could change your view-top-level to accept more.

jeaye17:07:01

Make sense?

zlrth17:07:05

how would i change it to accept more? earlier i meant to ask about wrapping it in something like a do or for loop.

jeaye17:07:11

You could do, for example, (defn view-top-level [& body] (into [view {:style ...}] body)) and then you should be able to pass it arbitrary.

zlrth17:07:34

ah thanks. i have that in a different circumstance. gotcha.

jeaye17:07:44

This is just Clojure data, so you're just merging vectors here.

jeaye18:07:17

user=> (into [1 2] [3 4])
[1 2 3 4]

jeaye18:07:42

Similarly, with views (used keywords so the repl works):

user=> (into [:view {:style {}}] [[:view :blah] [:view :meow]])
[:view {:style {}} [:view :blah] [:view :meow]]

zlrth18:07:40

looks great! thanks @jeaye

jeaye18:07:58

I like it so far.

pesterhazy18:07:22

We could trick the packager into ignoring our bundle

pesterhazy18:07:58

In outline, make a separate index.js with all the requires and a placeholder

pesterhazy18:07:05

Then bundle that

pesterhazy18:07:37

Finally replace the placeholder with the actual cljs compiler output

jeaye18:07:46

Ok, I think I follow so far.

jeaye18:07:35

Also, in making the test repo, I've copied my existing project, removed all the business sources, and left only the deps. If I remove all package.json deps, I can bundle with --dev false in 2.5 minutes.

jeaye18:07:00

That's with like 300 bytes of cljs sources and only the lein deps.

jeaye18:07:03

Adding each dep back in, to see what it does to the build. react + rn give another 30s, which is fine. Something in there must be adding minutes/hours.

jeaye18:07:53

@pesterhazy What would need to be in the separate index.js to get the bundle to work? Just all of the requires which are otherwise in all of the sources?

pesterhazy18:07:26

Basically immediately invoked function with an argument called require

pesterhazy18:07:49

Which is a function that takes a module name and looks it up in a map

pesterhazy18:07:11

This can be generated from . re-natal

pesterhazy18:07:37

I'm terse because I'm on my phone btw

pesterhazy18:07:53

This should be foolproof, i.e. even the RN packager can't screw this up

pesterhazy18:07:21

And similar to how re-natal sets up figwheel

pesterhazy18:07:36

@jeaye good idea to incrementally add code

pesterhazy18:07:00

I'm surprised that it's actually in the code, not in the deps

pesterhazy18:07:00

What pushes it over the edge?

jeaye18:07:37

I'm checking the deps right now, not the code.

jeaye18:07:05

Ok, I have all of our deps now, but only a single source file, and I can package in 2.5 minutes all the same... derp, I'm not requiring any of them.

pesterhazy18:07:58

Maybe the compiler leaves them out if not required

jeaye18:07:59

Yep. Thanks for your patience. 🙂

jeaye18:07:29

Are you privy to the details of how re-natal can generate this mock index?

jeaye18:07:01

Looks like it's nothing re-natal exposes, but may be in its source.

mfikes18:07:08

Hrm. I’m trying to use RCT_EXPORT_MODULE(); per the CalendarManager example at https://facebook.github.io/react-native/docs/native-modules-ios.html and when I look at NativeModules property, it is empty.

(.-NativeModules (js/require "react-native"))
gives #js {}

jeaye18:07:41

Is everything else empty as well, or just that?

mfikes18:07:49

Just that property

mfikes18:07:10

I’ve also stopped the debugger in the RCT_EXPORT_MODULE(); macro and I can see that it is registering properly

pesterhazy18:07:57

@jeaye your .re-natal should have a module section with all additional modules

mfikes18:07:08

I’m actually attempting to consume an existing (purely native) component: https://github.com/chirag04/react-native-in-app-utils

mfikes19:07:16

I’m going to repro the CalendarManager failure with a fresh re-natal init ... project

mfikes19:07:00

I’m suspicious the React Native packager might be doing something to make it work for regular projects

jeaye19:07:14

@pesterhazy That's almost exactly what I've written for this test repo.

jeaye19:07:27

'cept I was doing it in cljs.

pesterhazy19:07:03

(function (require){
	// PLACEHOLDER
})(function (name) {
	var modules={'react-native': require('react-native'), 'react': require('react')};modules['./images/cljs.png']=require('./images/cljs.png');
	if (modules[name]){
		return modules[name];
	}
	else {
		console.error("Not found:", name);
	}
});

pesterhazy19:07:20

the output should be something like this

pesterhazy19:07:18

then // PLACEHOLDER would be replaced by the actual cljs bundle, after through the rn packager

jeaye19:07:36

That bundles in 2.5m just the same.

jeaye19:07:28

Could it really be the 600K of cljs that does this?

mfikes19:07:07

It is trivial to repro the inability to use a native code module with a fresh re-natal project. I threw a copy of a repro repo up at https://github.com/mfikes/use-native-code along with instructions on how to see the issue. Perhaps there is something more that needs to be done to use native modules?

pesterhazy19:07:57

I don't think re-natal should be different from a regular rn project?

mfikes19:07:35

Right. I suspect I can take that repro and replace the index.ios.js content with the sample code from the Facebook page above

jeaye19:07:39

It's entirely due to the cljs size, @pesterhazy. I wrote a macro to generate lots of useless code, worth 4MB when compiled, and now I hit the same exact issues.

pesterhazy19:07:59

haha nice hack

pesterhazy19:07:47

could you put that up as a repo somewhere?

mfikes19:07:00

Bah! I found that if I go into the simulator and turn on “Debug JS Remotely”, then the native stuff works.

ios:cljs.user=> (js-keys (.-NativeModules (js/require "react-native")))
#js ["CalendarManager" "StatusBarManager" "SourceCode" "AlertManager" "ExceptionsManager" "DevMenu" "AsyncLocalStorage" "DevSettings" "ScrollViewManager" "JSCSamplingProfiler" "AccessibilityManager" "DevLoadingView" "Timing" "AppState" "DeviceInfo" "Clipboard" "PlatformConstants" "KeyboardObserver" "I18nManager" "WebViewManager" "RedBox" "UIManager" "NavigatorManager" "NativeAnimatedModule" "ActionSheetManager" "LocationObserver" "ImageStoreManager" "ImageViewManager" "ImageEditingManager" "LinkingManager" "NetInfo" "Networking" "SettingsManager" "Vibration" "WebSocketModule"]
(My CalendarManager is in there along with a lot of other native stuff.)

mfikes19:07:42

If I flip back to turn off remote debugging:

ios:cljs.user=> (js-keys (.-NativeModules (js/require "react-native")))
#js []

mfikes20:07:02

Also, when enabling remote debugging, it sets up the bridge and ends up calling my RCT_EXPORT_MODULE(); macro code again.

pesterhazy20:07:35

I've opened https://github.com/pesterhazy/re-natal-husk to explore my "empty husk" bundle idea

pesterhazy20:07:53

it works, just a few problems left to solve

jeaye20:07:21

Oh, awesome.

pesterhazy20:07:41

I just can't get the packager not to uglify/mangle a function argument name

pesterhazy20:07:03

can't come up with any tricks

pesterhazy20:07:41

like, the packager will insist on renaming function(require){BLA(require)} to function(o){BLA(o)}

jeaye20:07:42

That's likely not anything which is parameterized.

pesterhazy21:07:38

is there a way to trick minfiers into not renaming a var or an arg?

jeaye21:07:14

Nothing I know of, but that isn't much in the cljs/js world.

jeaye21:07:58

Fortunately, I can report that the :advanced route is actually able to get us into the app.

jeaye21:07:35

@pesterhazy Does exporting the fn help?

pesterhazy21:07:39

nice about :advanced comp

jeaye21:07:49

Ah need Android-specific bits then?

pesterhazy21:07:14

I only tried it with iOS, but it should work the same for android

pesterhazy21:07:03

it's hacky still - a few things should be improved

pesterhazy21:07:32

but it gives you fast packager builds that won't run out of memory

pesterhazy21:07:46

because the packager never sees the Google Closure generated bundle

jeaye21:07:14

We'll take a deep look at this, thanks!

pesterhazy21:07:53

Cool. Let me know what you think