Hey everyone! I'm running https://github.com/kanaka/cljs-bootstrap on a https://onion.io/omega2/ with https://openwrt.org/ & Node v8.10.0. Now I'd like to use Emacs/CIDER to connect to an nREPL server that does the evaluation in the Node/CLJS runtime. There is no way to run a JVM on the mirco. So I want to run a Clojure/JVM-nREPL server on my Windows box and have that JVM connect to the Node/CLJS. Any idea?
@henrikheine JVM+nREPL is meant to compile cljs to js, then the compiled forms can be sent to a web browser, a nodejs instance in the same machine or a nodejs in micro controller. I suspect if you need to run cljs-bootstrap in the first place. Why do you want cljs-bootstrap in the micro controller?
@myguidingstar I'm probably just confused about cjls-bootstrap. I tried running it just to see if I could run CLJS without a JVM on the micro/Node. You're saying you can send the compiled CLJS/JS to a running Node? That's just what I need. What would I need on the JVM-side and what would run on the Node-side?
ok, I guess the confusing part is "bootstrap". It can either mean "boostraping the compiler" (as in cljs-bootstrap project you posted above), or only "bootstraping the js env for evaluation" (as seen in this script https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/bootstrap_nodejs.js)
in your case, you need the later, not the former
(you don't need to look into the above bootstrap_nodejs.js, that's only for reference)
look at this instead: https://github.com/nrepl/weasel
you can use shadow-cljs :node-script
too. pretty easy to set up. extra easy if you can mount the files directly via sshfs or so
weasel will run on jvm desktop - it starts a websocket server and a nrepl server. You connect cider to the nrepl server, and in the readme you'll see the piece of code to put in the nodejs script. Don't forget to change the network address (from localhost to the local ip) and open firewall port
is it easy given that the nodejs instance is living in another machine?
yep
basically you set :output-dir "foo" :output-to "foo/script.js" :devtools {:devtools-url "<http://ip-of-machine-shadow-cljs.is.on:9630>"}
and either mount the foo
folder via sshfs or copy it over
best to mount though
but thats about it
so the important piece here is the devtools-url. Thanks
@henrikheine you may want to look at the shadow-cljs option instead. I haven't tried it myself, though
@myguidingstar @thheller Thank you guys! That's the way to go. Got to go now. I'll do a write-up on this when things work out.
@thheller I'm a bit curious, what is devtools
as in devtools-url
?
configures dev related stuff from shadow-cljs?
usually meant for this https://shadow-cljs.github.io/docs/UsersGuide.html#proxy-support but also works for other purposes. all it does it tell the code where it can find the shadow-cljs instance since that defaults to localhost or the current page url (which node of course doesn't have)
so it's "shadow's devtools", not "binaryage's devtools" 🙂
yes
do you think it is easy to support quickjs which is not nodejs-compatible and doesn't support websocket?
there needs to be some way to remotely connect back to the shadow-cljs instance to get hot-reload/REPL. otherwise already works if you don't need that.
see https://clojureverse.org/t/generating-es-modules-browser-deno/6116
quickjs is fine with that output
I'll have a look. Thank you very much
CrossPageChannel is deprecated in favor of MessageChannel https://google.github.io/closure-library/api/goog.net.xpc.CrossPageChannel.html
maybe clojure.browser.repl should "upgrade"
How do I access a media query in clojure. The javascript code is this
// Create a media condition that targets viewports at least 768px wide
const mediaQuery = window.matchMedia('(min-width: 768px)')
// Check if the media query is true
if (mediaQuery.matches) {
// Then trigger an alert
alert('Media Query Matched!')
}
I tried this
(. (. js/window matchMedia "--breakpoint-not-small") matches)
but it returns
#object[TypeError TypeError: window.matchMedia (...) .matches is not a function]
try with .-
since it seems to be a property and not a function
^ that's only for matches
. matchMedia
should still be used with .
because it is a function.
Can anyone explain why these docs don't seem to render in more recent versions? https://cljdoc.org/d/clojure-interop/cljs-web-api/1.0.0/api/web.Selection
Seems to me some namespaces were moved, web.Selection is web.other.Selection in .10
@claudius.nicolae many thanks!
Followup to the above question...
Once I get the selection with (. js/window getSelection)
, how do I then call methods like get-range-at
on it?
I see that I can do it like this, but it doesn't seem like it's the right way - it's not using the binding described in the docs:
{:onClick #(let [selection (. js/window getSelection)
; srange (. selection get-range-at 0)
; srange (.get-range-at selection 0)
srange (.getRangeAt selection 0)]
(web.other.Selection/get-range-at (web.Window/get-selection js/window) 0)
I can't seem to require web.other.Selection
.
No such namespace: web.other.Selection, could not locate web/other/Selection.cljs, web/other/Selection.cljc, or JavaScript source providing "web.other.Selection"
@thheller I followed https://github.com/thheller/shadow-cljs, did "npx create-cljs-project acme-app" and created a acme.core/foo.cljs - and "shadow-cljs watch my-app" (I'm using the Docker image theasp/clojurescript-nodejs:shadow-cljs-alpine). Now I try to connect the Node to the server (I do an exec into the container).
what version are you on? the ".other" bit is in the latest
node foo/my-app.js foo bar
this is acme.core/foo with args: ("foo" "bar")
REPL client error Error: connect EINVAL 0.0.37.158:80 - Local (0.0.0.0:0)
at internalConnect (net.js:913:16)
at defaultTriggerAsyncIdScope (internal/async_hooks.js:301:12)
at GetAddrInfoReqWrap.emitLookup [as callback] (net.js:1056:9)
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:65:10) {
errno: -22,
code: 'EINVAL',
syscall: 'connect',
address: '0.0.37.158',
port: 80
}
REPL client disconnected
Does this error message mean, that the NodeJS/CLJS tries to connect the server at 0.0.37.158:80 ? I have no idea where that could come from.
acme.core/foo just does a println and returns. Does that hinder the connection from being established?
org.clojure/clojurescript {:mvn/version "1.10.742"}
I meant clojure-interop version
Oh, shoot, that has to be installed separately? For some reason I assumed it's part of the cljs distro or something.
My fault! Didn't put http:// in front of IP. Getting there ....
cljs-web-api
seems to be a thin wrapper around web API. You don't need to use it - your code above is the proper way to do it via JS interop. Well, maybe you'll need to sprinkle some ^js
there if you have some problems after :advanced
optimizations.
@p-himik so it's not "more correct" to use the wrapper? It's not the more idiomatic approach?
Absolutely, thin wrappers aren't idiomatic.
IMO. :) But you can see a lot of prominent names in the Clojure community that are against thin wrappers. On the other hand, wrappers that actually do provide some useful functionality can be perfectly fine.
Thanks. This is my first bit of direct exposure to interop. I don't even know what that ^js
stuff is about and I haven't done anything with :advanced
, but I'll make a note of it for when it does come up.
At least with shadow-cljs, ^js
metadata on a symbol will tell the compiler to not mangle the names of fields/methods on that symbol that you access via JS interop. I'm pretty sure it works in the vanilla CLJS compiler. And :advanced
is just an optimization level that's typically used for production builds.
E.g. code like (.some_method x)
might be turned into e.g. x.f()
if GCC decides to shorten the name some_method
to f
. But it's not always appropriate because x
might come not from your code (where such a rename would make sense because it would be throughout the whole codebase) but from some thirdparty API, like (.getSelection js/window)
.
And (.some_method ^js x)
will always result in x.some_method()
(well, x
might be renamed but it hardly matters).
Same for
(let [^js x (somehow-get-x)]
(.some_method x))
Some details are available here: https://shadow-cljs.github.io/docs/UsersGuide.html#infer-externs
AWESOME! It works. On my Windows box (git bash) I just did a "scp -r foo <micro-box>" and then on the mirco just "node foo/my-app.js". Had to add a rule to my Windows defender firewall so that the micro could connect back to the Windows box. This is greate. So thanks a lot!!
@p-himik thanks for the thorough explanation. That makes a lot of sense. The ^js
basically forces the optimizer to leave that symbol alone.