Fork me on GitHub

I’ve created a project with create-cljs-app, which is awesome. However, now I’ve enabled the server option in shadow-cljs.edn, which allows me to add routes, and I want to send data from the front-end to the back. To send a map, I would have to turn it into a string or JSON, right? Two questions (I think): what format is best to send and receive it in? And, assuming I’m right in that I have to wrap the Ring or  Compojure routes, how and where do I do this in an app created with create-cljs-app? I don’t have a familiar instance to wrap, as create-cljs-app is a little different than what I set up myself. In my shadow-cljs-edn I have:

:dev-http {8080 {:root "public"
                  :handler app.handler/handler}}
and my handler ns requires are:
(ns app.handler
  (:require [crux.api :as crux]
            [compojure.core :refer :all]
            [compojure.route :as route]
            [muuntaja.middleware :as mw]
            ;; [ring.middleware.json :as json]
            [ :as io]))
and my handler is
(defroutes handler
  (GET "/about" [] "<h1>Hello World</h1>")
  ;; (POST "/test" req (prn (read (:body req))))
  (POST "/test" req (:body req))
  (route/not-found "<h1>Page not found</h1>"))
which returns the request at /test. I need to be able to send a map from the front end and send it off to Crux. I’m open to total changes in approach… whatever I have here is just from my thrashing along. I’m using cljs-http to send from the front end with a post.


I realize this could just as easily be a question for #clojure, but as the app is a create-cljs-app one, and involves sending from the front end, I decided to post it here.


@macrobartfast I stronly recommend developing your CLJ stuff independently of shadow-cljs. do NOT use :dev-http for this, much better to have a custom server you are in full control over. just using clj -m your.server or so to run it. as for transport format I'd recommend using transit-clj+transit-cljs


I don't like or use compojure so can't answer questions regarding that


Ah, ok! Running a separate server is my usual desire but I always run into CORS issues developing locally, where I spend 99% of my time. Do you have any strategies for doing that? I’m on OSX/Chrome here. This is a hurdle I need to overcome, for sure, and I would really like to have separate clj.


I don’t know what my problem is with CORS for dev… it’s one of those simple things I never worked out.


there are no CORS issues. just have your regular webserver serve the static files shadow-cljs generates. the REPL and hot-reload run over a separate websocket talking directly to the shadow-cljs server


ah, ok… I think I remember running into issues POSTing and GETing from my front end on localhost:port-1 to the server on localhost:port-2… but I’m not sure. I’ll be switching to separating my clj code independently and I’ll message here again if I run into those issues.


yes if you run requests between multiple servers that'll have CORS issue


oh, doh… I totally just understood the matter. gotcha.


but you don't have to use multiple servers


right… because it’s serving the static file up.


that’s what I wasn’t doing right… typically had two servers, for whatever reason.


yeah, just .js files as far as your server is concerned. the dynamic stuff is handled elsewhere, not a concern for your server.


last question (if you have time)… how do you usually direct your server to the static compiled site locally… a symlink… an absolute file path… or?


I assume shadow and your server are in different projects/directories, right?


when you use ring ring.middleware.file or ring.middleware.resource


no, I have everything in one project/repo


ah, ok… I didn’t know about the ring.middleware options.


just running the code separately, code is still together completely. doesn't have to be if you prefer that


I am so sorry to be so dense… when you create your server and your shadow in the same parent/project directory, I’m assuming they are each in their own subdirectories, right?


well, I use a separate namespace yes but everything sits in src/main


so I'll have a src/main/foo/bar/server.clj and src/main/foo/bar/frontend.cljs or so


that really is completely your choice how you want to organize your code


:thumbsup: that is actually an improvement over what I would have done; I didn’t realize I could run the server and shadow off of the same src/main… thanks!


don't need a :dev-http at all when you have your own server anyways


Hello. I’m looking for suggestions for a library, set of components or framework to implement a UI to let a user describe a workflow using drag and drop (dnd) of boxes and letting her connect them with arrows/connectors. Any idea?


A long time ago, I've added these to my notes: - -


I’m looking at React Flow.


Node Red seems pretty heavy.


For info, our UI is built with re-frame and react semantic-ui


Node Red is under a permissive license so you can extract whatever you need.

Pepijn de Vos09:05:10

What would be the recommended approach for adding a js dep thats not on cljsjs yet? Can you easily contribute a new pkg to cljsjs or people just use npm?


shadow-cljs users just use npm, for figwheel (or just cljs.main) you can use :target :bundle and use npm+webpack


but if you start using npm you'll have to remove all cljsjs dependencies. they don't mix well and you'd quite often end up with duplicated dependencies

Pepijn de Vos10:05:19

Hm interesting

Pepijn de Vos10:05:52

are there any significant differences between figwheel and shadow-cljs? I remember figwheel is what was around a couple of years ago. I think I kinda like to avoid webpack and all that, but maybe that's futile once you start to use some JS things.


well the npm support is a significant difference. otherwise shadow-cljs also supports hot-reload and REPL. as far as CLJS code is concerned they are identical, still just the regular cljs compiler under the hood

Pepijn de Vos10:05:48

So figwheel is more cljs centered where shadow is more npm centered?


no, you can use shadow completely without npm too


I'd say shadow is more of a complete all-in-one tool. covers every CLJS-related build aspect


figwheel and cljs.main are sort of more build-your-own kind of deal

Pepijn de Vos10:05:53

One of the things I want to use is Jupyter Lab, which requires a Python backend service, so it'll be a fun challenge to try and rig the development hot reload stuff together with a python server. In that sense build your own sounds like it might handle that better.


both should be fine with that. hot-reload and REPL really aren't coupled to the http server you use


don't know what the jupyter JS code looks like but if its on npm then shadow (or :target :bundle) should be fine with it

Pepijn de Vos10:05:01

Yea it's npm, but not on cljsjs

Endre Bakken Stovner13:05:16

This is supposed to select an element by id and apply a different style to it:

(defn page []
    (let [_ (-> (d3/select "#test")
                (.style "color" "green"))]
    [:div [:h2#test "whoooo"]]))
Problem is, it does not work. There are no errors in the developer console. Do I need to create the HTML before setting the style? Or what might be the reason for it failing? (This is just a simple example to understand a problem in a much bigger function. I know that is not the best way to set the style for an element.)


The Hiccup that this function returns turns into a DOM node waaaay down the line. Don't use IDs with React when the API that you need accepts DOM nodes directly - just use React refs.

Endre Bakken Stovner14:05:39

Thanks! Perhaps that was more of a #beginners question 🙂


You don't need a form-3 component. You can use a form-2 component or reagent.core/with-let.


But overall - yes, that's what I meant.

🙏 3

Note that when you use a form-2 component or with-let, you should access that node directly in the function that sets the ref. So you won't have any atom that stores the ref - you will just use it immediately.

Endre Bakken Stovner14:05:07

This still just leaves me with an empty <svg></svg>. Do you see anything obviously wrong here or might my problem lie elsewhere?

;; trying to do something like 
(defn graph-page []
  (let [graph (r/atom
               (-> (dagre/graphlib.Graph.)
                   (.setGraph (clj->js {}))
                   (.setDefaultEdgeLabel (fn [] {}))
                   (.setNode "hi" (clj->js {:label "hi" :width 144 :height 100}))
                   (.setNode "ciao" (clj->js {:label "ciao" :width 144 :height 100}))
                   (.setEdge "hi" "ciao")))]
    (fn []
      (let [renderer (dagre-d3/render)
            svg (d3/select "svg")
            inner (-> svg
                      (.append "g"))
            _ (renderer inner @graph)]
         [:h2#test "Mounting?"]


It's the same exact mistake as before.


When you're calling d3/select above, that svg element is not rendered yet.

Endre Bakken Stovner14:05:08

How do I fix it? Should the outermost function create the hiccup and the innermost modify it? Seems backwards but...


As I said the first time - use React refs. The gist you yourself linked uses refs.

Endre Bakken Stovner14:05:17

I guess I looked up what a looked like, but not in context of a react-ref 😳


if you want to mix d3 with react you'll need to use refs


or you can use select but you'll need to use it in the proper lifecycle stages


the react lifecycle would be componentDidMount or componentDidUpdate


or nowadays the modern variant useEffect

Endre Bakken Stovner15:05:39

Thanks! useEffect looks especially neat. But come to think of it, the data I want to display are from a re-frame sub so by the time I get it from there, the elements will have rendered.


thats what you want. have react render the DOM element and then d3 enhance it


Anyone have experience with a good org-mode parser? seems promising, but still on links and some other things. Also tried a few (via shadow-cljs) but they both failed with the same error: too much recursion

Pepijn de Vos18:05:01

I'm kinda struggling using a React component in Reagent 😞

Pepijn de Vos18:05:45

I managed to import the JS library with ["react-plotly.js" :refer [default] :rename {default PlotComponent}] and then somewhere I saw an example where they defined (defn plot [] PlotComponent) and then just used it as an element like [plot {:data ...}]


Also, I'm not well-versed in the intricacies of requiring things from the JS world so I'm not sure whether this is actually useful in your case, but if you're using a new enough version of ClojureScript (and possibly shadow-cljs), it might be:

Pepijn de Vos18:05:46

But obviously that's not correct and I can;t find the example anymore

Uncaught TypeError: Cannot call a class as a function


raw React Native components have to be adapted