This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-11-23
Channels
- # beginners (81)
- # boot (1)
- # cider (1)
- # cljs-dev (15)
- # cljsrn (1)
- # clojure (27)
- # clojure-europe (9)
- # clojure-hamburg (2)
- # clojure-italy (6)
- # clojure-nl (6)
- # clojure-spec (10)
- # clojure-uk (33)
- # clojurescript (9)
- # clojurex (5)
- # cursive (14)
- # datomic (21)
- # devcards (2)
- # duct (72)
- # figwheel (1)
- # fulcro (6)
- # kaocha (3)
- # leiningen (5)
- # nrepl (10)
- # off-topic (65)
- # parinfer (12)
- # re-frame (68)
- # reagent (1)
- # reitit (14)
- # shadow-cljs (65)
- # spacemacs (6)
- # sql (4)
- # tools-deps (2)
- # yada (1)
I don't understand how to properly separate dev config from prod config in Duct 0.11. I'm trying to introduce Duct into an existing (minimal) project sort of piece by piece. Is there an example project somewhere I could look at? For example, I'd like to run :duct.compiler/sass
only in dev.
I have read https://github.com/duct-framework/duct/blob/master/UPGRADING.md and I've managed to set up things so that when I do (duct/read-config "config.edn")
, it includes the contents of my dev.edn
under the duct.profile/dev
key, but none of that is being executed.
Well, this is probably one problem, at least:
Syntax error (ClassCastException) compiling at (dev.clj:35:3).
class duct.logger.timbre.TimbreLogger cannot be cast to class clojure.lang.IFn (duct.logger.timbre.TimbreLogger is in unnamed module of loader clojure.lang.DynamicClassLoader @36f39f6a; clojure.lang.IFn is in unnamed module of loader 'app')
clojure.core/eval core.clj: 3214
...
shadow.user$eval29750.invoke : 1
shadow.user$eval29750.invokeStatic : 1
...
dev/eval29754 dev.clj: 35
integrant.repl/go repl.clj: 54
integrant.repl/prep repl.clj: 16
...
clojure.core/alter-var-root core.clj: 5505
clojure.core/alter-var-root core.clj: 5510
...
integrant.repl/prep/fn repl.clj: 16
dev/eval29741/fn dev.clj: 28
duct.core/prep-config core.clj: 193
duct.core/build-config core.clj: 182
duct.core/fold-modules core.clj: 145
integrant.core/fold core.cljc: 282
clojure.core/reduce core.clj: 6827
...
integrant.core/fold/fn core.cljc: 282
duct.core/fold-modules/fn core.clj: 145
The same error is actually reproducible if you just add this into the config.edn
of a clean Duct Leiningen template:
:duct.logger/timbre {:level :info
:appenders {:duct.logger.timbre/println #ig/ref :duct.logger.timbre/println}}
:duct.logger.timbre/println {}
@U0BKWMG5B Do you want an issue for this, too? I guess it belongs in duct-framework/logger.timbre
?
I think the same error occurs whenever ig/init-key
returns something that satisfy ifn?
.
Have you moved all of your non-module keys into profiles? It sounds like you haven't done that step.
Anything beginning with :duct.module
or :duct.profile
is a module key.
In 0.10 and below, modules were mixed with non-module keys. In 0.11, there separation is explicit.
Yes, that's right.
Assuming you want to change the default :duct.module/logging
settings.
It depends if you want the configuration in all profiles, in which case put it in base, or just in production, in which case put it in prod.
Well, I have a config.edn
like this:
{:duct.profile/base {:duct.core/project-ns
:duct.logger/timbre {:set-root-config? true
:level :info
:appenders {:duct.logger.timbre/println #ig/ref :duct.logger.timbre/println}}
:duct.logger.timbre/println {}}
:duct.profile/dev #duct/include "dev"
:duct.profile/local #duct/include "local"
:duct.profile/prod {}
:duct.module/logging {}}
And then I do (repl/set-prep! #(duct/prep-config (read-config) [:duct.profile/dev]))
and (go)
and I get Assert failed: (map? config)
from ig/prep
.
Does the assert have a stacktrace associated with it?
Assert failed: (map? config)
Syntax error compiling at (/foobar/dev/src/dev.clj:45:3).
at clojure.lang.Compiler.load(Compiler.java:7647)
at shadow.user$eval30043.invokeStatic(Unknown Source)
at shadow.user$eval30043.invoke(Unknown Source)
at clojure.lang.Compiler.eval(Compiler.java:7176)
at clojure.lang.Compiler.eval(Compiler.java:7131)
at clojure.core$eval.invokeStatic(core.clj:3214)
at clojure.core$eval.invoke(core.clj:3210)
at clojure.main$repl$read_eval_print__9068$fn__9071.invoke(main.clj:414)
at clojure.main$repl$read_eval_print__9068.invoke(main.clj:414)
at clojure.main$repl$fn__9077.invoke(main.clj:435)
at clojure.main$repl.invokeStatic(main.clj:435)
at clojure.main$repl.doInvoke(main.clj:345)
at clojure.lang.RestFn.invoke(RestFn.java:1523)
at nrepl.middleware.interruptible_eval$evaluate$fn__20103.invoke(interruptible_eval.clj:87)
at clojure.lang.AFn.applyToHelper(AFn.java:152)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.core$apply.invokeStatic(core.clj:665)
at clojure.core$with_bindings_STAR_.invokeStatic(core.clj:1973)
at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1973)
at clojure.lang.RestFn.invoke(RestFn.java:425)
at nrepl.middleware.interruptible_eval$evaluate.invokeStatic(interruptible_eval.clj:85)
at nrepl.middleware.interruptible_eval$evaluate.invoke(interruptible_eval.clj:54)
at nrepl.middleware.interruptible_eval$interruptible_eval$fn__20146$fn__20149.invoke(interruptible_eval.clj:218)
at nrepl.middleware.interruptible_eval$run_next$fn__20141.invoke(interruptible_eval.clj:186)
at clojure.lang.AFn.run(AFn.java:22)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.AssertionError: Assert failed: (map? config)
at integrant.core$prep.invokeStatic(core.cljc:412)
at integrant.core$prep.invoke(core.cljc:412)
at integrant.core$prep.invokeStatic(core.cljc:417)
at integrant.core$prep.invoke(core.cljc:412)
at duct.core$prep_config.invokeStatic(core.clj:195)
at duct.core$prep_config.invoke(core.clj:184)
at dev$eval30027$fn__30028.invoke(dev.clj:41)
at integrant.repl$prep$fn__29833.invoke(repl.clj:16)
at clojure.lang.AFn.applyToHelper(AFn.java:154)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.lang.Var.alterRoot(Var.java:308)
at clojure.core$alter_var_root.invokeStatic(core.clj:5510)
at clojure.core$alter_var_root.doInvoke(core.clj:5505)
at clojure.lang.RestFn.invoke(RestFn.java:425)
at integrant.repl$prep.invokeStatic(repl.clj:16)
at integrant.repl$prep.invoke(repl.clj:14)
at integrant.repl$go.invokeStatic(repl.clj:54)
at integrant.repl$go.invoke(repl.clj:53)
at dev$eval30047.invokeStatic(dev.clj:45)
at dev$eval30047.invoke(dev.clj:45)
at clojure.lang.Compiler.eval(Compiler.java:7176)
at clojure.lang.Compiler.load(Compiler.java:7635)
... 27 more
What does your dev.edn
file look like?
{:shadow.cljs/watch {:id :app}
:duct.compiler/sass {:source-paths ["resources/sass"]
:include-paths ["node_modules"]
:output-path "resources/public/css"}}
No, because it's included via #duct/include
The resource is literally inserted verbatim where the reader tag is.
It must be something odd in my project because if I copy-paste those same config files into a clean Leiningen Duct template, I don't get that error.
Okay, weird, I'm not seeing anything obviously wrong here. Would you mind running a couple of commands for me?
FWIW, this is not a Leiningen project I'm working on. It's a deps.edn
project. Not sure whether it matters.
(-> (read-config) (doto ig/load-namespaces) (build-config [:duct.profile/dev]))
Oh, another thing to try is to shut down your REPL, clean your target directory, and restart your REPL.
Since multimethods can be missed by reloads.
Does the same thing occur when you restart your repl?
Are the dependencies the same as the ones in the template?
:dependencies [[org.clojure/clojure "1.10.0-beta4"]
[duct/core "0.7.0-beta2"]
[duct/module.logging "0.4.0-beta1"]]
No problem 🙂
As a bonus, I now understand much better how the whole thing works. The only thing I'm still not 100% clear on is the module/non-module distinction. For example, this page https://github.com/duct-framework/duct/wiki/Modules lists both logger.timbre and module.logging as modules, but logger.timbre actually isn't…?
Oh, that page wasn't added by me 🙂
I'll make a note to fix that page before release.
With regard to modules/non-modules, anything beginning with :duct.module
or :duct.profile
is a module. In 0.11, a module is a function that transforms a configuration, so config -> config
.
In 0.11, a configuration of modules is initiated into transformation functions, and then applied in dependency order to an empty map. This produces a new configuration, which is then initiated.
You can think of Duct's configuration as a "higher-order configuration", in the same way that we have higher-order functions.
Duct's config initiates into an Integrant config, which is then initiated into a system.
Right, so modules transform configurations and non-modules are things that contain stateful resources etc.
Right.
The idea is that you can write a module that adds a whole bunch of configuration so you can abstract common patterns of config.
In the same way that higher-order functions allow abstraction of code patterns, like map, filter, reduce, etc.
Might be useful to add at least one non-module key in the example here https://github.com/duct-framework/duct/blob/master/UPGRADING.md to make things clearer.
Where it says ;; ... more non-module keys
, maybe have e.g. :duct.logger/timbre
to make it clear you have to put it there.
Those are good ideas.