Fork me on GitHub
#shadow-cljs
<
2020-01-05
>
vemv05:01:58

I could repro the behavior tianshu describes, and documented it in https://github.com/nedap/speced.def/issues/100#issuecomment-570865803 . It seems pretty unfortunate that when using a standard mechanism such as ex-info, error reporting will become drastically worse, if the error happened on load. Needless to say there are many cljs libs that can throw a ex-info at any point. i.e. this is not specific to my library. @ thheller - are you 100% sure this is not something shadow-cljs can handle? Otherwise, it'd seem worth it to create an issue in the cljs compiler, or such.

thheller09:01:49

@vemv the issue is fixed by setting :devtools {:loader-mode :script} in your build config

vemv14:01:35

I got that point, but given :eval is the default, people can get a bad experience by default if using libraries such as mine Also, this seems an easy-to-forget intricacy

thheller15:01:56

well the problem is in throwing exceptions at load time. that is never good. with eval the source maps are likely loaded differently and maybe the browser then has trouble dealing with the stacktraces

thheller15:01:18

I really do not know. I could also just not catch any exceptions but that confused people more in the past

vemv15:01:01

> that is never good. it is good if you are checking :pre and :post conditions, or similar mechanisms (spec-related solutions) I do not have an opinion on the right solution (for one thing I am unfamiliar with many compiler or shadow-cljs intricacies), but I'd like to point out that this is a reasonable problem to have. It's not urgent for me either, but I'd be happy if this was tracked in the right place (shadow-cljs or clojurescript).

thheller17:01:41

the way I see it its a trade-off. faster loading via eval or slower loading but accurate errors during loading

thheller17:01:58

as far as I can tell runtime makes no difference its just the load time that is problematic

thheller17:01:50

I don't know what to do either. errors during load are problematic anyways since the program cannot continue after it. it gets into an undefined state so you have to reload the page anyways

vemv17:01:45

> as far as I can tell runtime makes no difference its just the load time that is problematic scienced it myself, correct :)

vemv17:01:16

> I don't know what to do either. errors during load are problematic anyways since the program cannot continue after it. it gets into an undefined state so you have to reload the page anyways I can see how there could be different programmer preferences around this. Personally I have no problem whatsoever with hitting Cmd + R if my program was so broken that it threw an exception on init. Maybe worth considering - document :script and :eval? Would be nice if programmers were aware of these tradeoffs upfront. At the same time, the root of the problem seems to lie in the js/Error <-> ex-info difference. By intution, there shouldn't be one. Would be interesting to determine what component is at fault (shadow, the compiler, etc)

thheller18:01:30

shadow or the compiler isn't involved in this. it can only be the way ex-info is implemented

thheller18:01:04

but it may just be a restriction of the javascript runtime that it only supports stacktraces for regular js/Error until it had a change to load the source maps and stuff

thheller18:01:28

you can try subclassing Error and see if you can get it to work

thheller18:01:38

shadow-cljs does nothing to ex-info in any way

vemv18:01:03

alright! thanks for the clarification. > you can try subclassing Error and see if you can get it to work yes, I did try changing the error being thrown in my lib https://gist.github.com/vemv/e9a7534a5bc7f277395add3e7c23a291 , with success. However, since many things can throw ex-info at any point, probably I won't end up changing my thrown exceptions. Would not be a 100% solution. documenting the loader modes as mentioned might do the trick.

thheller18:01:52

when exactly does your error happen?

thheller18:01:23

look like its your init fn

thheller18:01:54

so you can do it async whatever that is doing

thheller18:01:06

(defn init [] (js/setTimeout foo 0))

thheller18:01:20

instead of calling (foo) directly. or whatever you are doing

vemv18:01:54

the use case is: in a cljs app, I add 'spec checking' to defns somehow. could be :pre or instrumentation If for any reason (like programmer error) the specs fail, an error will be thrown during load time. seems a quite likely possibility regardless of the specific chosen 'spec checking' library

thheller18:01:04

yes. the problem is load time .. by making the call async you get out of load time

thheller18:01:24

from the stacktrace it looks like its your :init-fn call which is the LAST thing during load time

thheller18:01:32

so you have full control over when the error actually occurs

vemv18:01:48

(defn init [] (js/setTimeout foo 0)) is interesting, however I can't/shouldn't control how consumers of my library structure their applications Documenting this intricacy seems far leaner/cleaner than suggesting workarounds or doing a best-effort approach to replacing ex-info -> js/Error everywhere. Don't you agree?

thheller18:01:49

I don't know. I never had this issue before .. I'll think about it

tianshu04:01:36

is the async load behaves similar with adding a script tag in document?

thheller06:01:48

not sure what you mean? which "async load"?

tianshu07:01:35

I mean run the code in a js/setTimeout.

tianshu07:01:52

another thing I notice is that eval code in the repl facing the same problem. I can only get the meaningful error stack with js/Error.

thheller07:01:08

likely a problem with eval then

tianshu07:01:02

yes, problem exist even use :script loader-mode.

thheller07:01:13

the loader mode only affects actual loading of code

thheller07:01:29

and the one using :script doesn't eval .. so makes sense

tianshu07:01:11

yes, so this is a problem with eval code, not about the loader-mode.

thheller07:01:34

seems like it yes

Kamila Herková16:01:15

I am trying to import TextField from Material-UI. I am requiring using following code

(:require ["@material-ui/core/TextField" :default TextField])
However the symbol TextField is undefined and it shows following error:
TypeError: Cannot read property 'default' of undefined
    at eval (eval at shadow$cljs$devtools$client$browser$global_eval (), <anonymous>:1:55)
    at eval (<anonymous>)
    at Object.shadow$cljs$devtools$client$browser$global_eval [as global_eval] ()
    at 
    at Object.shadow$cljs$devtools$client$env$repl_call [as repl_call] ()
    at Object.shadow$cljs$devtools$client$browser$repl_invoke [as repl_invoke] ()
    at shadow$cljs$devtools$client$browser$handle_message ()
    at 
    at Object.shadow$cljs$devtools$client$env$process_next_BANG_ [as process_next_BANG_] ()
    at Object.shadow$cljs$devtools$client$env$process_ws_msg [as process_ws_msg] ()
Please could you help me to figure this out.

thheller17:01:50

@kamila.herkova try shadow-cljs browser-repl and (require '["@material-ui/core/TextField" :as x]) then x or (js/console.dir x) or so

thheller17:01:13

JS libs are very inconsistent regarding :default

thheller17:01:37

it looks like :default should work though

thheller17:01:09

might be a REPL problem. try loading the file normally and see if it works then

Kamila Herková17:01:44

After running x it outputs this:

== JS EXCEPTION ==============================                                                                          
ENCODING FAILED, check host console                                                                                     ==============================================     

knubie18:01:57

I got the same error recently when running (remove [:a :b] #{:a})

thheller18:01:49

@kamila.herkova that means it can't print the object. try (js/console.dir x) or (js/console.log x)

Kamila Herková18:01:01

After running (js/console.dir x) it returns nil .

knubie18:01:12

@kamila.herkova Does it print nil in the developer tools js console?

thheller18:01:03

dir returns nil yes, check the browser console instead

thheller18:01:23

FWIW :default works for me

Kamila Herková18:01:23

In browser console this is returned:

Object
default: [Exception: TypeError: Cannot read property 'default' of undefined at Object.get [as default] (node_modules/@material-ui/core/TextField/index.js:1:336) at Object.invokeGetter (<anonymous>:1:142)]
__esModule: true
get default: ƒ ()
length: 0
name: "get"
arguments: null
caller: null
prototype: {constructor: ƒ}
__proto__: ƒ ()
[[FunctionLocation]]: index.js:11
[[Scopes]]: Scopes[2]
__proto__: Object

thheller18:01:06

yeah there is had a default property

thheller18:01:33

so (require '["@material-ui/core/TextField" :default TextField]) and TextField should be working fine

thheller18:01:39

although it is weird that it is showing `default: [Exception: TypeError: Cannot read property 'default' of undefined at Object.get [as default] (node_modules/@material-ui/core/TextField/index.js:1:336) at Object.invokeGetter (<anonymous>1️⃣142)] ` for you

thheller18:01:46

I just get the regular property

thheller18:01:16

dunno why that might be though

Kamila Herková18:01:20

The problem is that this is the printout after running (require '["@material-ui/core/TextField" :default TextField]) .

thheller18:01:40

don't try printing it ...

thheller18:01:07

just inspect it in the console. react uses js/Symbol and those aren't printable by default

thheller18:01:13

so it doesn't work in the REPL

Kamila Herková20:01:05

This a minimal example of code where the problem occurs:

(ns project.text-field
  (:require ["@material-ui/core/TextField" :default TextField]))

(defn text-field []
  (js/console.log TextField)
  [:div]
And the following stacktrace:

thheller20:01:07

@kamila.herkova can't tell what isRequired is supposed to be but it might be caused by a dependency conflict. thats not so easy to debug unfortunately. for me it works in an empty test project so that makes dependency conflict more likely