bhauman / lein-figwheel

Figwheel builds your ClojureScript code and hot loads it into the browser as you are coding!
Eclipse Public License 1.0
2.88k stars 209 forks source link

print fns applied to exceptions fail #575

Closed mfikes closed 7 years ago

mfikes commented 7 years ago

If you try to apply *print-fn* or *print-err-fn* to an exception, you get "Figwheel: message from client couldn't be read!"

Example:

ios:cljs.user=> (*print-err-fn* (ex-info "hi" {}))
Figwheel: message from client couldn't be read!

Note: For comparison here is what you get in the Node REPL:

cljs.user=> (*print-fn* (ex-info "hi" {}))
{ Error: hi
    at new cljs$core$ExceptionInfo (/Users/mfikes/.cljs_node_repl/.cljs_node_repl/cljs/core.js:34785:10)
    at Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$3 (/Users/mfikes/.cljs_node_repl/.cljs_node_repl/cljs/core.js:34846:9)
    at Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$2 (/Users/mfikes/.cljs_node_repl/.cljs_node_repl/cljs/core.js:34842:26)
    at cljs$core$ex_info (/Users/mfikes/.cljs_node_repl/.cljs_node_repl/cljs/core.js:34828:26)
    at repl:1:138
    at repl:9:3
    at repl:14:4
    at ContextifyScript.Script.runInThisContext (vm.js:44:33)
    at Object.runInThisContext (vm.js:116:38)
    at Domain.<anonymous> ([stdin]:50:34)
  message: 'hi',
  data:
   { meta: null,
     cnt: 0,
     arr: [],
     __hash: -15128758,
     'cljs$lang$protocol_mask$partition0$': 16647951,
     'cljs$lang$protocol_mask$partition1$': 139268 },
  cause: null,
  name: 'Error',
  description: undefined,
  number: undefined,
  fileName: undefined,
  lineNumber: undefined,
  columnNumber:nil
 undefined,
  stack: 'Error: hi\n    at new cljs$core$ExceptionInfo (/Users/mfikes/.cljs_node_repl/.cljs_node_repl/cljs/core.js:34785:10)\n    at Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$3 (/Users/mfikes/.cljs_node_repl/.cljs_node_repl/cljs/core.js:34846:9)\n    at Function.cljs.core.ex_info.cljs$core$IFn$_invoke$arity$2 (/Users/mfikes/.cljs_node_repl/.cljs_node_repl/cljs/core.js:34842:26)\n    at cljs$core$ex_info (/Users/mfikes/.cljs_node_repl/.cljs_node_repl/cljs/core.js:34828:26)\n    at repl:1:138\n    at repl:9:3\n    at repl:14:4\n    at ContextifyScript.Script.runInThisContext (vm.js:44:33)\n    at Object.runInThisContext (vm.js:116:38)\n    at Domain.<anonymous> ([stdin]:50:34)' }
mfikes commented 7 years ago

I did a little digging into this and can see why it is occurring. Summary: Figwheel sends messages from the JavaScript environment back to Clojure serializing arguments to "RPC" calls as edn, and for the REPL print fns, the conversion to strings occurs on the Clojure side.

Perhaps another alternative would be to do the string conversions—only for the REPL print message—on the JavaScript side instead so that the arguments on the receiving end are (edn) strings.

That might open the door to being able to (*print-fn* #js {:foo 1}), and the exception type mentioned above. If you look at what the Node REPL does, it just uses console logging of the raw JavaScript values. (As an aside, I just noticed that Planck wasn't matching the Node REPL's behavior either and got it to be fairly close by making use of JSON/stringify, essentially using something like

(defn ->string 
  [x] 
  (js/JSON.stringify x nil " "))

Of course, if Figwheel were to consider something like this for non-string args, it suspect it would be wise to check (and (exists? js/JSON) (some? js/JSON.stringify))

One more bit of follow up on this: It appears that Error objects are given special treatment, and instead of JSON stringified representation, the message and stack properties are extracted to form the string representation.

bhauman commented 7 years ago

Alrighty just want to let you know I'm going to take a look at this.

bhauman commented 7 years ago

I've fixed this but if we are keen on keeping the contract for print-fn to only take strings let me know.