This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
I've got a very basic macro that compiles markdown into a quiescent component. What I'd like to do is retrigger a boot compile every time I change the markdown file. I've added my "markdown" folder to sources in build.boot and saving a .md file does trigger (watch) but doesn't change any cljs so the macro doesnt get run.
@lukemorton: Nothing Boot can do about that, Cljs compiler decides itself when to recompile cljs
Instead you could have task which watches .md files and compiles them into cljs files
@juhoteperi: @lukemorton or you could write a task that "touches" the relevant cljs file
@lukemorton: @juhoteperi: it could also create a clj file with multimethod dispatch that the macro will use to emit cljs
I'm assuming (apply some-task {:a true :b false})
doesn't work for some reason... i'll try that
yeah i can't get apply
to work this way:
clojure.lang.ExceptionInfo: Assert failed: cli options must be unique
(apply distinct? opts)
pandeiro: how about just putting (task-options! some-task {:a true :b false})
before the task?
I don’t see why apply would not work but I guess this would at least get the job done
@martinklepsch: ok, hadn't thought of that... but would that task-options! need to be manually reset after the task?
it’s side effectful so if you want to go the the previous state you have to do that yourself
ok, is there someway i can store the previous state for executing the reset! afterwards?
@martinklepsch: thanks for the idea but if (apply ...)
should work maybe I need to investigate that better; much less complex solution
@pandeiro: apparently task options are stored on the task var: https://github.com/boot-clj/boot/blob/8b6ebea81e06d4e76e9e6ac23896c21e1e5b68ad/boot/core/src/boot/core.clj#L805
@pandeiro: why do you need this kind of behaviour? (just curious)
e.g., I don't want to have to write two compile-assets-dev
and compile-assets-prod
tasks
like we need to be able to just go in there and change things without thinking about abstractions
hi all - is there an example for boot + immutant + cljs + hoplon? If not, no worries
actually, just an example with immutant and cljs would be great - I can’t see how to replace the standard jetty based (serve) task with immutant...
@colin.yates: if you figure it out and it is something that could be added to boot-http (a la :httpkit true), i'm happy to include it there
me neither - I will have a look but it won’t be for a while unfortunately (time pressure, lein works etc. you know - the usual excuses :-)).
@colin.yates: yep of course
@micha: so the difference between your example and what i'm thinking is that in yours, we need to know in advance which options (e.g., :optimizations
the caller of the task may want to set/override
yeah i thought about doing it similarly but i would prefer something more generic if possible
just to clarify -- (apply some-task some-task-opts-map)
is not supposed to work, right?
yeah the thing with environment is that the only way i know how to do it involves writing to a special file that gets picked up in the fileset
if i set db via some env
mechanism that writes to a file, won't the server also pick that up?
so in leiningen i used the special :test
profile + lein-env to ensure that the tests ran against apptest
db instead of regular app
db
meaning i couldn't run tests safely from the repl... but i could do lein test myapp.service.tests
and it would use the right test db
so it would have to be something special like (or (env :test-db-host) (env :db-host)) ...
i noticed that my namespaces are loaded separately for every task in the pipeline -- that's the expected behavior, right?
and if the task executes in a pod, that loaded ns is separate from other instances of the same loaded ns
cool... cool... so if i run tests in a pod, when the db.clj
gets required, it sees the test db env vars and makes a separate connection based on those -- is my logic sound?
(let [result (-> (session app) (get :some-endpoint))]
(is (= (:status result) 200)))
maybe one of the reasons i want it to work this way is that i'm using yesql and using (defqueries "queries.sql" {:connection db-conn})
so I don't need to pass the db conn into every query function
it ends up meaning the API can just do (db/get-foo-by-id {:id foo-id})
without having to specify the connection
Ugh I wonder why yesql moved backwards and started using global state
in effect i would be running the tests in a pod so they'd hit a different version of the API right?
@juhoteperi: is this a terrible anti-pattern i'm embracing?
All sane libraries move from global state to passing connection as parameter
So you can manage the state e.g. with Component
yeah like i said above, this is like the exact problem component exists for, i think
Though I don't see this {:connection ...} example on yesql readme anymore?
Oh right, they still haven't released that
micha: interesting solution... i'm actually using peridot so it's not really happening over HTTP
@micha Yeah I think there's some overlap for sure... doing mostly frontend stuff, i don't see component's usefulness for most of my work
i separate out all the orthogonal concerns of configuring the application into env vars
Regardless of whether one uses Component, I think it's best not force global state in libraries and let the apps decide how they manage it
@micha: yeah i think that is essentially what i'd be doing by loading the app (but not starting the server, to avoid port conflict) in a separate pod, right?
i think pod + with-redefs
may give me all i need, really... it's fairly uglegant, even
Can I see the underlying directory name of things returned from boot.core/input-dirs ?
@lukemorton: sure, those contain that info
ah, I printed out the dir and couldn't see the directory name I was looking for
this is so that you can add any file to the fileset you like, or remove files from the fileset etc
yeah I just wanted to know if files inside the source directory "markdown" had changed
I've ended up matching by filename instead
(b/deftask markdown
"Touch markdown.clj if .md files change"
[]
(let [prev (atom nil)]
(fn middleware [next-handler]
(fn handler [fileset]
(let [changed (if (nil? @prev) fileset (b/fileset-diff @prev fileset))
changed-paths (map #(:path %) (b/input-files changed))
md-paths (filter #(.endsWith % ".md") changed-paths)]
(println "Markdown changed:" md-paths)
(reset! prev fileset)
(next-handler fileset))))))
if you have files that are used for a new purpose, make it official, give them their own extension
Just to clarify, is the task I've written the right way to go about detecting if any markdown files have changed?
oh cool
handy
seems like this idiom could be wrapped up in a helper function, not too hard to implement but maybe fairly common use case?
ah yes I've read about with-pre-wrap
thanks for this
ah I see, yeah thanks for the insight
My solution to detecting markdown file changed and touching my markdown macro file to trigger live reload: https://github.com/drpheltright/big-time.cljs/blob/master/src/big_time/tasks.clj
I know you said something about multi methods earlier @micha but I don't understand them enough to run with that solution. If you have any resources that could help me see what you mean that would be good
@lukemorton: great name, i love it
@lukemorton: are you interested in pull requests?
yeah sure! whether I merge them or not... my discretion 😛
if boot pods are just normal jvm, then can't i manage elasticsearch inside a boot pod? that would make things so much easier
do you happen to know of a good resource that explains all the tradeoffs involved with the various web server configurations? i.e. interceptors, thread pools, http-kit, jetty etc
want to be pretty confident i can provision it corerctly so it won't fall over under load
@micha the pedestal docs are nice for interceptors vs pipelines https://github.com/pedestal/pedestal/blob/master/guides/documentation/service-interceptors.md
the thing i really need to understand is how the different architectures behave under sustained load