Fork me on GitHub
#clojurescript
<
2023-02-06
>
Michael05:02:45

what's currently the recommended way of doing HTTP requests with cljs? I switched to a fork of r0man/cljs-http since it seems all but dead at this point and still hasn't gotten around to merging a PR that would fix a bug that was giving off lots of warnings

hifumi12305:02:54

Last time I asked this question, it seems people use either https://github.com/JulianBirch/cljs-ajax or https://github.com/lambdaisland/fetch.

2
Michael06:02:30

fetch works great, thanks for the recommendation..

Michael06:02:53

also, how does async handling typically work? I'm trying to use core.async:

(go (let [res (<! (fetch/get ""))]
      (pprint res)))

Michael06:02:11

...but this is just giving me a ManytoManyChannel, not the actual request. #object[cljs.core.async.impl.channels.ManyToManyChannel]

hifumi12306:02:42

I don’t use core.async so I wouldn’t know, sorry

Michael06:02:51

do you use promesa?

hifumi12306:02:32

Neither. In my apps I use re-frame-http-fx, which depends on cljs-ajax, and it handles http stuff more or less transparently. I just have to declare method, URI, parameters, etc. in a map and dispatch events in my app

hifumi12306:02:49

When I do have to deal with async stuff from javascript libraries, I’ll use JS interop for promises directly

hifumi12306:02:07

e.g.

(-> (function-returning-promise)
    (.then do-more-stuff)
    (.catch handle-error))

p-himik09:02:38

Agree with the above. Interop with promises is so straightforward, I struggle to find value-add of Promesa.

2
dominicm11:02:09

I really like kitchen-async. I thought it would annoy me, but it really doesn't.

dominicm11:02:45

I'm currently using fetch via interop with a very thin wrapper to simplify query params and also throwing errors automatically.

borkdude18:02:24

kitchen-async and promesa have big overlap fetch is mostly all you need nowadays

2
Michael05:02:59

I've also just considered just using the raw fetch API, but not sure how advisable that would be

jan16:02:46

Dear clojurians. I've started to dabble in generative art using #C0FM7N1SM. For a single visual it works well, but I need to change the dev.deps.edn and restart the repl if I want to switch between sketches. So I would like to encapsulate these using a minimal web interface. The idea is that I could go to localhost:1234/sketch1 or localhost:1234/sketch2 or others. Is re-frame still the "best practice" tool for creating a minimal web interface?

p-himik16:02:09

It has never really been a tool for minimal web UIs. It's a library for state management, and in your case it doesn't seem like there'll be any state to manage. If all you need to do is just two separate web pages available at different URLs, then you don't need any WUI library at all - you can just serve barebones HTML at corresponding routes with your web server.

jan16:02:40

That indeed makes sense. Still trying to find out the focus of different tools.

jan16:02:03

The next question then obviously is how to approach creating such barebones HTML. I'm used to using javascript for this. Is http-kit + compojure what I should be looking at?

p-himik16:02:05

Creating HTML content and serving it are completely orthogonal tasks. You can write some HTML by hand just fine. Or use Selmer if you need templating functionality. Or any of the Hiccup libraries if you abhore HTML and prefer to work with Clojure vectors. Http-kit as a server is a reasonable choice. And Compojure is a reasonable routing library. For both, there are alternatives. But maybe you need neither. What exactly to use depends on what exactly you want to get. If it's two static routes that simply serve some pregenerated content, then you don't need anything apart from e.g. NGINX with some minimal config or a simple Python server (`python -m http.server`) with the right directory structure. If it's a single SPA that handles both those routes and changes the sketch depending on which route is active, without reloading the whole page, then the routing has to be handled on both the client and the server - might be easier to go with a Clojure web server then and share the routes info. In addition, you might want code reloading so when you change the CLJS code you see the changes immediately and don't need to reload the page. But maybe you already have it - if so, both of the above options should work with it.

p-himik16:02:40

But you already have a setup that servers you a single page with a single sketch, right? How does it work? Maybe you can turn it into a multi-page app with minimal code changes.

adam-james16:02:40

I think htmx may be a useful tool for something like this. Here’s an ehttps://github.com/prestancedesign/babashka-htmx-todoappthat’s a single babashka script.

jan16:02:33

The starting point for my work is the tutorial at https://www.bekk.christmas/post/2019/13/functional-generative-art-using-clojurescript, using figwheel.

jan16:02:53

My deps.edn:

{:deps  {org.clojure/clojure       {:mvn/version "1.10.0"}
         com.bhauman/figwheel-main {:mvn/version "0.2.0"}
         quil/quil                 {:mvn/version "3.0.0"}
         org.clojure/math.combinatorics {:mvn/version "0.1.6"}}
 :paths ["src" "resources" "target"]
}

jan16:02:21

My dev.cljs.edn:

{:main sketches.perlin_network}
;; {:main sketches.perlin_flow}
;; {:main sketches.circles}

jan16:02:36

And my src/sketches/ directory has 3 subdirectories: perlin_network, perlin_flow and circles. I comment/uncomment a line in dev.cljs.edn to change between the visuals (which are generated on-the-fly, so it is not pre-generated static content).

jan16:02:57

So it would be nice to have a central page on which I have a link to each of the sketches...

jan17:02:27

(To give you an idea of what is generated:

p-himik17:02:27

If you aren't in a hurry, later today or maybe tomorrow I can come up with something based on that guide as I've used quil myself, so it would be interesting to create a "framework" for multi-sketch web app. Although if you don't mind I'd prefer to use shadow-cljs instead of figwheel-main.

jan17:02:52

Thanks, @U2FRKM4TW I hadn't heard of shadow-cljs yet. A very minimal solution would be OK, and it is not time-critical, so go ahead 🙂

jan17:02:01

The index.html mentions

<body>
    <div id="sketch"></div>
    <script src="cljs-out/dev-main.js"></script>
  </body>

jan17:02:43

If I could get a handle on the cljs-out/dev-main.js? But I suppose that would be too hacky.

p-himik17:02:55

Nah, it should be an SPA - that would be most convenient IMO. Click a button/link and you're navigated to a different sketch while the previous one is paused, without being destroyed.

solf17:02:02

I just started a project using reagent + shadow-cljs + quil, and live reload works well. I'll upload a minimal example once I'm back at the home

solf01:02:16

Got a (relatively) minimal example of interaction between reagent and quil: https://github.com/llacom/example-shadowcljs-quil-reagent/blob/master/src/llacom/quil_playground/core.cljs You can see it at https://llacom.net/quil-reagent/ I’m not sure if that’s exactly what you want, but it shows how to dynamically create quil sketches, you might be able to adapt it from there

jan12:02:21

Thanks for the code, @U7S5E44DB. Unfortunately, it's not completely what I'm looking for: I need a simple way of routing between different pages. For example:

p-himik22:02:44

I did come up with something, although I decided to be brave beyond reason and try to use shadow-grove as the UI library. If that doesn't repel you, I'll upload it somewhere.

p-himik22:02:56

Ah, I still have to figure out how to do hot code reloading without resetting any of the sketches.

p-himik19:02:04

So, state preservation ended up being a PITA given how opaque a sketch is. And there were some hiccups with p5.js and its way of handling canvases. Also I ended up using Reagent because shadow-grove was just making things way more complicated than I'd like for such a small project. Anyhow, here it is: https://github.com/p-himik/quil-sketchbook

jan10:02:24

@U2FRKM4TW Thanks Eugene. That looks like what I need. It seems like there was a lot of other code necessary to get this running... The core.cljs is extensive.

p-himik12:02:09

NP. At least it's relatively straightforward, apart from the canvas hiding thing, where p5.js doesn't behave in a nice way.

jan12:02:03

I think that the canvas hiding was one of the problems that I had as well. But now I can start working on the interesting code again 🙂

🎉 2
jan10:02:20

@U2FRKM4TW I've been able to recreate some of the plots that I generated in javascript earlier using the framework you set up. Thx. To make sure that I understand it correctly: every namespace (i.e. every sketch) is always loaded, right? Will that not give issues with memory consumption? (I notice that a js/console.log in sketch A will still show up even if I work on sketch B). Is there a way to "unmount" the sketches when not selected?

jan10:02:50

(Note: I'm used to working with javascript svelte, and as a framework it's pretty well set up)

p-himik11:02:33

I doubt p5.js+quil use so much memory that you'd notice even with a hundred of sketches, and yeah, sketches are on pause when they are inactive. But you should test it anyway if the page will have memory constraints. The whole point of this exercise, at least for me, was to create something that preserves the state when switching between sketches. With unmounting, the task would be significantly simpler.

p-himik12:02:47

But you wrote: > I notice that a js/console.log in sketch A will still show up even if I work on sketch B Do you mean its update function? Or just the initialization function? Because if it's the former, then something needs to be fixed. And of course, if you would still like to have an ability to unmount a sketch when it's inactive and initialize and mount it again when it's active, feel free to create an issue in the repo.

jan12:02:20

It's indeed in the draw function... There might be another small issue, though: sometimes one of the sketches does get redrawn constantly, even though there is a (q/no-loop) in the setup. Refreshing the page fixes this.

p-himik12:02:11

Hmm. Is there an easy way to reliably reproduce it?

jan12:02:01

I'm not sure, but it seems to happen when I opened a sketch that does loop, and then open one that doesn't. Not 100% sure, though.