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]
[<http://clojure.java.io|clojure.java.io> :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
don't need a :dev-http
at all when you have your own server anyways
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
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?
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?
A long time ago, I've added these to my notes: - https://www.totaljs.com/flow/ - https://nodered.org/
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.
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
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?
that really is completely your choice how you want to organize your code
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
Hm interesting
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
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
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
Yea it's npm, but not on cljsjs
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.
Thanks! Perhaps that was more of a #beginners question 🙂
I guess this is what you mean? https://gist.github.com/pesterhazy/4d9df2edc303e5706d547aeabe0e17e1
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.
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.
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 <https://dagrejs.github.io/project/dagre-d3/latest/demo/sentence-tokenization.html>
(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)]
[:div
[:h2#test "Mounting?"]
[:svg]]))))
It's the same exact mistake as before.
When you're calling d3/select
above, that svg
element is not rendered yet.
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.
I guess I looked up what a https://purelyfunctional.tv/guide/reagent/#form-2 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
Thanks! I think this post covers the relevant material: https://presumably.de/reagent-mysteries-part-3-manipulating-the-dom.html
the react lifecycle would be componentDidMount
or componentDidUpdate
or nowadays the modern variant useEffect
https://reactjs.org/docs/hooks-effect.html
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?
https://github.com/200ok-ch/org-parser seems promising, but still https://github.com/200ok-ch/org-parser/issues/30 on links and some other things.
Also tried a few https://www.npmjs.com/package/orga https://www.npmjs.com/package/org (via shadow-cljs) but they both failed with the same error: too much recursion
I'm kinda struggling using a React component in Reagent 😞
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 ...}]
But obviously that's not correct and I can;t find the example anymore
Uncaught TypeError: Cannot call a class as a function
You're probably looking for this: https://github.com/reagent-project/reagent/blob/master/doc/InteropWithReact.md#creating-reagent-components-from-react-components
omg yay
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: https://clojurescript.org/news/news#_library_property_namespaces
raw React Native components have to be adapted
https://github.com/vouch-opensource/reagent-react-native/blob/master/src/reagent/react_native.cljs
: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!