Fork me on GitHub
#clojurescript
<
2019-10-14
>
akond05:10:34

i have an expression

(->> [:#container
	 [[:p {:margin-bottom "8px"}]]]
	garden.core/css)
is it possible to define a var that contains a result of this expression at compile time?

akond05:10:31

what i want is a string instead of all this.

paul93122406:10:36

Hello guys, I need a little help with shadow-cljs. I can't make the css hot reload work.

paul93122406:10:00

this is my filesystem

paul93122406:10:32

and this is my lein-shadow config

thheller08:10:59

don't set :watch-dir or :watch-path at all and it should just work. assuming you are including the css via <link rel="stylesheet" href="/css/site.css">

thheller08:10:21

and accessing everything via ?

paul93122410:10:49

unfortunately it doesn't work this way either. I have a http-kit server, and this is where I link my css. (live reload of code works, only css doesn't)

thheller13:10:27

so you are not using the built-in server on port 3000? you can then remove the :http-port 3000 from the config and just add :watch-dir "resource/public" (no :watch-path)

paul93122415:10:42

this is my nem config. still doesn't work though 😞 (anyway, I am fascinated by your work on shadow-cljs)

thheller16:10:04

did you check the devtools requests panel? or console? it might be sending the request and your webserver just might provide the old version?

thheller16:10:01

and check if there is an actual <link rel="stylesheet" href="/css/site.css"> in your HTML. not sure what include-css actually emits?

paul93122422:10:44

well I checked the devtools, it wasn't there, the link was okay. I spent some hours with it then it magically started to work again. I looked at https://github.com/jacekschae/shadow-reagent , downloaded it, tried it out to see it work, and when I started my original project css reload worked 😄 Thank you for cleaning up my misunderstanding about http-root and helping me repair my config!

thheller23:10:18

the :source-paths you can probably also remove unless lein-shadow does something with them. shadow-cljs won't use them if you use lein.

paul93122423:10:29

I call shadow-cljs from the repl with (dev). Thank you, I removed :source-paths aswell.

leonoel07:10:05

@akond compute it in a macro, and emit the result

akond08:10:31

i have tried that. but somehow i didn't manage to achieve the required effect.

akond08:10:03

(defmacro compile-time-value []
	#?(:cljs (->
				 [:#popup-container
				  [[:p {:margin-bottom "8px"}]]]
				 garden.core/css)
	   :clj  ""))

leonoel08:10:27

why are you using a reader conditional here ?

akond08:10:44

i was to told to do so

akond08:10:53

i tried both with and without reader conditional, actually. none worked out for me.

leonoel08:10:51

it should work without the reader conditional, because macros are run in clojure (assuming you're not self-hosted).

leonoel08:10:41

are you sure your macro is properly required ?

akond08:10:30

i thought a simple (:require nss :as alias) would do.

leonoel08:10:34

try adding a (:require-macros [your-ns :refer [compile-time-value]]) to the cljs namespace

akond08:10:52

it works!

akond08:10:11

a-a-a-a-h!!!!!!!!!!!

akond08:10:40

thank you very much, sir.

thheller09:10:43

please stop using :require-macros in consumer namespace. the only :require-macros you should ever have is (ns some.thing (:require-macros [some.thing])) so its own name

akond09:10:12

it is a very helpful article.

akond09:10:42

it is a pity i hadn't seen it

thheller09:10:39

well I only posted it a couple days ago 😉

leonoel09:10:52

it should be in official documentation

Risetto08:10:58

I have a let statement with a reagent atom, and within the let I have a for. I want to reset! the value of my atom from within the for loop but it seems like it don't have access to my let variable from there?

Lu08:10:54

Can you share that code snippet? @olle142

Risetto09:10:47

(defn box [element]
  (let [selected-box (reagent/atom "")]
    (for [option (:options element)]
      ^{:key option} [:div.box
                      {:on-click #(reset! selected-box (:value option))}])))

Lu09:10:01

@olle142 your atom is being redefined at each rerender. You need to use reagent form 2 .. which means wrapping your dom elements (your for loop) with an anonymous function

Risetto09:10:48

That did the trick, thanks @Lu!

clj 4
Risetto09:10:58

If I want to add a class to my :div.box based on selected-boxs' value, do I have to force a rerender or something?

Lu09:10:19

@olle142 Not really 🙂 You can simply do:

[:div.box
 {:class (if (= @selected-box "your-value")
           "this class"
           "other class")
  :on-click #(reset! selected-box (:value option))}]

Risetto10:10:54

Ah that's awesome, thank you so much 😄

Lu10:10:26

You're welcome 😄

Lu09:10:09

Whenever your selected-box atom is reset you're guaranteed that the re-render happens and the if statement will be evaluated again to assign the right class 🙂

Ramon Rios12:10:21

Does someone has face it before?

Ramon Rios12:10:58

That's my view

Ramon Rios12:10:08

(defn role1-panel []
  [:div ])

(defn role2-panel []
  [:div [:h1 "Hello from role2!!!"]
   [:a {:href (routes/home)} "Home"]])

(defn role3-panel []
  [:div [:h1 "Hello from role3!!!"]
   [:a {:href (routes/home)} "Home"]])

(defn role4-panel []
  [:div [:h1 "Hello from role4!!!"]
   [:a {:href (routes/home)} "Home"]])

(defn home-panel []
  (fn []
    [:div
     [:h1 "Main Menu"]
     [:ul
      [:li [:a {:href (routes/role1)} "Role 1"]]
      [:li [:a {:href (routes/role2)} "Role 2"]]
      [:li [:a {:href (routes/role3)} "Role 3"]]
      [:li [:a {:href (routes/role4)} "Role 4"]]
      [:li [:a {:href (routes/home)}  "Home"]]]]))


(defn main-panel []
  (let [p (rf/subscribe [:db-admin-service/current-panel])]
    (js/console.log "current panels" p)
    (if-let [c @p]
      [c]
      [home-panel])))

Ramon Rios12:10:46

That's my subs.cljs

(def components-per-id {:home-panel [v/home-panelsu]
                        :role1-panel [v/role1-panel]
                        :role2-panel [v/role2-panel]
                        :role3-panel [v/role3-panel]
                        :role4-panel [v/role4-panel]})

(rf/reg-sub
 :db-admin-service/current-panel
 (fn [db]
   (js/console.log "isso funciona mesmo?")
   (get components-per-id (d/current-panel db))))
 

Ramon Rios12:10:19

my routes

(defn select-menu
  "Dispatches an event that selects the given menu.  Any parameters can also be passed on."
  [id & [params]]
  (rf/dispatch [:db-admin-service/select-menu id]))


(defroute home "/" [query-params]
  (select-menu :home-panel query-params))

(defroute role1 "/role1" [query-params]
  (select-menu :role1-panel query-params))

(defroute role2 "/role2" [query-params]
  (select-menu :role2-panel query-params))

(defroute role3 "/role3" [query-params]
  (select-menu :role3-panel query-params))

(defroute role4 "/role4" [query-params]

benzap13:10:45

try changing (defn role1-panel [] [:div ]) to (defn role1-panel [] [:div nil])

Ramon Rios15:10:47

My issue was that i was returning a vector inside other vector

Ramon Rios15:10:57

As soon as i put a 3 vector it worked

scknkkrer12:10:02

Hi @ramon.rios, can you share your code here ?

Brad S16:10:23

quickstart question on Windows: Exception in thread "main" java.nio.file.InvalidPathException: Illegal char <:> at index 2: /D:/xx/xx/xx/src/clojure/test/out/cljs/core.js

Brad S16:10:33

from this command: java -cp "cljs.jar;src" cljs.main --optimizations advanced -c test.core

Brad S16:10:44

it looks like it's because of the /D:

Brad S16:10:55

wonder if anyone knows how to get past that error, thanks

Brad S16:10:38

ANSWER: delete the "out" folder before doing this

itaied17:10:14

I'm trying to call var provider = new firebase.auth.GoogleAuthProvider();. Did this: (ocall firebase "auth.GoogleAuthProvider") Got this:

app.js:2176 failed to load shadow.module.app.append.js TypeError: this.wa is not a function
    at  (auth.js:134)
What am I doing wrong?

thheller17:10:04

using ocall in the first place. seriously do not ever use it.

thheller17:10:34

assuming that firebase was your :as alias in the :require you probably just want firebase/auth.GoogleAuthProvider?

itaied17:10:14

Yea that actually worked, but how can I execute something like this: firebase.auth().signInWithPopup(provider).then(...).catch(...)

lilactown17:10:04

@itaied use the dot form of interop

lilactown17:10:57

you can call a method on an object like (.foo bar) where foo is the method name and bar is the object

thheller17:10:37

(-> (firebase/auth) (.signInWithPopup provider) (.then ...) (.catch ...))

itaied17:10:57

Well I couldn't make it work... Executing this: (println (-> (firebase/auth) (.signInWithPopup (firebase/auth.GoogleAuthProvider)))) resulted:

app.js:2176 failed to load shadow.module.app.append.js TypeError: this.wa is not a function
    at  (auth.js:134)
    at Function.d [as GoogleAuthProvider] (auth.js:359)
    at Object.ui$auth$core$auth_init [as auth_init] (core.cljs:17)
    at Object.ui$core$mount_root [as mount_root] (core.cljs:18)
    at Object.ui$core$init [as init] (core.cljs:25)
    at eval (/js/compiled/cljs-runtime/shadow.module.app.append.js:2)
    at eval (<anonymous>)
    at Object.goog.globalEval (app.js:827)
    at Object.env.evalLoad (app.js:2174)
    at app.js:2431

itaied17:10:55

And actually, just running this (firebase/auth.GoogleAuthProvider) result in the same error

thheller17:10:16

what is the JS example for using this?

thheller17:10:37

seems like you are maybe calling it before initializing something else you are supposed to initialize?

itaied17:10:38

var provider = new firebase.auth.GoogleAuthProvider();

itaied18:10:10

There is an init function that I call just before this one

thheller18:10:51

do you have a link or something?

thheller18:10:59

one isolated line of code doesn't tell the whole story

thheller18:10:08

also which version of firebase do you use?

thheller18:10:33

and your requires?

thheller18:10:49

(:require ["firebase" :as firebase] ["firebase/auth"])?

itaied18:10:08

(ns ui.auth.core (:require ["firebase/app" :as firebase] ["firebase/auth"] [oops.core :refer [oget ocall]]))

thheller18:10:29

seems like that should work then

thheller18:10:24

(firebase/auth.GoogleAuthProvider) this is calling it as a function

thheller18:10:35

but its a constructor so you should call it as (firebase/auth.GoogleAuthProvider.) maybe?

thheller18:10:54

ie. new Thing() instead of Thing()

itaied18:10:41

just a sec

thheller18:10:02

yep definitely add the .

thheller18:10:40

(firebase/auth.GoogleAuthProvider.) or (new firebase/auth.GoogleAuthProvider)

itaied18:10:20

it did work !

itaied18:10:27

wow thanks a lot man 🙂

itaied18:10:04

I read the warning of oops and the advanced renaming. is it safe to use interop this way?

thheller18:10:23

cljs-oops is working around really really old problems that are either fixed or have "easier" solutions

itaied18:10:10

thanks again 🙂

itaied17:10:08

does it make any difference if I call (firebase/auth) or (.auth firebase)?

thheller17:10:52

:as firebase sets up a namespace alias. so it should be used as such (ie. firebase/*)

thheller17:10:23

the dot form also works but the compiler handles it slightly differently. mostly works but more stuff you have to watch out for (eg. var shadowing)

lilactown19:10:22

has anyone tried using shadow-cljs or figwheel with macOS Catalina? any issues?

thheller20:10:42

@lilactown you should give it a try and let us know. 😉 if you also run into the hawk issue I'll need to figure out how to detect catalina and disable it by default

👌 4
lilactown20:10:49

lol. I just sent an @all at work telling people not to upgrade until I can verify. I am going to try and get ahold of someone who’s already done the upgrade

mfikes21:10:52

I’ve been using Catalina with various ClojureScript projects for the past few months—I saw no issues.

Trevor22:10:18

Is there any existing library or tool which reads a typescript .d.ts file and generates clojurescript bindings for that typescript file? Wanted to check before I see about hacking one up

thheller22:10:43

what kind of bindings do you have in mind? you don't really need bindings if you can just call the code directly anyways?

Trevor22:10:28

Well I'm still hung up on the autocomplete thing. I can get autocomplete on my own namespaces, so I figured it wouldn't be to hard to have a script that generated all the stuff I would write by hand anyway so I could get some autocomplete in Cursive

Trevor22:10:31

Cause yeah shadow-cljs makes it super easy to ensure the javascript is included and accessible, but it would be real nice if I didn't have to jump into an npm libraries docs to figure out the API

thheller22:10:24

hmm yeah not aware of anything that would do this

Trevor22:10:09

I thought I had found something with https://github.com/angular/tsickle but I missed the s in Closure there 🙂

thheller22:10:35

but cursive has this feature to generate "stubs". not sure if you can actually abuse this but it basically does the same things to provide a bit more completion for macro generated code

Trevor22:10:16

Kotlin's dukat tool is trying to do something like this, but it's way harder for Kotlin, cause it's trying to reconcile two very different type systems. For clojurescript I think I just need to look for export class and export function and get the names of the parameters and dump those to a cljs file

thheller22:10:30

maybe cursive supports the closure output though. not sure how much of the closure library it actually supports

Trevor22:10:36

I mean I haven't done anything yet so there's probably something I'm not thinking about, but figured I'd ask first

thheller22:10:02

yeah the issue with npm is that there is no clear standard

thheller22:10:16

every package does its own thing and its a complete mess

thheller22:10:30

so its really hard to index everything in a "sane" way

thheller22:10:01

I wish it was as simple as just looking at export 😛

Trevor22:10:54

Sure, I'm just going for 80% useful. My day job is typescript + kotlin, and we rarely use an npm library that doesn't have a decent set of typescript bindings, and those are fairly predictable.

Trevor23:10:07

No idea if it'll work, but would be neat if I could just run something against a .d.ts and generate some basic cljs to work with

dazld10:10:57

Would it create stubs? Bit like the datomic stubs cursive creates..? That’s a fun idea.

dazld10:10:13

Lack of completion for interop does make exploring js libraries a little slow and error prone.

dazld10:10:55

As @U05224H0W mentioned below, I guess it’s part of the externs puzzle. Cursive adds stubs to the classpath, I think, to enable completion during dev. Making those stubs and doing something similar would be super cool.

Trevor20:10:56

Yeah absolutely. Just stubs. I'm looking around there isn't a super simple thing to use to look at a .d.ts file and get the exports. For a proof of concept I'll probably just try some regex.

Trevor20:10:37

Yeah I'm not sure how it would really work in the larger picture, proof-of-concept I'll just dump the stubs to src/ts/... for now.

Trevor20:10:55

I'm trying to see if there is some way to get tsc to dump an AST, but ain't seeing anything yet

Trevor20:10:28

Hmm, and Kotlin is trying to solve this problem too: https://github.com/Kotlin/dukat However, clojurescript doesn't care about the types, which should make this way simpler. I wonder if I can hack the final output step to generate the clojurescript bindings 🙂

Trevor21:10:57

Yeah, I think I'm going to fork dukat and add an option to output cljs bindings 🙂

thheller23:10:44

yeah I'd be interested to see that

thheller23:10:22

thought about using .d.ts for externs related things some time ago

Trevor23:10:56

I think it might not be too crazy cause cljs really would only care about the class/function name and it's args. The cljs doesn't care if the args have super crazy extended types so we can ignore them. Kotlin on the other hand has to do some legit gymnastics to reconcile literal types into kotlin code that's still adhering to a JS api

👍 4