Quick and dirty websocket repl for you to play with: https://github.com/johnmn3/repl.ws Not quite ready for announcements as there's still lots of bugs, but kick the tires as hard as you can!
Okay, so the strategy with http://repl.ws isn't going to work. I was shadowing a none existent namespace http://cljs.repl.ws in order to get some of cljs' repl bits for free just by passing a re ws flag. I thought that was the intended use case David had for the -re flag, wrt extension. But thinking about it further - we probably shouldn't squat on future namespaces that the core team may actually populate one day - it'll just make things confusing.
David concurred so I updated the lib to use it's own main. It tries to act just like cljs.main but you just use mink.main like so:
clj -M -m mink.main -c ex.core -w src
Still a rough and dirty experiment, but feel free to play with it here: https://github.com/johnmn3/minkOne bug I just noticed, multiple repl user connections use the same current-client value. Each repl should have it's own current-client.
just curiousļ¼ sorry for the stupid question. Does this mean users can do like online peer repl driven programmingļ¼or is this a fact happened long time to clojure community.
Eventually. That feature is broken right now. But yeah that has existed in clojure world for many years. It's just a fun side effect of how things are put together - many clients and many users on one repl server.
Not a dumb question. To do it "online," potentially between people from around the world, you'd need to setup your own secure tunnels. A website embedded party repl would be way easier and yeah that already exists I believe.
Hello,
has someone used https://github.com/griffinbank/test.contract in a clojurescript environement successfully? Despite the fact, that it is written in .cljc I was not able to use it. test.contract uses protocols and inspects them at runtime. I get errors like: No protocol method Model.initial-state defined for type function: function(){} does not satisfy map? and others. I assume, that it is because Protocols are not reified in CLJS.
Maybe @arohner can chime in.
sounds to me like you are passing a function somewhere you are supposed to pass a map? maybe wrong argument order?
there is no reference to CLJS in the repo, so I wouldn't be surprised if nobody actually tested this
The same code runs fine in CLJ, but fails in CLJS. I strongly suspect, that it caused by how protocols are implemented in cljs.
there is no reference to CLJS in the repo, so I wouldn't be surprised if nobody actually tested this
You are probably right.We intend to use in CLJS, but havenāt gotten there yet
I wouldnāt anticipate the PR being that difficult. PRs welcome
I can have a look into it, but I have to get a better understanding of how protocols work in CLJS
As far as I can see: test contract just needs the vars for each method name of a protocol. It is not to hard to get that information, but it requires that (defn model [ā¦]) is changed to a macro.
@arohner I have been able to run in CLJS š . 2 changes were needed. 1. the mock namespace, which contains the State Protocol is shadowed in CLJS (see here https://clojurians.slack.com/archives/C03S1L9DN/p1732105416688439?thread_ts=1732100469.195189&cid=C03S1L9DN) . Solution is to rename the namespace, but this could be a breaking change 2. extract the protocol data at compilation time. This must be done in a macro, but no change for (defn model [ā¦]) is needed. Because the protocol-value is a map in CLJ and we only need the vars of the methods, we can create that map at compilation time in cljs by providing a little helper macro. So usage looks like this:
(def model
(c/model
{:protocols #{(cljs-resolve ApiToTest)}
....)
I can provide a PR if you are fine with the changes. Especially point 1.Ah, the namespace g.t.c.mock is shadowed by the var g.t.c/mock?
It's not shadowed, it's completely overwritten. And I assume what overwrites what depends on the loading order.
yeah. Fixing that makes sense. Letās change the ns to mock-protocol. We only have one use of it in āuserā code, so thatās not that bad, and better to fix it now before it becomes a problem
I created a PR, which fixes the ns bug.
I want to eval code from within a clj process in a headless browser cljs repl. I saw the idea in this years Clojure conj talk about cljs math. I got it working that I can run my code once, but if I try to run it a second time in the same jvm process, then it will hang. I suspect, that some resource cleanup is not correct, but I cannot see which one. Code is in the comment.
(ns my-repl-test
(:require [cljs.core.server]
[cljs.repl.node]
[cljs.repl.browser]
[clojure.core.server :as server]
[clojure.edn :as edn]
[ :as io])
(:import [com.microsoft.playwright Playwright BrowserType$LaunchOptions]))
(def reader (atom nil))
(def writer (atom nil))
(defn cljs-eval [expr]
(-> (binding [*out* @writer
*in* @reader]
(println expr)
(read-line))
edn/read-string
:val))
(defn with-browser-repl [f]
(with-open [server (server/start-server {:accept 'cljs.core.server/io-prepl
:address "127.0.0.1"
:port 0
:name "cljs.math-repl"
:args [:repl-env (cljs.repl.browser/repl-env
:launch-browser false)]})]
(let [port (-> server (.getLocalPort))]
(println "Server opened on port" port)
(with-open [p (Playwright/create)
browser (.launch (.chromium p) (doto (BrowserType$LaunchOptions.)
(.setHeadless true)))
context (.newContext browser)
socket (java.net.Socket. "127.0.0.1" (-> server (.getLocalPort)))
rdr (io/reader socket)
wrtr (io/writer socket)]
(try
(println "establish repl conn")
(reset! reader rdr)
(reset! writer wrtr)
(println (binding [*out* @writer
*in* @reader]
(read-line))) ; read once, returns "Waiting for browser to connect to ...\n"
(with-open [page (.newPage context)]
(println "connecting to " "")
(.navigate page "") ; use playwright to get a browser to connect to it
(println "Executing tests") ; this gets still printed on the second run
(f) ; here it hangs on the second run
(println "Tearing down test pREPL."))
(finally
(reset! reader nil)
(reset! writer nil)))))))
(comment
(do
(with-browser-repl
#(do (println (cljs-eval "(+ 1 3)")) ; prints 4
(println (cljs-eval "(+ 1 2)")))) ; prints 3
(with-browser-repl
#(do (println (cljs-eval "(+ 1 3)")) ; hangs here
(println (cljs-eval "(+ 1 4)"))))) It prints:
; Server opened on port 57722
; establish repl conn
; {:tag :out, :val "Waiting for browser to connect to ...\n"}
; connecting to
; Executing tests
; 4
; 3
; Tearing down test pREPL.
; Server opened on port 57853
; establish repl conn
; {:tag :out, :val "Waiting for browser to connect to ...\n"}
; connecting to
; Executing tests deps.edn
org.clojure/clojure {:mvn/version "1.12.0"}
com.microsoft.playwright/playwright {:mvn/version "1.39.0"}
com.griffin/test.contract {:mvn/version "0.0.1"}
org.clojure/clojurescript {:mvn/version "1.11.132"}
org.clojure/spec.alpha {:mvn/version "0.5.238"}Does it work if you append \n to the strings you're evaluating? e.g.
(cljs-eval "(+ 1 3)\n")
It could be that read-line isn't returning because there's no newline
edit: i see you're using println which should append the newline so it's likely not that, sorryHi thanks for your suggestion.
println is irrelevant here. It runs in the clj process. Only the string in cljs-eval is send to the browser repl, evaluated there in cljs, and returned (consumed via readline).
Adding \n to the string does not work. I tested it. And from the example one can see that cljs-eval is called twice in with-browser-repl. There are 2 readline calls under the hood and two values are returned. It is the second invocation of with-browser-repl that gets stuck.
Is there any way you could keep an eye on the launched process(ess) to verify your suspicion that they are not torn down correctly?
Alternatively, can you try not tearing down processes and reusing them instead? Perhaps that would also shed some light on things. (Just throwing things out there while reading code on my phone, sorry if it doesn't apply)
If you verify that they are not torn down correctly, perhaps you can try killing pids instaed and see if that verifies that s second call will work fine after process teardown.
Is there any way you could keep an eye on the launched process(ess) to verify your suspicion that they are not torn down correctly?
These arenāt processes, but threads so it is hard to say. I use with-open every where, so I would expect, that the resources tear down. However, I cannot tell for sure.
Alternatively, can you try not tearing down processes and reusing them instead? Perhaps that would also shed some light on things.
I tried it. And it worked most of the time. Until there is an exception in the cljs-repl eval. Then things are out of sync. Readline is one evaluation behind and a restart is required. This is what I did:
(defn enable-cljs-eval! []
(let [server (server/start-server {:accept 'cljs.core.server/io-prepl
:address "127.0.0.1"
:port 0
:name "cljs.math-repl"
:args [:repl-env (cljs.repl.browser/repl-env
:launch-browser false)]})
port (-> server (.getLocalPort))]
(println "Server opened on port" port)
(let [p (Playwright/create)
browser (.launch (.chromium p) (doto (BrowserType$LaunchOptions.)
(.setHeadless true)))
context (.newContext browser)
socket (java.net.Socket. "127.0.0.1" (-> server (.getLocalPort)))
rdr (io/reader socket)
wrtr (io/writer socket)]
(println "establish repl conn")
(reset! reader rdr)
(reset! writer wrtr)
(println (binding [*out* @writer
*in* @reader]
(read-line))) ; read once, returns "Waiting for browser to connect to ...\n"
(let [page (.newPage context)]
(println "connecting to " "")
(.navigate page "") ; use playwright to get a browser to connect to it
))))
With this snippet I can run (cljs-eval (ā(+ some thingā)) as often as I want unless the string-expression throws during evaluation.I still havenāt solved the teardown issue. Anyway, I started wrapping it up in a small library š : https://github.com/HendrikLevering/cljs-eval Now you can run this in CLJ:
(enable-cljs-eval!)
(cljs-eval "(.createElement js/window.document \"div\")")
{:tag :ret, :val "#object[HTMLDivElement [object HTMLDivElement]]", :ns "cljs.user", :ms 13, :form "(.createElement js/window.document \"div\")"}
; for convenience
(cljs-eval! (js/alert "div"))
nil