Fork me on GitHub
#clojurescript
<
2018-03-27
>
richiardiandrea00:03:54

Async/await is basically just sugar around promise so the only way you could do that is by code rewriting like core.async, wild guess here of course, haven't looked at the Promesa code

cfleming00:03:54

@lee.justin.m yeah, the thing is I can’t see any way to do that using promesa.

cfleming00:03:20

Looking at the alet code, the strange thing is that the awaits should be taken out during macroexpansion.

cfleming00:03:43

So I think it’s actually a problem with the alet macro somehow.

cfleming00:03:47

In this case, I think the mechanism by which the async can propagate is that the function returns a promise. So in code calling that function, I would also have to use alet or manually handle the promise.

cfleming00:03:12

But this is getting towards the fairly hazy limits of my understanding of this.

justinlee00:03:33

yea that’s exactly how you’d do it in javascript, and since promesa is using promises i think that’s probably what you need to do there

cfleming00:03:50

Oh oh, thanks, that’s good to know.

justinlee00:03:50

i would think it’d be something like (alet [x (await (fn [] (alet [x (await something)] x)))])

justinlee00:03:04

where you have to repeat the alet in the inner function

justinlee00:03:10

i don’t think it’ll work if you omit that

cfleming00:03:34

Right, that’s essentially what I’m doing, except I’m manually handling the promise using then in the caller.

cfleming00:03:12

But I think the issue is that alet isn’t macroexpanding correctly since the expansion should have removed the await from the code.

justinlee00:03:13

You should also be able to do (-> (alet [x (await something)] x) (.then (fn [x] do-something))

justinlee00:03:27

i don’t get the alet macro if that doesn’t work

cfleming00:03:36

Yes, that should work.

cfleming00:03:07

Oh, I think I see the problem. I don’t think I can do (alet [x (when y (await (z)))] ...)

justinlee00:03:39

really? when just macroexpands to an if statement

cfleming00:03:07

It may be possible to implement that, but alet doesn’t right now - it just checks that the right hand side of the binding is a coll, and that the first symbol in the coll is 'await.

justinlee00:03:43

oh wow that’s good to know. well there goes my hopes for the promesa library 🙂

cfleming00:03:14

Hehe, I still really like it.

cfleming00:03:23

And that may be easy to fix.

cfleming00:03:44

Certainly in my case it’s easy to work around.

cfleming00:03:32

Yes, that was it.

cfleming00:03:22

Thanks for the help though, I feel like I improved my knowledge of the async stuff in general 🙂

lwhorton01:03:33

im having a hard time googling this — but does cljs have a built-in fn for converting a cljs ns -> js ns? it would do something like symbol -> string -> replace / with . -> replace - with _

thheller08:03:58

careful when using this at runtime. it will probably break if you use :advanced.

lwhorton14:03:12

ive been writing an “unsafe” resolve for cljs which basically just farms-out to js-eval such that it still works under advanced comp

thheller17:03:23

@U0W0JDY4C that sound pretty much impossible?

lwhorton19:03:13

not really sure yet, but it to the side

lwhorton19:03:45

the intent was to essentially just do window.namespace.name_space.fn in such a way that advanced compilation will still work, and our “invocation” just becomes window.a.b.c() when compiled

dpsutton01:03:43

Does munge work for you?

lwhorton02:03:36

sort of, thanks for pointing out that fn

danielo51515:03:44

Hello to everyone

danielo51515:03:07

I am trying to start using clojurescript, but I am having a very bad time

danielo51515:03:15

Being used to JS this is very hard to setup

danielo51515:03:38

Anyone could point me to a more or less modern template for building node-js targeted clojurescript ?

danielo51515:03:59

Thans @joelsanchez But that includes figwheel, do I really need it for node-js commandline scripts =

joelsanchez15:03:16

no but you'll need it for development

danielo51515:03:36

But it is very old, and does not include modern cljs capabilities

joelsanchez15:03:53

you may be able to use lein ancient on your project and simply update clojure and clojurescript

joelsanchez15:03:03

I say "may" because something might break

danielo51515:03:49

I have been updating them manually, currently using [org.clojure/clojure "1.9.0-alpha15"] [org.clojure/clojurescript "1.9.521"]

danielo51515:03:05

But I'm affraid there is a lot of boilerplate

danielo51515:03:32

An unnecessary stuff like :npm {:dependencies [ instead of npm-deps

danielo51515:03:38

I'm quite confused, to be honest

joelsanchez15:03:42

wish I could help you but I'm not familiar with npm-deps or node, sry

danielo51515:03:41

I am familiar with node

danielo51515:03:43

Very familiar

danielo51515:03:51

But not with clojure and lein

richiardiandrea15:03:39

@rdanielo what is that is giving you bad time in the vanilla cljs setup?

danielo51515:03:05

@richiardiandrea is not the vanilla cljs, is setting up an environment for a non-trivial node-js app

danielo51515:03:40

The template provided by @joelsanchez seems to be very good. I discarded it at first because it was using figwheel, which I though was just for the browser

richiardiandrea15:03:41

@rdanielo just trying to understand what specifically is failing so that I can help further

danielo51515:03:55

But I am a bit confused

danielo51515:03:01

How should I manage npm deps ?

danielo51515:03:20

Adding them to package.json or adding them to the compile option of project.clj ?

danielo51515:03:52

Ok, that makes sense. My old template was using :npm { :dependencies

danielo51515:03:17

Should I duplicate them both for dev and prod builds ?

danielo51515:03:19

Seems redundant

richiardiandrea15:03:25

So how you "install" the npm deps this depends on you

richiardiandrea15:03:43

You can use npm or let cljs install for you

richiardiandrea15:03:58

Yes you need that redundancy at the moment

richiardiandrea15:03:40

But a build.cljs is a program that could potentially parse package.json

richiardiandrea15:03:03

But that is already an advanced topic, better to get the basics first

danielo51515:03:24

I would prefer to move to the entire cljs ecosystem

danielo51515:03:39

So I think I will add them to :npm-deps

richiardiandrea15:03:03

Also, this is vanilla cljs - there are also alternatives like shadow-cljs or lumo

richiardiandrea15:03:34

Yep try that out and let me know how it goes, the new quick start cljs.main makes things super easy

kah0ona18:04:41

Coincidentally I also need to use an npm module (uppy), am targeting the browser. I use figwheel with leiningen. Does this apply to leiningen as well?

kah0ona18:04:58

Because I get

----  Could not Analyze  src/cljs/cs2/components/widgets/uppy.cljs  ----

  No such namespace: uppy, could not locate uppy.cljs, uppy.cljc, or JavaScript source providing "uppy"

danielo51515:03:55

Seems to make interop very easy

danielo51515:03:13

What is that cljs.main that you are talking about ? which kind of quick start is it ?

richiardiandrea15:03:46

It has just been released, all the new doc should be up to date

danielo51515:03:26

But what is it ? Is a template ? A compiler ? What is it?

danielo51515:03:00

Something that I'm missing is something like npm install for lein. I mean, I want to just make 'lein npm-install request' and make that add it to my deps

richiardiandrea15:03:01

Scroll down into node.js

danielo51515:03:05

Are you related to the project ?

danielo51515:03:22

Because I have feedback about that docs, but not sure where to report

richiardiandrea15:03:18

No, I am a contributor as well, feedback can either be sent here or to https://dev.clojure.org/jira/browse/CLJS

richiardiandrea15:03:39

They don't accept PRs on GitHub ;)

danielo51515:03:13

awesome, thanks

danielo51515:03:25

Is there any good cljs http request library ?

richiardiandrea15:03:22

I use node stuff directly usually

danielo51515:03:37

I started making a wrapper around request, but I did not wanted to re-invent the wheel

danielo51515:03:56

Do you use promises on cljs ? Or is it better to use core.async with callbacks ?

richiardiandrea16:03:26

depends on the use case, I personally use both

tmulvaney15:03:27

@richiardiandrea I may be wrong but I think the ClojureScript Site does accept issues and PRs via github https://github.com/clojure/clojurescript-site

tmulvaney15:03:10

But the actual codebase is all via JIRA like you mentioned

justinlee16:03:22

@tmulvaney @richiardiandrea @rdanielo that’s right they do accept PRs on the clojurescript site for docs--I just submitted my first one.

justinlee16:03:11

@rdanielo One point to help you out: much of what you read about “npm-deps” and using npm modules is going to be geared to the specific problems of doing on the browser, not node. Things are actually easier for you on node because you do not need to worry about advanced compilation, which requires some care, and you don’t need to worry about code size. Although I can understand the appeal of moving everything to cljs, I actually recommend that you manage you npm dependencies using npm or yarn and a package.json. Your life will be much easier.

👍 8
richiardiandrea16:03:48

@tmulvaney @rdanielo my bad they do accept PRs for the docs

danielo51516:03:53

Since file size may not be a problem, saving some extra bytes will be a great addition

jcr16:03:01

Ok, so I've tried the new cljs quickstart guide too, and also installed clj cli tools. Everything's smooth, but there are a couple of things I would definitely not like if I was a beginner: 1) I want to start a node repl, but this thing also starts a jvm process (which eats half a gigabye of ram btw); why? Confusing. 2) Stacktraces. Not helpful. I wish they were either hidden completely or written to a logfile. "IllegalArgumentException: Namespace hello-world.core does not exist" is enough to figure out the problem, no need for the stacktrace in the stdout. 3) Exception that are not catched. If I accidentally close the repl page, I get "java.net.SocketException: Broken pipe (Write failed)". I wish it would say "can't connect to the browser; is the repl open?" or something like that. 4) print-length and print-level. I wish they were set to reasonable default values in the repl, so (range) won't blow up in your face. I think that's all. By the way, clj --repl is really fast compared to lein repl, it only takes a second or so to run. Very nice for a beginner.

dnolen16:03:56

@just_crashed first thing to understand, we do not change things just because it is good or bad for beginners - that is, it’s something to weigh against everything else

dnolen16:03:01

1) ClojureScript is written is Clojure - we remote control JS runtimes - that’s just how it works. JVM has means for managing RAM usage - we’re not going to get into that in the Quick Start

dnolen16:03:52

3) other REPLs do fancier error handling, we don’t want to maintain that kind of thing in browser REPL

dnolen16:03:38

4) we’re missing support for user.cljs, would be a nice way for user to set stuff like that

jcr16:03:55

@dnolen I understand that, but at the same time I feel like official getting started guide is kinda meant to be targeted at beginners first and foremost; after all, if you're not a beginner, you probably already have your cider\cursive and .lein/profiles.clj (or whatever build tool you use) set up. At the same time, I understand that maintaining beginner-oriented stuff in core cli tools is probably not a goal.

dnolen16:03:19

yes, just way out of scope

dnolen16:03:28

cljs.main isn’t about beginners anyway

dnolen16:03:39

it’s just as awesome for experts as it is for the Quick Start

dnolen16:03:20

I’m not a beginner and I use cljs.main all the time now

dnolen16:03:43

it absolutely should and must work for everyone

dnolen16:03:08

which means it won’t be perfect for beginners - but it ain’t shabby either

jcr16:03:29

Hm, can you elaborate a bit? I realise don't quite see the place of clj in the clojure infrastructure then. I thought it was meant as a lighter\more basic\more stable alternative to lein for those who don't need any advanced stuff. Should it replace lein as the main build tool in the future? Also, do you think it might be worth mentioning community projects like maria.cloud on the getting started page then?

dnolen16:03:46

people can use whatever they want

dnolen16:03:11

but as an experienced user my own opinion is that clj is better suited to how I want to work

dnolen16:03:50

I’ve been using all the various options in anger for years now, and clj does what I actually want

dnolen16:03:26

but this completely separate from cljs.main

dnolen16:03:39

cljs.main doesn’t have anything to do with which tool you’re using

dnolen16:03:01

use it from lein, boot, with Maven - whatever

jcr16:03:56

Tbh I feel kinda uncomfortable about that, since clj and lein use different config formats, library authors have to worry about several build systems, etc. Although probably that's unavoidable anyway, sooner or later alternatives show up anyway.

jcr16:03:30

re cljs.main - yeah, I understand that, but I kinda can see that some people would prefer clj\cljs.main "stack" and others lein\figwheel "stack". But yeah, it's more of an imaginary construct, nvm

chadhs17:03:54

I’m struggling here. what’s a good strategy for actually storing the response that comes back from something like this: https://github.com/r0man/cljs-http#async-response-handling

jcr17:03:56

@U060QNFEZ you can use it as a future, you can add all responses to a single channel, it depends; what exactly are you trying to do?

chadhs17:03:34

(defn get-weather-data
  []
  (go
    (let [response (<! (http/get
                        ""
                        {:with-credentials? false
                         :query-params {"zip" "53149,us"
                                        "units" "imperial"
                                        "appid" "supersekret"}}))
          weather-data (get response :body)]
      weather-data)))

chadhs17:03:57

i want to write a helper function that will fetch weather data from an api

chadhs17:03:57

@just_crashed the problem is i can only capture this within the go block. i’m missing the mechanism for now i can reference this to get the value on demand so to speak

jcr17:03:35

go block returns the last expression as a channel, so in general you can read a value from a block just like you would read from any channel

jcr17:03:09

also, you have a blocking version of <! which can be used outside the go block

jcr17:03:31

also, you can say define a promise, and then deliver it inside the go block

jcr17:03:59

so basically it depends on how do you want to store and process your results after you've received them

chadhs17:03:55

@just_crashed what do you think would be the simplest approach if from a high level my goal is to fetch weather-data once an hour

chadhs17:03:05

using this with a SUPER simple re-frame app

jcr17:03:30

so you have your app state in an atom?

chadhs17:03:37

i just want an edn map in my state db called “weather-data” which is the body of that response.

chadhs17:03:20

@just_crashed yes the db is pretty small

chadhs17:03:24

(def default-db
  {:time-current (helper/get-time-data)
   :weather-data (helper/get-weather-data)})

chadhs17:03:47

the helpers are

chadhs17:03:52

(defn get-time-data
  []
  (js/Date.))

chadhs17:03:08

and the get-weather-data which i’m trying to write currently

chadhs17:03:35

i can prn out the response in the repl so the call works. just trying to navigate the async nature of this

chadhs17:03:58

thnx for helping me. pretty new to cljs side of things and have barely played with core.sync

jcr17:03:10

well basically you have the value you need inside the go block, right? then you can add it to the db via an event

jcr17:03:54

since you need to check it every n minutes you will have a go-loop with a timout or something like that

jcr17:03:34

so you do your api call, check if it's alright, dispatch an event to re-frame, then wait for a timeout and repeat, something like that?

chadhs17:03:42

yeah i have it all set up as far as the event sub and view flow from there. just didn’t understand how to get the value of the channel. as i have it written now it just returns nil

jcr17:03:31

In the code you've posted above, you're getting the value out of the channel into 'response'

jcr17:03:37

You mean it's nil?

chadhs17:03:59

oh correct and if i add a prn statement in there i can prove it’s really returning the response

chadhs17:03:20

but since the whole things is wrapped in the go block if i call get-weather-data it returns nil

jcr17:03:50

...and if you replace "prn" with "dispatch-sync" you will add your weather data to the db

chadhs17:03:33

i think i get it, im thinking about this a bit wrong. the operation needs to happen inside a go block

chadhs17:03:04

for example

chadhs17:03:12

(go (prn (async/<! (get-weather-data))))

chadhs17:03:16

that works

jcr17:03:21

exactly!

chadhs17:03:38

so in my initial db state and in my event i need those actions to happen in a go block

jcr17:03:54

in the context of re-frame, your just dispatch your event inside the go block, yeah

jcr17:03:01

and then write a handler for it

chadhs17:03:08

and i only need the go block in my helper namespace because i’m referencing the value to grab and return the body

jcr17:03:27

yep. so (dispatch [:new-weather-data response])

chadhs17:03:32

and i have the handler and so on already written as i’m displaying fake static values in the ui

jcr17:03:38

and then just a pure function to add that data to the appropriate place in the db

chadhs17:03:38

and time display is working and updating.

chadhs17:03:43

was just missing this piece

chadhs17:03:45

thank you!

jcr17:03:01

np, glad to help :)

chadhs18:03:29

@just_crashed im curious is there a best practice for how to initialize a re-frame app database? i’ve had odd behaviors where and event dispatch updates the db but then flips back to the old data.

jcr18:03:22

I believe initial dispatch-sync should be enough, but I'm not a re-frame expert by any means

jcr18:03:18

are you sure you didn't use the async version? because that might mean some other handler runs before initiliazation is finished

chadhs18:03:02

no worries, gives me something to think about

dnolen17:03:26

@just_crashed yes the distinction is completely imaginary

dnolen17:03:50

in fact my claim is that plugin frameworks around tools is just a busted concept

dnolen17:03:07

if tools were instead a la carte libraries like ClojureScript is as a baseline - we wouldn’t be in this mess

dnolen17:03:55

gulp vs. grunt, ivy vs maven, foo vs. bar who wants this?

jcr17:03:03

So your idea is to use clj as a single entry point and let all other tools be a libraries that run inside that? But we still at least need config files and stuff, I don't really see how e.g. making lein a library would solve the project.clj vs deps.edn problem. Did I misunderstand you?

jcr17:03:53

Oh, and lein was there long before cli tools, so I guess people didn't really had an option to make it a lib back then?

jcr17:03:36

That being said, I'd really like if build tools followed the Ring example, but that still implies a common spec format

dnolen17:03:55

clj doesn’t have anything to do with what I’m describing

dnolen17:03:04

just make your lib just work at the command line - period

dnolen17:03:37

just like ClojureScript

dnolen17:03:14

aka leverage a feature Clojure has had for nearly it’s entire existence

dnolen17:03:02

if you want to build specific integrations for lein or boot cool do that - but do ^ first

jcr17:03:49

I see. But you can't write lein itself as a library, can you?

dnolen17:03:53

No but does that matter - I doubt it

jcr17:03:16

Well then you would automatically "un-lein" anything lein-specific, so it could be used from any repl

jcr17:03:51

But yeah, it'd be a temporary ugly workaround instead of a common sense long-term solution

jcr17:03:29

By the way, I've checked the repl guides at http://clojure.org - damn! That's some awesome documentation! Really great work, don't know how I've missed it. Kudos to everyone involved.

Alex Miller (Clojure team)18:03:45

it was just added on Friday! thanks go to @U06GS6P1N!

👏 4
jcr18:03:40

@U06GS6P1N you rock :)

🎸 4
danielo51518:03:40

Hey, is anyone using nightlight for ClojureScript nodejs development? Seems like an easy way eon have a cool editor with repl and few configuration

p4ulcristian18:03:57

Hello Clojurians! I have a very small problem with my production site, but still annoying enough! In my css I use 'url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='2000' height='2000' viewBox='0 0 800 800''..., but after lein uberjar it looks like "url("data:image/svg+xml,%3Csvgxmlns='http://www.w3.org/2000/svg'width='2000'height='2000'viewBox='00800800'%3E%3Cgfill='none'%3E%3Cgstroke='%23ab8e1b'stroke-". So all spaces gets removed. What do you think causes that? I guess some cssminifying from lein uberjar, but I can't manage to find it.

john18:03:47

seems like cljs.main is both a "beginner's entry point" and an "expert's clojurescript tool" and lein and boot are still there for "everything in between"

john18:03:14

and perhaps tooling can lean on cljs.main more in the future

dnolen18:03:25

I don’t see it that way

dnolen18:03:41

you could use clj approach at pretty much every level of expertise

dnolen18:03:56

existing projects are likely to use lein or boot, but if I was doing something new I would just use clj

dnolen18:03:46

but that’s not to say you shouldn’t use lein or boot

Alex Miller (Clojure team)18:03:58

these are also not mutually exclusive

richiardiandrea18:03:05

I see it more like a tradeoff between rolling your own command line pipeline vs use something battery included...many devs have different ways of tackling how they want to build an artifact

Alex Miller (Clojure team)18:03:13

you can use plugins with lein or boot that pull deps from a deps.edn

richiardiandrea18:03:48

I see the whole thing now more "pure" cli friendly though, which is good

richiardiandrea18:03:07

(because I like cli, subjective 😄)

jcr19:03:10

Having both project.clj and deps.edn (just to fetch git deps I presume?) is, well, less than optimal imo. I would much rather prefer lein supporting everything "natively" so to speak

dnolen19:03:43

well, I don’t personally know why that is necessary, or even desirable - but if the lein community wants to sort that it will happen - but doesn’t seem like much of a win to me

dnolen19:03:34

also eventually you should start wondering why ClojureScript ~20,000 lines of Clojure starts faster than lein

dnolen19:03:41

or whatever

danielo51519:03:25

Sorry for quoting myself, but I think it got missed

dnolen19:03:52

@rdanielo maybe check the #nightlight channel? It seems like they definitely support browser based dev

dnolen19:03:01

but I don’t see anything specific about Node.js

jcr20:03:01

@dnolen well, I don't imply that lein is somehow technically superior or something like that - I really don't - but if I have a choice, I would prefer not to have two config files instead of one (if that doesn't provide some obvious huge benefits). It's just easier: here you have your profile, with source paths and deps. Now if you add e.g. lein-tools-deps you have to add plugin deps to project.clj, other deps to deps.edn. You can argue that it this case it's not a big deal, but things tend to add up. If something goes wrong, the fewer places you have to look = the better. So I would definitely prefer tools.deps to be used as a lib (just as you've said earlier!), with all the possible burden of integration handled by the lein people and NOT exposed to the end-users. Another thing to consider: the notion that clojure(script) is simply a lib, you need the build tool to do things with it (there are other build tools, but you don't have to know about it unless you want to) - this notion is a simple one, easy to understand and explain to someone. Also, one could argue that it's a question of backwards compatibility (of the platform as a whole). I'd definitely not like it if some guy 5 years in the future is working with some project written today, then needs to add some feature to the build process, asks how to do it here in the slack and everyone going "oh, you still use XXX? everyone's already using YYY, you need it for that feature, it's also 25% faster and shinier!" - you see what I mean? So you saying "lein community" kinda makes me a bit nervous (I swear I can hear howls of js developers in my head), given that probably somewhere around 95% of the clojure projects use lein today. I don't mean it at all as a critique of the work you do or something like that, it's just another perspective to consider I guess? Anyway, tl;dr: don't break the web^W lein!

danielo51520:03:40

I'll check that channel

john20:03:25

I think lein proved that we do like declarative build and dep configurations. But putting it all into one project file has made the whole thing kind of brittle and difficult to compose configurations together. There's also a problem with when there's 30 plugins connected to my project and I don't know what's impacting things.

john20:03:48

clj and cljs.main allow for lein to be decomposed into different tools

👍 4
john20:03:46

like a simple deps.edn templating tool that sits behind a clj -Anew ... alias could replace lein's new command pretty easily

john20:03:58

and even pull templates from clojars

justinlee21:03:42

@john any suggestions on reading material? I don’t really follow what you or dnolan are saying but would like to learn more

john21:03:42

in lein you'd normally use lein uberjar to make a jar, but with clj you can use clj -A:depstar -m hf.depstar.uberjar MyProject.jar as per this composable library: https://github.com/healthfinch/depstar

john21:03:49

But if you'd prefer to use a different jarring method, you could instead make an alias for https://github.com/juxt/pack.alpha

john21:03:24

and if you're doing something in dev and you need to fix something in one of these tools, you can just fork them and depend on your fork, right there in the deps.edn file that declares the lib

Alex Miller (Clojure team)21:03:33

the key point is that clj is about a) creating classpaths that include some set of deps and b) running programs

Alex Miller (Clojure team)21:03:44

and that build tools are nothing more than a set of small programs

Alex Miller (Clojure team)21:03:10

clj is designed to make that set of programs composable / customizable

richiardiandrea21:03:27

one could potentially contribute a boot tasks/fileset implementation on top of cli

john21:03:07

I think he means the reverse

john21:03:27

use boot tools as a clj lib?

Alex Miller (Clojure team)21:03:26

isn’t that what boot-tools-deps does? I’m probably just misunderstanding.

Alex Miller (Clojure team)21:03:45

do you mean invoking boot with clj?

richiardiandrea21:03:32

yes Alex (I don't think boot-tools-deps does that now, but I am checking 🙂 )

richiardiandrea21:03:08

> Updates Boot's resources, sources, and classpath based on the paths, extra paths, and classpath computed by tools.deps

Alex Miller (Clojure team)21:03:35

I guess I don’t know if that would be useful. maybe?

john21:03:02

clj -Aboot ...

richiardiandrea21:03:06

yes so I was saying that clj is lower level and could be used to call boot tasks, well maybe that's not that useful...I am brainstorming after your statement above 😄

richiardiandrea21:03:46

it would be more like the clj -m boot.main or something...but again, don't know about its value...

richiardiandrea21:03:14

just saying it is doable 😄

Alex Miller (Clojure team)21:03:46

maybe it would be if it opened the set of boot tasks through clj

richiardiandrea21:03:16

lemme try one thing

john21:03:38

then you could compose various boot tasks within deps aliases, right?

Alex Miller (Clojure team)21:03:05

not sure. aliases affect either how you build the classpath or the main opts you pass (but those replace, not add)

Alex Miller (Clojure team)21:03:25

the composition model is different

Alex Miller (Clojure team)21:03:39

seems like if you want to do that, you’re better off using boot and boot-tools-deps

richiardiandrea21:03:46

(sorry for spamming 😄 )

richiardiandrea21:03:47

I am also off-topic, this should probably go in #boot-dev

zentrope21:03:19

Is there a lein-ancient alike for the clj tool?

darwin22:03:08

just anecdotal evidence[1], if you wanted people to run clojure code as scripts from sources without forcing them to use specific build tooling (lein/boot/etc) you had to jump through hoops like I did there the good news is that what used to be 50+ lines of dirty and fragile bash/maven is now a one-liner with rock-solid clojure tool 🙂 [1] https://github.com/binaryage/dirac/commit/a7eae5e855fe7480bd949fde04f26a33d3388ecd

justinlee22:03:16

@john and others, thanks for the illuminating discussion and links. I’ve read all of that material and looked through alex miller’s slides now. I understand now the concept that tools.deps does this classpath resolution and construction. In your example, you pointed out that you could do clj -A:depstar -m hf.depstar.uberjar MyProject.jar to make an uberjar. But where are we supposed to keep recipes for builds? Still in lein? E.g., if you need to compile your sass into css, bundle up some static resources, run tests, build an uberjar, you’ll need a repeatable process somewhere. I don’t see how tools.deps helps with that.

zentrope22:03:21

@john Ah! Excellent. Thanks!

zentrope22:03:55

I’d use a Makefile. ;)

justinlee22:03:04

if that’s the actual answer, then fine. a shell script may be preferable

zentrope22:03:11

@lee.justin.m I think the Golang folks do that: use Makefile pseudo tasks to manage the various command-line invocations for their projects.

john22:03:19

what's not repeatable about clj?

zentrope22:03:04

Yeah, I think of a Makefile as a shell script, basically with some extra interesting features.

justinlee22:03:09

the steps need to be written down somewhere. right now they are written down in project.clj

justinlee22:03:29

is the idea not to do that and to just use standard unix tools?

zentrope22:03:20

With clj you have a lot of different invocations, one for test, one for uberjar, another for repl: it’s hard to remember them all, so, put them in a script, set of scripts, a makefile, etc?

justinlee22:03:43

@zentrope yes that’s exactly my question

zentrope22:03:10

That’s been my assumption. Probably not easily cross platform (if one of those platforms is windows).

justinlee22:03:16

for example, @darwin put it in a shell script

john22:03:19

We'll see. I think a lot of these things can just become composable cli declarations

darwin22:03:15

@lee.justin.m yes, use whatever tools fit the best, for me shell is the best glue at the moment, I tend to create scripts subfolder and keep my commands there as plain shell scripts

john22:03:25

but yeah, you'll need to provide collections of configs to various libs that are compiling css, etc, and we'll have to settle on a way to manage the various configs, rather than using one single project file

darwin22:03:24

I used to escape horrors of complex lein configuration by escaping into shell scripts (via lein-shell plugin) and then returning back invoking lein which often caused multiple JVM instanced stacked as a sandwich in my virtual memory - luckily enough I have a pretty beefy machine 😉

darwin22:03:22

but in this new model lein in just another unix tool at my disposal, I might decide to use it, maybe having multiple smaller config files and use them ad-hoc for specific tasks. instead of maintaining one monolithic one and rely on it as “central dispatcher” of all-things-clojure

john22:03:17

it may well be you need to make available garden.edn and advanced-testing-tool.edn as specific config files for each lib

justinlee22:03:04

huh well i’ll guess we’ll just have to see. this is all very :face_with_monocle:. the thing is the unix tools are generally not built with 30 second startup times in mind.

darwin22:03:35

well, if startup time is your issue then you should build suite of commands in your repl, fire it up once a day and then use your favorite repl prompt for invoking them

john22:03:24

actually, with the new socket server, maybe you could have a sort of repldor cljd that always runs and just does nothing until you invoke something

john22:03:16

will, if we're going down the make road, there's mach: https://github.com/juxt/mach

richiardiandrea23:03:02

this is cool stuff!

zentrope22:03:18

Regular make is fine for providing targets (short cuts for commands) and a few pre-condition checks for directories.

zentrope22:03:27

Especially if not doing true incremental builds.

Alex Miller (Clojure team)22:03:01

the vast majority of the “build” things I do are single step (but I rarely use cljs)

zentrope22:03:19

make uberjar

john22:03:29

Right, I don't think I'll need to go down the make road most of the time

john22:03:06

well, you're using it as a launcher there

zentrope22:03:21

The last line of that stolen from a Golang project (that now uses Mage (a go build tool).)

zentrope22:03:59

It’s really just a dup of lein-aliases, in this case.

zentrope22:03:29

Anyway, it does seem like using clj requires remembering several potentially complicated command-lines, or writing them down to be launched and/or cut/pasted.

zentrope22:03:40

Now we need a lein-pedantic for the clj tool….

👍 4
john23:03:36

@lee.justin.m @zentrope and I don't think I'll need remember where to put different config files and their defaults because I can still just use some project templating tool. Then I just remember the invocations and config touch points, similar to how I do now.

justinlee23:03:07

@john that sort of kicks the can down the road. what is the project templating tool going to do?

john23:03:30

you were saying that you viewed lein's project.clj as a sort of recipe. I'm just saying, you can still have that, it'll just be two or three recipes you compose together. And it'll be just as easy to construct those default recipes with some templating tool, just like lein.

john23:03:54

but who knows, if folks built something cool around using mach, maybe folks will take it a different direction

edward23:03:42

I am having trouble using let in a macro. The macro

(defmacro foo [arg]
  `(let [bar (+ 1 ~arg)]
    bar))
gives me the error
myproject.core> (foo 1)
---- Could not Analyze <cljs form> line:1 column:1 ----

Invalid local name: myproject.core/bar at line 1 <cljs repl>

1 (foo 1)
^---

---- Analysis Error ----
nil
Any ideas why?

edward23:03:17

Here is the macro expansion:

myproject.core> (macroexpand '(foo 1))
(let* [myproject.core/bar (clojure.core/+ 1 1)] myproject.core/bar)

noonian23:03:11

Syntax-quote is expanding bar into myproject.core/bar and fully-qualified symbols are not valid in let bindings. To get an unqualified symbol you can “unquote a quoted symbol” like ~'bar in your macro and you will get what you intend. However, that introduces bar into the scope which can be dangerous (it could shadow something already defined in the namespace) so Clojure provides a feature called automatic gensyms for this. If you just write bar# instead of bar Clojure will pick a good generated symbol (unqualified) and this is the correct way to do it. So you would write it like:

(defmacro foo [arg]
  `(let [bar# (+ 1 ~arg)]
      bar#))
Sorry for the long-winded reply 🙂

edward23:03:16

Wow! Amazing. Both forms work exactly as you described. Where can I find this information for future reference? I didn’t see it on https://clojure.org/reference/macros

noonian00:03:08

https://aphyr.com/posts/305-clojure-from-the-ground-up-macros has some info on gensym’s about a third of the way in (recommend searching for “gensym”). I couldn’t find many resources that talk about gensym’s that don’t introduce macro basics as well

noonian00:03:16

Clojure For the Brave And True also has a chapter on macros and again you have to search for “gensym”: https://www.braveclojure.com/writing-macros/

edward00:03:55

Cool thanks!

zentrope23:03:49

@john You use more than one deps.edn file?

john23:03:06

no, but you could provide your figwheel.edn and garden.edn and build.edn all separately. And you could use some clj -m foo.new chestnut my-project to automatically create those files and folders in their correct places, if that was your thing.

😮 4
zentrope23:03:06

Depending on what you invoke with CLJ, it would pick up the appropriate whatever.edn (in addition to deps.edn)?

zentrope23:03:16

Or would it merge, kinda like lein profiles?

john23:03:35

well, figwheel knows about a figwheel.edn I believe, if you know how to use it

john23:03:03

you can basically move your figwheel config out of profile.clj I believe

john23:03:36

it's figwheel specific edn, not necessarily like deps.edn

zentrope23:03:57

Yeah, I wouldn’t mind that. All the figwheel things are named figwheel. Easier to debug a complicated build (of which NONE SHOULD EVER EXIST! ;).

kah0ona18:04:41

Coincidentally I also need to use an npm module (uppy), am targeting the browser. I use figwheel with leiningen. Does this apply to leiningen as well?

kah0ona18:04:58

Because I get

----  Could not Analyze  src/cljs/cs2/components/widgets/uppy.cljs  ----

  No such namespace: uppy, could not locate uppy.cljs, uppy.cljc, or JavaScript source providing "uppy"