Fork me on GitHub
#clojurescript
<
2021-03-03
>
twashing02:03:07

Does anyone know, when https://clojurescript.org/news/2017-07-12-clojurescript-is-not-an-island-integrating-node-modules, how do we reference packages with @ symbols. In this case @google-cloud/pubsub ? A) Ie how would we include it in a build.edn like this. The example here fails to fetch the module.

{:target       :nodejs
 :output-dir   "public/js/compiled"
 :output-to    "public/js/main.js"
 :install-deps true
 :npm-deps     {:express        "4.17.1"
                :@google-cloud/pubsub "2.1.0"}}
B) And with the right incantation, how would we load it in?
(require '"@google-cloud/pubsub")
(require '"google-cloud/pubsub")
(require '"@pubsub")
(require '"pubsub")

twashing02:03:38

Ok, so I know the “require” is this: (require '["@google-cloud/pubsub" :as pubsub]) . But still wondering howto get the Clojurescript compiler to pull it in.

thheller08:03:21

the guide you linked is outdated and not recommended today

twashing15:03:21

Ok, I glanced again at Clojuerscript’s https://clojurescript.org/reference/compiler-options#npm-deps. And it just looks like we need to wrap the @package/name in a string. So that was my initial failure to notice. This works for me.

{:target       :nodejs
 :install-deps true
 :npm-deps     {:express         "4.17.1"
                "@google-cloud/pubsub" "2.1.0"}}

Chris McCormick07:03:46

client: we want a web based solution. also the server has to run behind our firewall. also everything is windows. me: 😎

$ make phoenix-classify-server.exe 
npx shadow-cljs release server app --debug
shadow-cljs - config: /home/chrism/dev/phoenix-species-photo-classifier/shadow-cljs.edn
shadow-cljs - connected to server
[:server] Compiling ...
[:server] Build completed. (81 files, 1 compiled, 0 warnings, 4.21s)
[:app] Compiling ...
[:app] Build completed. (79 files, 0 compiled, 0 warnings, 4.86s)
cp -v public/*.css build/public/
'public/mui.min.css' -> 'build/public/mui.min.css'
'public/style.css' -> 'build/public/style.css'
cp -v public/index.html build/public/
'public/index.html' -> 'build/public/index.html'
npx nexe build/server.js -r "./build/server.js.map" -r "./build/public/**/*" -t win32-x86-12.16.2 -o phoenix-classify-server.exe
ℹ nexe 4.0.0-beta.17
✔ Included 7 file(s)
✔ Already downloaded...
✔ Compiling result
✔ Entry: 'build/server.js' written to: phoenix-classify-server.exe
✔ Finished in 1.175s
anyone else using nexe to ship cljs?

mikejcusack15:03:46

How do you use Reveal with ClojureScript in Cursive?

mikejcusack15:03:18

For people using Reagent and want to style with Material Design how are you going about it?

mikejcusack19:03:43

Is there any way to generate ES6+ JS with CLJS?

thheller19:03:20

which part of ES6? 😛

mikejcusack19:03:31

The useful bits like let and const

thheller19:03:45

how would that be useful for us? but the answer to that is no, there is no way to make the compiler generate those.

mikejcusack19:03:18

How is generating old JS with only vars ok in CLJS, but yet if you did that in vanllla JS people would blow your head off?

mikejcusack19:03:48

I must be missing something

thheller19:03:13

the compiler takes care of writing JS code that doesn't have those issues

thheller19:03:39

how what? any particular thing you are worried about?

mikejcusack19:03:56

How does the compiler use vars and not have issues?

thheller19:03:15

the same way you did in "old" JS if you were careful

thheller19:03:11

what particular thing are you worried about? I really cannot explain the entire compiler over slack 😛

mikejcusack19:03:22

I'm trying to understand how it can use vars (mutable) and not have issues around the mutability

mikejcusack19:03:35

But I don't know the compiler under the hood

Lu19:03:54

Just a broad idea ... when you write cljs code and use a variable within a function, the compiler makes sure that generated var won’t be touched by anything else outside of that scope .. so practically it’s treated like a let.

Lu19:03:01

There’s no how .. the generated code won’t have functions manipulating that var

mikejcusack19:03:24

I'm saying how does it ensure that

Lu19:03:22

If you wanted to take the compiled code and change that var I guess you could .. but the code is produced to not ever touch that var

thheller19:03:32

a) namespacing b) shadowing

thheller19:03:30

(def a 1) becomes some.ns.a = 1 so it can't clash with (def a 1) in some other ns since that will have a different name

thheller19:03:14

then if you shadow yourself like (fn [a] (let [a (inc a)] ...) second a will actuall have a different name and not mess with the other one

mikejcusack19:03:51

And what is stopping some.ns.a from being changed to 2?

mikejcusack19:03:39

So how is that ok?

thheller19:03:41

it is just how CLJ(S) works and just because you can do certain things does not mean that you should. so people in general won't

mikejcusack19:03:03

So what's stopping rogue code from doing it?

thheller19:03:32

just like const is pretty much useless in JS. const a = { foo: 1 } can still do a.foo = 2;

mikejcusack19:03:51

That's true and one of my peeves of JS

mikejcusack19:03:58

But let still does what it claims

lilactown19:03:15

@U01NYKKE69G the semantics of Clojure, which the compiler implements, doesn't allow mutation of vars. So if all your code is in ClojureScript, then the semantics will remain

mikejcusack19:03:06

Ok. I'm just trying to learn the actual how. I like having a thorough understanding of things.

mikejcusack19:03:36

I'm trusting that what you guys are saying is true. I just want to know the details to better understand the code

thheller19:03:52

the common problems you can have in JS are not issues you'll have in CLJS. the compiler takes care of the quirks and ensures that the code actually does what you told it to do

lilactown19:03:27

when the compiler takes your ClojureScript code and converts it to JS, the compiler has rules for how it should write code. It outputs JS code in such a way that it won't cause some of the maintenance issues, like hoisting or mutating things willy-nilly

lilactown19:03:23

that's kind of a hard question to answer. It is "a simple matter of programming" as it were

thheller19:03:00

study the generated code or compiler I guess. that'll give you more answers than we can.

lilactown19:03:02

the compiler has a bunch of different steps that parses your code, analyzes your code, and then turns it into JS according to a set of common rules. those are all implemented in code

mikejcusack19:03:24

Studying the generated code is really difficult because of how it is all smashed together

thheller19:03:47

run it through prettier JS or so

lilactown19:03:02

this can give you a good sense for how CLJS code gets converted to JS, before optimizations are run: http://app.klipse.tech/

lilactown19:03:43

you can type in CLJS code and see the JS output

mikejcusack19:03:05

I can't type into the cljs box

lilactown19:03:34

hmm strange. are you on mobile?

thheller19:03:48

I also can't see the JS code?

mikejcusack19:03:58

Nope. And tried with Firefox and Chromium

lilactown19:03:38

🤷:skin-tone-2: it works on the latest Chrome on my mac for me

lilactown19:03:00

I'm sure there are other places out there

lilactown19:03:09

to view this sort of thing

thheller19:03:39

the code compiles and runs fine but I can't see the JS anywhere

lilactown19:03:09

hmm. here's what I see

mikejcusack19:03:15

For me the cljs is generated from the clj

mikejcusack19:03:36

And it's not actually cljs code

thheller19:03:03

hmm yeah that works but

(fn [a] (let [a (inc a)] (+ a a)))
doesn't

thheller19:03:29

disregard the CLJ/CLJS symbols. they are kinda confusing. this thing only supports CLJS.

3
lilactown19:03:44

@U05224H0W that is weird :thinking_face: it shows JS code once I wrap it with (def foo ,,,)

lilactown19:03:41

yeah to be clear @U01NYKKE69G: the code on the left is the ClojureScript code that one would write, and on the right is the JavaScript code that the compiler outputs

👍 3
thheller19:03:05

hmm indeed. maybe I should build a thing like this for shadow-cljs 😉

lilactown19:03:22

that would be neat! 😄

mikejcusack19:03:50

Ok, now this is helpful, thanks.

mikejcusack19:03:56

Try:

(defn example []
  (let [[count set-count] (js/React.useState 0)]
    [:div#example
     [:p "You clicked " count " amount of times"]
     [:> js/MaterialUI.Button
      {:on-click #(set-count inc)
       :color "primary"
       :variant "contained"}
      "Click"]]))

mikejcusack19:03:14

So it immediately invokes the functions

mikejcusack19:03:17

That makes sense

thheller19:03:56

if you want to get extra confused look at some :advanced optimized output. that is completely mind boggling what the compiler does with that sometimes. 🙂

😁 3
raspasov05:03:41

@U01NYKKE69G also to see fn bodies at the REPL, try

(set! *print-fn-bodies* true)

👍 6
raspasov05:03:35

=> (set! print-fn-bodies true) => + #object[cljs$core$PLUS “function cljs$core$PLUS(var_args){ var G__10823 = arguments.length; switch (G__10823) { case 0: return cljs.core.PLUS.cljs$core$IFn$_invoke$arity$0(); break; case 1: return cljs.core.PLUS.cljs$core$IFn$_invoke$arity$1((arguments[(0)])); break; case 2: return cljs.core.PLUS.cljs$core$IFn$_invoke$arity$2((arguments[(0)]),(arguments[(1)])); break; default: var args_arr__9263__auto__ = []; var len__9238__auto___10825 = arguments.length; var i__9239__auto___10826 = (0); while(true){ if((i__9239__auto___10826 < len__9238__auto___10825)){ args_arr__9263__auto__.push((arguments[i__9239__auto___10826])); var G__10827 = (i__9239__auto___10826 + (1)); i__9239__auto___10826 = G__10827; continue; } else { } break; } var argseq__9264__auto__ = (new cljs.core.IndexedSeq(args_arr__9263__auto__.slice((2)),(0),null)); return cljs.core.PLUS.cljs$core$IFn$invoke$arity$variadic((arguments[(0)]),(arguments[(1)]),argseq_9264__auto__); } }“]

mikejcusack18:03:14

Thanks for the tip! Man, that's a lot for just +

thheller18:03:12

+ is just + in most cases in the code. the above is just variadic function dispatch boilerplate since you can't actually use + that way in JS

raspasov08:03:10

@U01NYKKE69G and you can do stuff like:

raspasov08:03:13

(apply + (range 1000))

mikejcusack08:03:01

Haha, I'm not new to Clojure and ClojureScript. I've just never been a fan of JavaScript so the fact ClojureScript removes that burden has caused me to exist peacefully without opening the hood. I have looked a bit under the hood for Clojure though. I'm not sure why I have a sudden interest in opening the hood now. 😄

raspasov09:03:02

I can relate to “just never been a fan of JavaScript” 😂