Fork me on GitHub

ok, so the module is compiling and loading, but now it seems that the set-query! is not working, or rather that the routing target component is not getting the query update by the time it renders, since it still has the initial temporary [{:loaded component [*]}] query when the attempt is made to load its new query's component to render it: (some-> this prim/get-query prim/query->ast1 ,,,) call. However the new query IS visible in the router's list of queries and components inside of Fulcro Inspect.


Hey @thosmos. I have not personally tried it with code splitting…so you’re the guinea pig. Are you saying you’re nesting a router in the dynamic loaded part? Or just a target?


At the moment I just have one router, the root router, and it and all of its route targets are in the main module. Each route target has a simple query of [{:module-comp [*]}] When a route attempt is made to, in this case the "about" module, the route target's :will-enter calls dr/route-deferred. In the code module there's a definition for a regular defsc module

(defsc AboutComp [this {:keys [about/hello]}]
  {:query [:about/hello]}
and the module loading code calls set-query like so:
(prim/set-query! reconciler class {:query [{:about-comp (prim/get-query AboutComp)}]})
But that query is not finding its way in AboutPage's (the route target) query by the time its render is called, which is where the attempt is made to load the AboutComp's factory and state.


So, you cannot directly use AboutPage or code splitting just won’t happen there.


The loaded module should be written to call a function that sets the target ready…e.g. at the bottom of the ns where you would tell the loader that you’ve loaded. That way the main program doesn’t have to know anything about the code in the module.


or do you no longer need to do that last step…don’t remember


(tell the loader you loaded)…either way, referring to the AboutPage in your main app will prevent code splitting


now, if the load immediately calls the then (which it could if nothing was actually split), then it might run on the same execution that the will-enter is running on, which would be a nested transact!, which is not assured to work. You could try using ptransact! instead (which is safe to call from within transact context). Either way you’re going to need to fix it so your parent code doesn’t mention anything in the module you wish to split.


hmm, not sure I understand, I have two components, AboutPage (the route target) and AboutComp (which is defined in the module)


AboutPage is the one that calls dr/route-deferred and load-module


Then why are you setting :class to AboutPage???


so that when the module loads it know which component's query to set-query on?


the goal is to set-query on the route-target's query, correct?


Yes, as (get-query AboutComp)


but you set :class to AboutPage


and if you structure you code that way, splitting won’t work


I'm getting rid of my second approach as that might be confusing


but either way my guess is a nested transact kind of problem


Yes I do get-query AboutComp in the module code and then use the value of :class that was set by the main module to set query on AboutPage to use AboutComp's query?


I thought I followed the example to a T, but maybe I'm missing something


I'll work up a minimal example


So, I don’t remember what I wrote, but it was armchair code


ok, got it


the module that is being loaded is where the query gets set from


not the module that is already loaded


yes that is what I'm doing (or rather my first attempt was), but I didn't use the state map in the get-query so I'll try that first before working up an example


my second attempt was to pass a reference to the loaded class back to the first component and try to set-query from there.


I tried adding the state-map to the get-query, but that didn't resolve the issue. I put the relevant pieces in a gist here:

tony.kay16:02:55 You might need a follow-on read here to tell Fulcro what should refresh


(some-> this (prim/get-query (prim/component->state-map this)) prim/query->ast1 :component prim/factory)


I don’t think Fulcro sets the dyn var during render, it’s more during it’s use of get-query…I could be wrong here, but it is suspect


progress! I'm now seeing the module component when I initially load the page on another route and switch to it, but if the initial load is on /about, then it's only loading it for a moment, long enough to see it, then it disappears and shows the pending and error routes.


what is the dyn var you're referring to in your last message?




get-query uses that to look for state if you don’t pass it


the call to get-query needs the state map


(get-query this state-map)…dynamic queries are resolved via the state map. There is a dynamic var that supplies that during render, but outside of the render loop it has to be manually supplied (or the dynamic var set).




Open an issue if that’s in the dr namespace


(and thanks for trying it out 🙂 )


Is there an idiomatic way to use react’s renderToStaticMarkup?


Or rather, on the server, some call analogous to renderToStaticMarkup


If you run server-side in node, then all js libs are available…In Fulcro, we have to have clj code that can “interpret” the UI…so, render-to-str is actually a CLJ implementation of React’s server render stuff.


that’s a great idea! running it on node would be perfect for my use case


It looks like fulcro/pathom makes heavy use of namespaced keywords in queries (“input” “output”). It makes sense to me now, but I am curious: this looks like it would fit well with datomic (which I don’t use). Do people do things differently with ex. SQL / other databases? Do they add an extra step in the resolver (like prefixing elements with the table name)?


@nha in my current project I am using PostgreSQL as a database, and yes my resolvers do have a step to prefix elements. Perhaps I could abstract it away but for now I have kept it very explicit, e.g.:

(defresolver course-resolver
  [env input]
  {::pc/input #{:course/id}
   ::pc/output [:course/name]}
  (let [course (Course (:course/id input))]
    {:course/name (:name course)}))


ok, I was thinking about doing something similar - thanks for the data point 🙂


No problem 🙂 Also, I have found it useful to only provide IDs for references. For example:

(defresolver course-resolver
  [env input]
  {::pc/input #{:course/id}
   ::pc/output [:course/name {:course/task-sets [:task-set/id]}]}
  (let [course (Course (:course/id input))
        task-sets (map (fn [{:keys [id]}] {:task-set/id id})
                       (db/select TaskSet :course_id (:id course)))]
    {:course/name (:name course)
     :course/task-sets task-sets}))


Then a “task set” resolver can pick up from there and load more data


performance-wise it’s not ideal as it suffers from the N+1 queries problem, but conceptually it’s nice imho


you can optimise performance later


You could also look into something like (I haven’t used it yet)


Interesting, I am not sure yet how I am going to model my queries so thanks for that 🙂