babashka / nbb

Scripting in Clojure on Node.js using SCI
Eclipse Public License 1.0
844 stars 51 forks source link

send console output to nREPL clients #305

Open ikappaki opened 1 year ago

ikappaki commented 1 year ago

Is your feature request related to a problem? Please describe. When developing interactively on the REPL, is essential for the user to observe the serve responses.

nbb can use javascript packages that sent their text output to the console. When interacting on nREPL, console output is sent to the server stdout/stderr streams, which are not forwarded to the nREPL client, thus the user is likely to miss important output information.

For example if we were to jack-in to nbb with cider on a project with puppeteer installed and eval the following

(ns issue
  (:require ["puppeteer$default" :as puppeteer]
            [promesa.core :as p]))

(p/let [browser (.launch puppeteer #js {:headless false})
        page (.newPage browser)]
  (.goto page "https://clojure.org")
  (.waitForSelector page "xyz" #js {:timeout 1000}))

puppeteer will log to the console that Waiting for selector `xyz` failed: Waiting failed: 1000ms exceeded, but there will be nothing displayed on the user nREPL client, so they will not be aware that something has gone wrong (this information will be printed in the *nrepl-server ...* buffer, but users are most unlikely to monitor this buffer).

Describe the solution you'd like Either intercept and replicate all js console output or stdout/stderr streams to the nREPL client, possibly using print.

Describe alternatives you've considered Replace console.log/err fn with ones that use println.

Happy to have a look if a solution is agreed.

Thanks

borkdude commented 1 year ago

Since I'm not sure what is the consequence of messing with js/console.error etc, I think trying this out in user space might be a good first step.

ikappaki commented 1 year ago

Since I'm not sure what is the consequence of messing with js/console.error etc, I think trying this out in user space might be a good first step.

Sure, here is a naive implementation in userspace to replicate console.log output to the clojure's *out* stream that can easily extended to cover all the other relevant logging fns

(ns user
  (:require ["util" :as util]))

(def console-log-original
  "The original console.log fn."
  js/console.log)

(defn console-log-to-*out*-replicate!
  "Replaces `js/console.log` with a fn that forwards its messages both
  to `js/console.log`, and Clojure's `*out*` stream."
  []
  (set! (.-log js/console)
        (fn console-log-new
          ([data]
           (console-log-original data)
           (println :js/console.log data))
          ([& args]
           (let [txt (apply util.format args)]
             (console-log-new txt))))))

#_(console-log-to-*out*-replicate!)

Btw, should nbb automatically read from user.cljs in the classpath at start up? It doesn't seem to be working for me when invoking nbb repl. I empirically know that this works with the mainstream clojure(script) repls, but couldn't find a reference in the documentation after having a quick look😅

Thanks

borkdude commented 1 year ago

user.clj and user.cljs aren't supported in bb / nbb yet, but bb has BABASHKA_PRELOADS which kind of takes that role (and predates even being able to load files 😅 ).

Does your workaround above work for you in the nREPL?

ikappaki commented 1 year ago

user.clj and user.cljs aren't supported in bb / nbb yet, but bb has BABASHKA_PRELOADS which kind of takes that role (and predates even being able to load files 😅 ).

OK thanks, I find this feature quite useful for REPL driven development.

Does your workaround above work for you in the nREPL?

Yes, after evaluating the above in a CIDER nbb nREPL and executing (js/console.log ":test %s %d" "string" 1), I can see in

nrepl-server buffer

nREPL server started on port 62379 on host 127.0.0.1 - nrepl://127.0.0.1:62379
:test string 1

cider-repl buffer

;; ClojureScript REPL type: nbb
;;
:js/console.log :test string 1

user> 
borkdude commented 1 year ago

As long as the original output is also still visible, I think it's a reasonable fix

ikappaki commented 1 year ago

Would you like me to prepare a PR to explore this?

borkdude commented 1 year ago

Sounds good