Fork me on GitHub
#clojurescript
<
2020-12-20
>
henrik4210:12:09

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?

myguidingstar10:12:53

@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?

henrik4211:12:05

@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?

myguidingstar11:12:24

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)

myguidingstar11:12:46

in your case, you need the later, not the former

myguidingstar11:12:52

(you don't need to look into the above bootstrap_nodejs.js, that's only for reference)

thheller11:12:57

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

myguidingstar11:12:18

is it easy given that the nodejs instance is living in another machine?

thheller11:12:10

basically you set :output-dir "foo" :output-to "foo/script.js" :devtools {:devtools-url ""} and either mount the foo folder via sshfs or copy it over

thheller11:12:13

best to mount though

thheller11:12:24

but thats about it

myguidingstar11:12:56

so the important piece here is the devtools-url. Thanks

myguidingstar11:12:18

@henrikheine you may want to look at the shadow-cljs option instead. I haven't tried it myself, though

myguidingstar11:12:07

@thheller I'm a bit curious, what is devtools as in devtools-url?

thheller11:12:09

configures dev related stuff from shadow-cljs?

thheller11:12:51

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)

myguidingstar11:12:46

so it's "shadow's devtools", not "binaryage's devtools" ­čÖé

myguidingstar11:12:33

do you think it is easy to support quickjs which is not nodejs-compatible and doesn't support websocket?

thheller11:12:35

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.

thheller12:12:41

quickjs is fine with that output

myguidingstar12:12:40

I'll have a look. Thank you very much

henrik4219:12:30

@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).

henrik4219:12:51

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

henrik4219:12:25

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.

henrik4219:12:40

acme.core/foo just does a println and returns. Does that hinder the connection from being established?

henrik4220:12:17

My fault! Didn't put http:// in front of IP. Getting there ....

henrik4221:12:08

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!!

­čśä 3
myguidingstar11:12:41

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

henrik4211:12:39

@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.

clyfe12:12:24

CrossPageChannel is deprecated in favor of MessageChannel https://google.github.io/closure-library/api/goog.net.xpc.CrossPageChannel.html

clyfe12:12:04

maybe clojure.browser.repl should "upgrade"

GGfpc16:12:49

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]

valerauko16:12:18

try with .- since it seems to be a property and not a function

p-himik17:12:34

^ that's only for matches. matchMedia should still be used with . because it is a function.

­čĹŹ 3
­čĺ» 3
Buidler18:12:33

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

clyfe18:12:26

Seems to me some namespaces were moved, web.Selection is web.other.Selection in .10

Buidler19:12:04

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)]

clyfe19:12:47

(web.other.Selection/get-range-at (web.Window/get-selection js/window) 0)

Buidler19:12:53

I can't seem to require web.other.Selection.

Buidler19:12:45

No such namespace: web.other.Selection, could not locate web/other/Selection.cljs, web/other/Selection.cljc, or JavaScript source providing "web.other.Selection"

clyfe19:12:39

what version are you on? the ".other" bit is in the latest

Buidler19:12:18

org.clojure/clojurescript {:mvn/version "1.10.742"}

clyfe20:12:00

I meant clojure-interop version

Buidler20:12:31

Oh, shoot, that has to be installed separately? For some reason I assumed it's part of the cljs distro or something.

p-himik20:12:53

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.

Buidler20:12:18

@U2FRKM4TW so it's not "more correct" to use the wrapper? It's not the more idiomatic approach?

p-himik21:12:17

Absolutely, thin wrappers aren't idiomatic.

p-himik21:12:58

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.

Buidler21:12:49

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.

p-himik21:12:39

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).

p-himik21:12:00

Same for

(let [^js x (somehow-get-x)]
  (.some_method x))

Buidler21:12:23

@U2FRKM4TW thanks for the thorough explanation. That makes a lot of sense. The ^js basically forces the optimizer to leave that symbol alone.