Once again trying to navigate the GUIDE.rst with 0.11 and when adding the Static Route, dev> (reset) :reloading (todo.main dev user) :duct.server.http.jetty/stopping-server Execution error (IllegalArgumentException) at integrant.core/resume$fn (core.cljc:450). No method in multimethod 'init-key' for dispatch value: :body
@colliderwriter Could you send me your configuration? My work on updating the guide has been a little sidetracked.
@weavejester Here's what I have: {:duct.profile/base {:duct.core/project-ns todo :duct.router/ataraxy {:routes {[:get "/"] [:index]} :handlers {:index :todo.handler/index} }} :duct.profile/dev #duct/include "dev" :duct.profile/local #duct/include "local" :duct.profile/prod {} :duct.module/logging {} :duct.module.web/api {} :duct.module/sql {} [:duct.handler.static/ok :todo.handler/index] {:body {:entries "/entries"}} }
You should place the handler inside the base profile.
In 0.11, the configuration contains only modules or profiles (which are a type of module).
Mixing modules and normal keys generated too many issues, whereas separating them makes the setup process simpler.
Got it, edited, works. Sorry for my confusion.
No problem - it's my own fault. The guide really needs to be updated.
I think I've learned the lesson at hand though
So thanks
If I can feel my way through the rest of the guide, I promise to submit a PR for an updated version
If you have any more questions, just send them my way.
@weavejester I'm afraid I do have another. WHen I add the route inside the base profile, I can (reset) without any errors, but i still get the 404 with the "not-found" body as if I had not edited it at all.
Oh, I think you're missing an #ig/ref
.
So:
:duct.router/ataraxy
{:routes {[:get "/"] [:index]}
:handlers {:index #ig/ref :todo.handler/index}}
However, you can also write:
:duct.router/ataraxy
{:routes {[:get "/"] [:todo.handler/index]}}
The Ataraxy router has a ig/prep
stage where it fills in the handlers if they're not specified.
The Ataraxy module still exists as well, so you could also write:
:duct.module/ataraxy
{[:get "/"] [:index]}
Ah I wasn't clear if that was still legal
Which is more concise, but lots of people thought it was too confusing
So when writing the router, I decided that it's better to be explicit.
I have limped on to the next step...
I'm going to try and find some time tomorrow to revise the guide.
I made it over a couple more hurdles but my best guess when adding the query route was
:duct.router/ataraxy
{:routes {[:get "/"] [:index]
[:get "/entries"] [:entries/list]}
:handlers {:index #ig/ref :todo.handler/index
:entries/list #ig/ref :todo.handler.entries/list}}
which fails at (reset) with
`No method in multimethod 'init-key' for dispatch value: :integrant.composite/duct.handler.sql.query+todo.handler.entries.list_29426
That's essentially saying "I can't find any multimethod for any of the keys in the composite key"
What does your list entries key look like, and do you have the required dependencies?
List entries key:
[:duct.handler.sql/query :todo.handler.entries/list]
{:sql ["SELECT * FROM entries"]}
Which is placed inside the project-ns map
Do you have the right dependency?
duct/handler.sql
I think.
So in your dependencies, @colliderwriter, you should have [duct/handler.sql "0.3.1"]
Right, i added it. Sorry.
You might also need to add in the :db
key manually, because I haven't updated the duct/handler.sql
library yet either.
So:
[:duct.handler.sql/query :todo.handler.entries/list]
{:db #ig/ref :duct.database/sql
:sql ["SELECT * FROM entries"]}
Yes, I got
user> (dev)
Syntax error compiling at (merge.clj:102:11).
No such var: ig/reflike?
It sounds like you don't have Integrant 0.7.0
Haha i just got what was in the template
So a dependency (maybe handler.sql because it's old) might be overriding it.
If you add in Integrant 0.7.0 it should work.
But if you run lein deps :tree
it should tell you what dependency is overriding Integrant and replacing it with an older version.
Leiningen always chooses the "nearest" dependency to your project file, but that's not always the most up to date.
[integrant "0.7.0"]
I think is the dependency you want to add.
Real life is intruding. Can we finish this tomorrw?
Sure.
Thanks again
I might have the guide updated by then.
If you don't I promise to do it myself
Thanks 🙂
I've just update my fullstack app to latest duct from v0.10. The only problem I have is this custom module no longer works. It tries to tweak figwheel config a little bit
https://github.com/walkable-server/realworld-fulcro/blob/master/dev/src/dev.clj#L22
why is that?
@myguidingstar That looks okay... Could you show me an example of use?
@weavejester I just use it with {} params here https://github.com/walkable-server/realworld-fulcro/blob/master/dev/resources/dev.edn#L1
Ah, I see. You're putting it in the dev profile.
Give me a minute or two to think about the best way forward for this.
Okay, so in Duct 0.11 I separated out Duct modules from Integrant's normal component keys. Mixing the two caused too many issues, even if it was convenient.
This does mean that you can't place modules inside profiles, since profiles are a type of module.
However, what you can do is make the module more generic, and add in keys that the module uses.
So for example:
(defmethod ig/init-key :fulcro.module/devcards [_ {build-id :build-id :or {build-id 0}}]
(fn [config]
(-> config
(update-in [:duct.server/figwheel :builds build-id :build-options :preloads]
conj (ig/ref ::preloads)
(assoc-in [:duct.server/figwheel :builds build-id :build-options :devcards]
(ig/ref ::devcards)))))
There's probably a more elegant way of arranging that, but hopefully you get the idea?
I'm also going to try and make the cljs stuff more easily configurable in future as well, so this should be less of an issue.
what is that (ig/ref ::devcards)
for?
It references a configuration key called ::devcards
Let me check the module.cljs to see if there's a more elegant way of doing this.
so the separation of Duct modules from Integrant's normal components means only modules can "modify" other modules?
Not quite; modules can modify the configuration, but they can't modify other modules.
Profiles are just a type of module that merges its value into the configuration.
Duct now separates out each stage, whereas before they were all mixed together.
So first of all there's a read stage, which also handles reading included files.
This produces a configuration of modules.
The modules are initiated, composed, and then this produces an Integrant configuration.
This Integrant configuration is initiated to produce the system.
You can think of the Duct module configuration as a "higher level" configuration. It's a configuration that produces a configuration.
Duct config -> Integrant config -> running system
So back to your problem. A better solution might be to write:
(require '[duct.core :as duct])
(defmethod ig/init-key :fulcro.module/cljs-build-options [_ _]
(fn [config]
(update-in config
[:duct.server/figwheel :builds build-id :build-options]
duct/merge-configs
(:fulcro/cljs-build-options config))))
And then in your dev.edn
:
{:fulcro/cljs-build-options
{:preloads [fulcro.inspect.preload]
:devcards false}}
and I'll need {:fulcro.module/cljs-build-options {}}
to initiate it config.edn?
Right
is there a better verb to use in place the above "initiate it"?
This should be a lot easier. I'm looking at the code for module.cljs and I think I can modify it so that changes like these won't need a module to alter the code.
Could you possibly open a issue on module.cljs for something like "It should be easier to modify the build options"?
sure
thank you so much for Duct and everything. It's a smooth dev experience 🙂
No problem. The 0.11 changes could be a lot smoother, though! All I can say about that is that I'll get through the backlog of stuff to do eventually! 🙂
is (derive ::something :duct/module)
required anymore?
No, I don't believe so, although it's not a bad idea to put that in your duct_hierarchy.edn
for clarity.
ok
I’m excited to hear that you are thinking about this friction with module.cljs. I’ve been meaning to write to you about this issue. There’s hundreds of options that can be passed to the ClojureScript compiler and passing them through to module.cljs has been somewhat awkward of late. Especially once one starts adding foreign JS libs and externs to the system. Somewhat related: You mentioned here recently that you were looking at shadow-cljs with reference to recent figwheel compatibility issues. I got frustrated with the figwheel situation and also had problems integrating third party JS libs which used different JS module systems, so switched to shadow-cljs. It was a painless experience and everything worked first time! shadow-cljs is really that good. Nice and fast too 🙂
I should be doing some work with Duct and cljs within the next month or so, so it's in my best interests to take another look 🙂
The guide (https://github.com/duct-framework/docs/blob/master/GUIDE.rst) has now been updated for Duct 0.11.
I’d like to extend duct.core.env/coerce
to add a 'Keyword
coercion. I’ve defined a new`defmethod` but the method doesn’t seem to be registered when config is read. I get No method in multimethod 'coerce' for dispatch value: 'Keyword
. I’ve registered the new method in my main.clj
where the config is loaded.
Do I need to override the #duct/env
reader with a version that has the registered dispatch?
Facepalm. I updated main.clj
but then tested in the REPL. I helps to modify the right runtime! Requiring the defmethod
works just fine.