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: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: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 😉
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
Updated shadow-cljs to 2.11.7 - still works, although e
is now rendered differently in the console.
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.
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 @thheller
you can use :devtools {:loader-mode :script}
then shadow-cljs won't catch errors
release builds also never catch any errors
but with that said ... throwing during load is a really really bad idea so don't do it 😛
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.
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 ...)
.
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
Thanks for the tip about setTimeout
. I have no idea what's going on either... but glad I'm not crazy.
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.
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!
you can see the implementation of clojurescript's persistenthashmap here: https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs#L7879
Thanks!
you're welcome. it can be pretty dense at first
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
and this can be helpful
https://hypirion.com/musings/understanding-persistent-vector-pt-1
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
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
ah ok. then i won't keep sending screenshots. sorry about that 🙂
yeah no nasty interfaces in clojurescript. you get to see the protocols
lol no worries, love your enthusiasm
Is there a reason that clojure every
is not defined in clojurescript?
Clojure 1.10.1
user=> every
Syntax error compiling at (REPL:0:0).
Unable to resolve symbol: every in this context
you mean every?
whoops. i got the wrong clojure every
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?
Do you mean this function? clojure.set/subset?
yes
is that in the cljs clojure.core
? It's not listed in the API docs
ah, but i see it in the source
It’s in set
namespace
yes, just as it is in clj, but it's not listed in https://cljs.github.io/api/ which confused me
I see it https://cljs.github.io/api/clojure.set/#subsetQMARK
as i said above, once i thought to look in the source, i saw it. thank you for responding
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
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?
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"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
@rob703 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
But maybe it's possible to at least add some externs for the stuff that eval
expects to be there.
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
barebones hot reload: what are people using these days?
figwheel-main is pretty minimal.
kind of where i was headed, thanks
i briefly had the “well, a filesystem watcher that calls a build script…” thought
and then thought better of it
There's a little more to it annoyingly :)
I think you could make a lighter figwheel, but nobody really wants to! (it's a lot of work)