Fork me on GitHub
#re-frame
<
2021-08-11
>
borkdude10:08:22

We've been hitting this assert randomly in production code recently. All fine during dev but once compiled the advanced build to staging, it breaks.

(defn console
  [level & args]
  (assert (contains? @loggers level) (str "re-frame: log called with unknown level: " level))
  (apply (level @loggers) args))

p-himik10:08:42

Is there some specific level that triggers it?

borkdude10:08:01

We don't even use any loggers

p-himik10:08:58

That's fine. But does the assert message above include the level? And what's the stacktrace? I'm 80% certain that there's some library in your dependencies that changes @loggers but does it in an improper way.

borkdude10:08:03

we're on 0.11.0. upgrading to 1.2.0 breaks another thing. it's a bit of a crisis

p-himik10:08:23

Hmm. That is strange. And 0.11.0 doesn't have any obvious way to break loggers, unless the compiler ignores the ^:private metadata. I would try to print the result of (re-frame.loggers/get-loggers) right at the start of the application, just to double check. If that doesn't provide any insight, I would copy re_frame/loggers.cljc into my own code and add a watcher to the loggers atom there to see when exactly it is modified with (js-debugger) , plus an extra statement before that assert to log the current state of loggers.

p-himik10:08:31

Also, that particular logging message is this line:

(console :error "re-frame: no" (str kind) "handler registered for:" id)
So seems like there's also an issue in your app's code.

borkdude10:08:15

{:log #object[bound log], :warn #object[bound warn], :error #object[bound error], :debug #object[bound debug], :group #object[bound group], :groupEnd #object[bound groupEnd]}

p-himik10:08:30

Yeah, all fine here.

borkdude10:08:57

but that's when there is no bug as well in production

borkdude10:08:04

it happens randomly in some builds

p-himik10:08:39

So it's tied to a build, and not some specific behavior?

borkdude10:08:03

well, we thought we solved it by making something lazy non-lazy, this helped solving the bug last time

borkdude10:08:19

but now I built some new feature and it starts happening again. Only in release builds :((

borkdude10:08:33

and there's a demo soon... this is stressing me out.

p-himik10:08:14

Then do all the things I described and try again and again to trigger it on a release build in staging. I don't see any other way to get useful information from it.

borkdude10:08:35

now I'm getting this:

borkdude11:08:21

starting with a clean build solved that problem, still weird

borkdude11:08:21

I installed an override of re-frame loggers in our production build

borkdude11:08:41

(defn console
  [level & args]
  #?(:cljs (.log js/console "level" (str level)))
  #?(:cljs (.log js/console "has-logger" (some? (level @loggers))))
  ;; (assert (contains? @loggers level) (str "re-frame: log called with unknown level: " level))
  ;; (apply (level @loggers) args)
  )

p-himik11:08:24

And what does @loggers contain at this point?

borkdude11:08:05

I'm going to take a look at that next, but this error might hint at what's really going wrong.;.

p-himik11:08:55

Not sure - unless the JS console is mixing things up, that error is after those logged statements. So it can't affect @loggers at that point. Unless it has happened before, up the log, as well.

lassemaatta11:08:10

I got curious and google that this.options.useExtendedSearch stuff and most hits seem to relate to a fuse.js fuzzy search library. any chance you're using it and something horrible happens during advanced compilation?

borkdude11:08:35

yep we use that. thanks, looking into this

borkdude15:08:36

We're deploying with optimizations simple now until we get this sorted

borkdude15:08:50

Thanks for the moral and technical support

p-himik11:08:35

That project is not open source, is it?

borkdude11:08:58

unfortunately not

borkdude11:08:04

with pseudo-names true our build succeeds

👍 3
borkdude16:08:33

we upgraded to the newest CLJS + all the libs that were breaking with google closure

borkdude16:08:45

and guess what... it compiles/works again with advanced

p-himik16:08:53

Sweet! My guess is that one of the libs didn't have that precious ^js or something like that in the right place.

bringe18:08:32

Lately I've been working on a re-frame + react native project and noticing that some react libraries in the JS ecosystem now use hooks as their main/only API. So far I've avoided using hooks with re-frame because it seems they somewhat go against the model of doing things in events, and using view components only to render the state created by the events. Does anyone use hooks with re-frame? I wonder if it could become a problem in time that newer JS react libraries mainly use hooks and don't provide their functionality otherwise. For example, maybe I need to do X, and library Y does just what I need and is the most/only community supported library that does X. Then I realize library Y only exposes X through a hook. So do I just avoid library Y and write this functionality myself? Maybe I'm misunderstanding something, as I haven't used hooks much in the past, and I can't say I'm a well-seasoned re-frame user.

p-himik18:08:09

Hooks by themselves are OK, as long as you control the component's state yourself. And you should be able to wrap any such component into a hook-less one. What's not OK is when e.g. some component just asks you for a URL and then loads data from that URL. But such cases are rather rare, at least in my experience.

bringe21:08:32

Hmm, so for example, if I want to use an auth library that has a hook like useAuthClient that gives me a function like login - I'd want to call login in a re-frame effect, but for reasons I'd want to call it on app initialization and only then. I guess my confusion comes with figuring out the proper way to get that login function in a re-frame event if I have to obtain if from within a component. On the one hand I have the app initialize event which doesn't have much to do with components, yet I want to call a function I can only get from within a component. I could be thinking about this all wrong, though.

p-himik22:08:03

Ah, that's an example of a bad hook. It hides the state, making it opaque for re-frame. And of course it's not really specific to hooks, although they facilitate it. I would try my best to avoid using such code altogether. But if the login function can be called outside a component, you can pass it to an event and make a custom effect that would call a function that you pass to it.

bringe22:08:17

Ah I see. Thanks for the info and tips. So far, I've managed to avoid hooks with re-frame.