Fork me on GitHub
#clojurescript
<
2020-11-19
>
neilyio00:11:55

I'm trying to set a custom error handler in the browser... but setting window.onerror doesn't seem to take effect right away. Does anyone know why? Here are two cases:

(defn error-handler [message url line column e]
  (js/console.log "MY CUSTOM ERROR MESSAGE")
  (js/console.error e)
  true)

(set! (.-onerror js/window) error-handler)

(defn fail []
  (throw (ex-info "Big error" {})))

(fail) ;; error-handler is not run.
outputs:

neilyio00:11:35

But delaying the call to fail with setTimeout produces the expected result:

(defn error-handler [message url line column e]
  (js/console.log "MY CUSTOM ERROR MESSAGE")
  (js/console.error e)
  true)

(set! (.-onerror js/window) error-handler)

(defn fail []
  (throw (ex-info "Big error" {})))

(.setTimeout js/window fail 3) ;; error-handler is run!
outputs:

p-himik00:11:43

It works for me just fine without setTimeout. No idea why it would work for you differently. BTW you can use js/setTimeout instead of (.setTimeout js/window ...).

p-himik00:11:50

Huh, but if I try the analogous JS code in a JS console I get the behavior that you see for some reason:

window.onerror = (message,url,line,column,e) => {console.log('my handler'); console.error(e);}

throw new Error('hi')
// Uncaught Error: hi

setTimeout(() => {throw new Error('hi')}, 0)
// my handler
// Uncaught Error: hi

neilyio00:11:13

Thanks for the tip about setTimeout. I have no idea what's going on either... but glad I'm not crazy.

p-himik00:11:18

Well at least there's an explanation for what I see in JS: https://stackoverflow.com/a/17534068/564509 Also the comments are interesting - try using (js-debugger) to see the call trace.

thheller08:11:58

shadow-cljs catches errors during load so it never gets to your onerror. the settimeout takes it out of the load phase and therefore your handler triggers. never throw during load 😉

p-himik11:11:56

As I mentioned - for some reason, it works for me.

(ns clj-playground.core)

(defn error-handler [message url line column e]
  (js/console.log "MY CUSTOM ERROR MESSAGE")
  (js/console.error e)
  true)

(set! (.-onerror js/window) error-handler)

(defn fail []
  (throw (ex-info "Big error" {})))

(fail)
gives
main.js:2226 failed to load clj_playground.core.js #error {:message "Big error", :data {}}
env.evalLoad @ main.js:2226
(anonymous) @ main.js:2393
core.cljs:4 MY CUSTOM ERROR MESSAGE

p-himik11:11:02

Updated shadow-cljs to 2.11.7 - still works, although e is now rendered differently in the console.

p-himik11:11:57

Also, what if it's not my code that throws an error during load but something that I :require? I think wanting to be able to instrument such scenarios is a perfectly valid thing.

neilyio16:11:09

That's exactly what I was trying to do, it was a whole headache to try and figure out what was going on... thanks for clarifying @U05224H0W

thheller16:11:23

you can use :devtools {:loader-mode :script} then shadow-cljs won't catch errors

thheller16:11:31

release builds also never catch any errors

thheller16:11:46

but with that said ... throwing during load is a really really bad idea so don't do it 😛

neilyio16:11:05

Agreed, it's more just a development workflow thing. Sometimes it can help if I'm debugging something strange. Glad there's an option for it.

pinealan02:11:26

How/where in source code is persistent data structure implemented in clojurescipt? I’ve tried cljs website faqs and googling and neither showed in-depth explanations. Any pointers are appreciated!

dpsutton02:11:25

you can see the implementation of clojurescript's persistenthashmap here: https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs#L7879

dpsutton02:11:56

you're welcome. it can be pretty dense at first

pinealan02:11:18

Also do I understand correctly that much more of cljs in implemented in itself than Clojure? That’s the feeling I got from skimming the cljs.core namespace, where I can see a lot of language feature protocols are defined, whereas in the Clojure counterpart they are in Java

dpsutton02:11:43

and this can be helpful

dpsutton02:11:00

yeah Rich Hickey (the creator) wrote about this in the history of clojure paper (which is an excellent read). Clojurescript is a "clojure in clojure" kinda language that he felt really demonstrated how good the choices made in the language was

pinealan02:11:09

ya I’ve read that one, was always wondering to what degree is clojurescript “written in itself” thanks a lot for pointing me to the source code, it explains a lot

dpsutton02:11:46

ah ok. then i won't keep sending screenshots. sorry about that 🙂

dpsutton02:11:18

yeah no nasty interfaces in clojurescript. you get to see the protocols

pinealan02:11:38

lol no worries, love your enthusiasm

Jason12:11:35

Is there a reason that clojure every is not defined in clojurescript?

thheller12:11:34

Clojure 1.10.1
user=> every
Syntax error compiling at (REPL:0:0).
Unable to resolve symbol: every in this context

thheller12:11:38

you mean every?

Jason12:11:02

whoops. i got the wrong clojure every

Jason12:11:25

Pardon my cljs newbness, but I'm trying to make sure that all the members of set-a are in set-b. every? is not the answer. I then thought of subset from clj but it's not in cljs. Am I missing something?

lukas.rychtecky12:11:18

Do you mean this function? clojure.set/subset?

Jason12:11:51

is that in the cljs clojure.core? It's not listed in the API docs

Jason12:11:40

ah, but i see it in the source

lukas.rychtecky12:11:08

It’s in set namespace

Jason12:11:06

yes, just as it is in clj, but it's not listed in https://cljs.github.io/api/ which confused me

Jason12:11:58

as i said above, once i thought to look in the source, i saw it. thank you for responding

👍 3
xceno13:11:44

Can I completely disable any optimizations the google closure compiler does to a single npm-dependency when using shadow-cljs? It somehow destroys a function call inside a web worker, and it seems I don't have any other options left right now

manutter5113:11:17

I’m not sure I understand your issue, but is it something you could resolve by downloading the source to your npm dependency and building it locally?

xceno15:11:58

Well my issue is a bit weird, but here are the details: I use a library that converts a function to a string, so it can instantiate a web-worker: https://github.com/antvis/Graphin/blob/a87b8f64e2303aad42c94a72d2dd861e1a7ea234/packages/graphin/src/layout/basic/forceWithWorker.ts#L70 What happens is, that this function here: https://github.com/antvis/Graphin/blob/a87b8f64e2303aad42c94a72d2dd861e1a7ea234/packages/graphin/src/layout/basic/worker.ts#L6 Gets converted/compiled to the following code:

(... Some other stuff);function(){onmessage=...
So the worker instantly crashes, because this top level function has no name. The error is: "Uncaught SyntaxError: Function statements require a function name"

xceno15:11:55

I've tried it with webpack in a typescript project and can't replicate the issue there. In my clj project I've also played around with externs, reducing compiler-optimizations, etc. but to no avail. Therefore I came to the conclusion that something else in the closure compiler must be the issue, but I can't figure it out

thheller15:11:26

@U012ADU90SW it appears the library does some runtime eval so it is likely that it calls something that was renamed and not expecting it to be minified/renamed. hard to say but there is no way to disable optimizations

p-himik17:11:33

But maybe it's possible to at least add some externs for the stuff that eval expects to be there.

xceno17:11:54

I thought the same about externs, but since it's an anonymous function there's not much to do in term of named externs. Anyway, thanks guys! I'll try to figure something out, it may just end up as yet another workaround. Maybe I compile it separately and load it on app start or something like that

devn20:11:24

barebones hot reload: what are people using these days?

Braden Shepherdson21:11:33

figwheel-main is pretty minimal.

devn21:11:53

kind of where i was headed, thanks

devn21:11:36

i briefly had the “well, a filesystem watcher that calls a build script…” thought

devn21:11:39

and then thought better of it

dominicm21:11:24

There's a little more to it annoyingly :)

dominicm21:11:49

I think you could make a lighter figwheel, but nobody really wants to! (it's a lot of work)