when deploying my fulcro app it crashes saying postgres refused to connect.
does anyone know if there's more information available anywhere for configuring the prod.edn
file in the template?
my guess is it may be something in there?
No exception? No stack trace? Have you debug Iogging on? (see default.edn)
the specific error is Connection to localhost:5432 refused. Check that the hostname and port are correct and that the postmaster is accepting TCP/IP connections.
there's a number of thing that can be causing this but my understanding is that it's ssl rleated.
if you suspect that there is some java ssl system property you can set to get detailed logs (not related to Fulcro in any way)
@holyjak, first of all awesome writeup and I do have a question, looking at the first diagram of https://github.com/fulcro-community/guides/blob/main/minimalist-fulcro-tutorial/index.adoc#an-overview-of-fulcro, makes me wonder where does the application code fit in? So there are resolvers, the front end (the defsc macro), parsers and so on. I wonder if it is possible to make a diagram showing where each of these elements fit in.
@timofey.sitnikov I have added a section for your figure, see https://github.com/fulcro-community/guides/blob/main/minimalist-fulcro-tutorial/index.adoc#review
Re-reading my own comment….“There’s no alternative way to talk to a remote” means “through Fulcro’s mechanims”…you can of course use http client or any such thing to grab data, and one you have data you could use swap! against Fulcro’s state atom, but you’d get zero support from Fulcro that way. By at least using merge-component!
you’d get normalization and refresh. By using the official mutation/remote system you get even more. Just clarifying.
Thank you! Do you think it is worth it? Defsc clearly belongs to the UI, parser and resolvers to Pathom, defmutation to both. It is simple, no?
I'm having trouble getting fulcro-rad to start up. I'm using a copy of fulcro-rad-demo as is - I have not made any changes yet.
When I execute shadow-cljs watch main
, I get this:
Execution error (IllegalArgumentException) at shadow.build.js-support/eval15243$loading (js_support.clj:1).
No matching field found: getRegisteredGroups for class com.google.javascript.jscomp.DiagnosticGroups
It looks like a version conflict in the Google closure compiler code being called by shadow-cljs?
The nearest issue I have found is https://github.com/thheller/shadow-cljs/issues/488. I followed Thomas' https://shadow-cljs.github.io/docs/UsersGuide.html#failed-to-load, and checked dependencies. My project was using a slightly older version of closure-compiler-unshaded, as listed https://clojars.org/thheller/shadow-cljs/versions/2.8.110 for the corresponding version of shadow-cljs. I forced the correct version of closure-compiler-unshaded in my deps.edn
, but it made no difference. I also checked the source code of closure-compiler-unshaded and it does contain the getRegisteredGroups
method. I have also confirmed that the correct version of the library is being used with clj -Spath
.
Has anyone experienced this before? I find it strange that the exact copy of the repo as is, runs into this problem?
@andre.richards that is definitily a version conflict. should be
org.clojure/clojurescript 1.10.773
com.google.javascript/closure-compiler-unshaded v20200830
It becomes simple after a while, but there are a lot of components that fit together and it is not easy to grasp it right away. I tried to put something together quickly, but it needs more work. The idea is to gain understanding of how everything fits together.
Thanks @thheller. I changed it to those versions, but still get the same error...
@holyjak, let me know what you think.
did you restart the shadow-cljs process after? did you change it in the correct place?
Hi, yes I did restart. If I do clj -Spath
to print the classpath, I get this (I split and filtered classpath using clojure just to make it easier to find correct info):
("/Users/andre/.m2/repository/org/clojure/google-closure-library/0.0-20191016-6ae1f72f/google-closure-library-0.0-20191016-6ae1f72f.jar"
"/Users/andre/.m2/repository/org/clojure/google-closure-library-third-party/0.0-20191016-6ae1f72f/google-closure-library-third-party-0.0-20191016-6ae1f72f.jar"
"/Users/andre/.m2/repository/com/google/javascript/closure-compiler-externs/v20200830/closure-compiler-externs-v20200830.jar"
"/Users/andre/.m2/repository/com/google/javascript/closure-compiler-unshaded/v20200830/closure-compiler-unshaded-v20200830.jar")
and which clojurescript version? and which shadow-cljs? they all need to align otherwise you get this error
ClojureScript:
("/Users/andre/.m2/repository/org/clojure/clojurescript/1.10.773/clojurescript-1.10.773.jar")
shadow-cljs:
("/Users/andre/.m2/repository/thheller/shadow-cljsjs/0.0.21/shadow-cljsjs-0.0.21.jar"
"/Users/andre/.m2/repository/thheller/shadow-cljs/2.8.110/shadow-cljs-2.8.110.jar"
"/Users/andre/.m2/repository/thheller/shadow-util/0.7.0/shadow-util-0.7.0.jar"
"/Users/andre/.m2/repository/thheller/shadow-client/1.3.2/shadow-client-1.3.2.jar")
This is the version of shadow-cljs specified in the fulcro-rad-demo. Should I try the latest shadow-cljs?
I have included my config files
well as I said .. they need to align. and that shadow-cljs version is too old for the above
yes, you should try 2.11.15
. or get the matching versions for the older ones https://clojars.org/thheller/shadow-cljs/versions/2.8.110
Cool! Sadly neither Slack nor my phone can display it. Will try later on PC
Thanks, 2.11.15
is working.
I promise, I did earlier match my versions of clojurescript and Google closure compiler to https://clojars.org/thheller/shadow-cljs/versions/2.8.110 :man-shrugging:
Thanks again for your help. I'll sponsor you a drink on GitHub if you are listed there for sponsorship. 👍
ideally you just have shadow-cljs as a dependency then you don't need to worry about it for the most part
but that also runs into trouble if other libs declared dependencies on other clojurescript versions that they shouldnt
so yeah its a bit messy unfortunately
@holyjak OK, here you go.
Understood, thanks 🙂 And thanks for a wonderful library! 👏👏
Nice! Yes, I guess something like this could be useful. Do you want to polish it when you have time?
Where would it fit into the doc? How about adding it into the doc and polishing it as we go?
One more version
OK, so I created a pull request for you and when you have time, maybe you can place it into the right section and I will keep working on it.
I am going to make one more post, on the main thread, maybe I can get some good feedback.
Good morning Clojurians, I am trying to create a diagram of how parts of fulcro work together. Here is what I have, I am looking for some feedback, how can I make it more accurate/better?
You have defmutation
displayed on the frontend side, but not on the backend. Perhaps add that in to the Pathom section to show that mutations exist there as well?
So remember that mutations all go through mutations
Here is my attempt to do simple typeset for your diagram, with my suggestion using the example of People and Car in the Fulcro 3 tutorials. It looks not very pleasant, but it has the advantage that it's created with text, that we can effectively edit the textual specification to improve it together. Here is the source code:
#+BEGIN_SRC plantuml :exports none :file ./normalization-illustrated.png
@startuml
skinparam linetype polyline
title App State
rectangle "UI" as UI {
circle "root :sample" as root_data
rectangle ":sample" as sample_table {
circle ":person/id 3" as person_id_3
rectangle ":car" as car_table {
circle ":car/id 22" as car_id_22
circle ":car/id 42" as car_id_42
}
}
}
database "Normalized Data Graph" as DB {
'rectangle "root :sample" as root_data
rectangle ":person/id" as person_table_n {
rectangle ":person/id 3" as person_id_3_n
}
rectangle ":car/id" as car_table_n {
rectangle ":car/id 22" as car_id_22_n
rectangle ":car/id 42" as car_id_42_n
}
}
UI .right.> DB : UI tree to normalized DB
root_data -down-> person_id_3
'person_table -down-> person_id_3: :person/id 3
'car_table -down-> car_id_22 : :car/id 22
'car_table -down-> car_id_42 : :car/id 42
person_id_3 -down-> car_id_22
person_id_3 -down-> car_id_42
person_id_3_n -down-> car_id_22_n : person/cars
person_id_3_n -down-> car_id_42_n : person/cars
@enduml
#+END_SRC
With your correction/feedback, I can further improve it. (I'm still not quite comfortable with modeling the data in terms of graph yet. My understanding may not be accurate.)
I use https://plantuml.com/ to create it with my emacs setup.Thanks for giving that a try. The main concept I was trying to get across is just that the operations of Fulcro are always centered around some portion of a tree. Sometimes it’s the whole tree, sometimes it is a subtree. But the overall point is that a very small number of core concepts are involved in pretty much everything you do.
I’m not sure what to say about your diagrams. I sorta see what you’re getting at, but they don’t convey what I was trying to get across.
The “dashed lines” for something that doesn’t exist at some point, and stressing manipulation of/with subgraphs was most of what I was trying to talk about
mixing in keywords might be helpful somehow…this is really more of a whiteboard discussion/lecture I think, or a presentation with animations 😄
I'll try to express your idea of partial tree of UI elements being absorbed into the normalized tables.
That’s basically what’s in my head on those kinds of diagrams. Use dashed lines for elements that you “know the shape of” from the query, but do not yet have in the database. Initial state is just the portion of the UI that goes into client db, and then is turned into a tree for sending to root. Root is only able to render the data it gets. Loads/merge component are just “tacking” new things into the db, and then creating edges (targeting).
The operation of Fulcro is really mostly those three frames. Start, render, put in data, render, put in data, render …
and render is nothing more than “get data from db w/query and pass to root”
Mutations are the missing part from this set of diagrams, because there’s also the “fiddle with db and issue remote updates that can return data”…But a load is just a special internal mutation that has one particular structure
There’s a mutation diagram that might be useful @timofey.sitnikov
Sorry, I do not really get this "mutations all go through mutations". You mean that remote Fulcro mutations are sent as EQL mutations?
Technically a mutation can talk to any number of remotes, or a transaction could run some number of mutations each which could talk to any remote.
Fulcro enforces (by default) that writes are prioritized over reads, and that operation is in the order of submission (per remote)
But the diagram of a mutation result is JUST exactly the first diagram for normal operation. A mutations’ returning
and with-target
indicators (which you say in a remote) allows the remote to return a tree of data that is normalized via the query, with edges created by targeting. It’s all the same thing over again. The big exception is that the action
sections of mutations can also do arbitrary manipulation of the normalized db.
So the “return value” story of mutations looks exactly like the “load” and “merge component” cases from diagram 1.
And action
sections can use merge-component
to do structured data insertion via the exact same mechanism (normalize a tree of data and create join edges).
If you’re using websockets, then a push can send a tree of data, and include a “topic” that names which kind of thing it is. Then merge component can be used to do the same thing: normalize it into the db and create edges….or a push could trigger a mutation. As another side-note: UISM is nothing more than a way to “join together” a bunch of scattered mutations into a more cohesive unit that abstracts the specific UI components away from the logic. An actor in UISM is one of the UI elements as an abstraction. Thus, UISM gives you both a way to unify related logic to a task (i.e. session management) while simultaneously not having to know any specifics of the UI components themselves.
that was word salad…not sure what I meant to say…..let me reconstruct it in my head 😜 …
Yeah, I was commenting on Timofey’s diagram. Remote behavior always involves a mutation….even loads (there’s an internal-load
mutation)
Thanks a lot! I will think about it.
There’s no alternative way to talk to a remote. You issue a mutation through transact (read df/load!
…that’s what it does too), the mutation says it has local and remote operations. Everything that changes in Fulcro or talks on the network is a mutation, even internally. (load puts in and clears load markers, locally, then indicates desired remote operation, and uses a different result-action
than normal mutations…go read the mutation in the data-fetch ns 🙂 )
Yeah, I’d love better formal diagrams, so making some variant of these pretty would be very welcome