Fork me on GitHub
#clojurescript
<
2022-06-21
>
Jérémie Salvucci15:06:30

Hi, I've been using clojurescript + shadow-cljs for a while and lately I bumped into a few issues related to macros + clojure dependencies. For my clojure projects, I use integrant to manage system components and this is actually very handy to describe the whole system. When I'm working on a project in dev mode, I load the dev configuration and all details are managed directly. But when I'm working with clojurescript (shadow-cljs + clojure deps), I don't have the same abilities and I'd like to address this. How do you manage your profiles (dev, test, prod) with the current ecosystem? Does something relying on integrant exist? I would like to avoid playing with classpath and same filenames to handle this.

thheller16:06:07

could you be more specific on what specific problem you are trying to solve? I mean you can use integrant in CLJS? but what is the particular issue?

Jérémie Salvucci17:06:40

for instance, I want to describe several system components with specific urls and connection details and I have different configurations depending on the loaded profile (dev, test or prod)

Jérémie Salvucci17:06:12

My main issue was related to the fact that integrant is designed for programs using clojure. I don't think I can use integrant to actually load a configuration at the clojurescript level. If I want to describe a foreign api with a specific url for dev and another for test, I can but I won't be able to access these profiles from clojurescript without going through a macro. I may be wrong here…

thheller19:06:25

well, yes the way you get access to a config file is different but you can just load if via xhr or something

thheller19:06:43

in CLJ this isn't a decision at build time and it shouldn't be in CLJS either

thheller19:06:57

so move it to runtime and either get the config via xhr or out of your html or something

thheller19:06:05

if you are running in node you can also just load it from disk of course

thheller19:06:50

the only difference really is that you cannot dynamically require namespaces

Jérémie Salvucci20:06:45

ok, I thought there was something else behind that would prevent this. But if it's just the way config files are accessed, I can try something. Thank you, I'm going to experiment

rolt22:06:06

if it's an option for you, you can "inline" all 3 configs files in your source files and select the correct one using closure define. It's not really "config" anymore though

henryw37410:06:25

fyi if you're looking for integrant-like that works in javascript (ie most likely need async components), https://github.com/juxt/clip is what I use.

Jérémie Salvucci13:06:46

Thanks, I'll take a look at it. Right now, I use macros to select the right profile and inline it for integrant to read it on client side

Drew Verlee18:06:11

This is a light survey question. Do you use Yarn or something similar but more then NPM? If so, why or why not?

genRaiy18:06:06

Trivial question ... is there a more idiomatic way of converting a string into a ClojureScript boolean?

(let [env-defaults {:DEBUG "true"}]
  ; env vars are always strings
  (.valueOf (js/Boolean. (get env-defaults :DEBUG false))))

p-himik19:06:15

Depends on the semantics that you need. Maybe a plain (= value "true") is enough.

genRaiy19:06:50

yeah, true that could work but I would rather be stricter and use a boolean the way the good lawd intended

djblue22:06:09

({"true" true "false" false} s false) 🔥

😂 1
dnolen19:06:32

@raymcdermott there's a new function called parse-boolean if you can use a more recent Clojurescript

genRaiy19:06:22

nice, and yes I can always be super modern!

genRaiy19:06:18

after playing with it I notice that parse-boolean blows up if it gets nil or a boolean. So in the above case I have to change the default to "false".

genRaiy19:06:10

so it feels odd that parse-boolean does not treat nil as false

dnolen19:06:44

the inputs must be strings for all the parse-foo fns I think by design

genRaiy19:06:05

[ it's also very modern to complain a lot 😆 ]

genRaiy19:06:41

ok, it's certainly better than the original version I had

dnolen19:06:51

you also want to be careful w/ Boolean ctor in JS has similar problems to Java

dnolen19:06:07

I think in your above case it might be ok, not sure

genRaiy19:06:06

it accepted the false :man-shrugging::skin-tone-3:

dnolen19:06:35

I mean using the ctor will make a thing which is not the primitive boolean and won't compare correctly like Java

dnolen19:06:06

I don't know the spec for .valueOf in this case

genRaiy19:06:26

.valueOf does exactly that ... returns the primitive value - that's how I made it work

genRaiy19:06:53

cos Boolean per se was indeed not useful

genRaiy19:06:25

and I guess false is OK cos you just pass that value straight through to JS ie no interop needed

dnolen19:06:43

I see from your original example why you seem to care about nil and false cases because of your use of get and get default value

dnolen19:06:41

I think just merging w/ a real defaults map first gets rid of the problem though - don't need to care about the cases

genRaiy23:06:20

I want to read a value from the environment to test whether DEBUG is on or off. I'm not sure how merge will help here. I'm probably missing something obvious.