This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-03-10
Channels
- # aleph (1)
- # beginners (4)
- # biff (7)
- # calva (7)
- # cider (8)
- # clara (17)
- # clerk (19)
- # clj-kondo (30)
- # clojure (12)
- # clojure-austin (1)
- # clojure-europe (12)
- # clojure-losangeles (1)
- # clojure-norway (21)
- # clojurescript (2)
- # datalevin (1)
- # datomic (24)
- # duct (3)
- # fulcro (8)
- # hyperfiddle (8)
- # lambdaisland (4)
- # membrane (6)
- # missionary (7)
- # off-topic (55)
- # overtone (2)
- # reagent (4)
- # reitit (4)
- # releases (6)
- # shadow-cljs (80)
I need a macro to behave differently depending on the module
that is being build to emit different code to a web worker and the browser window (and also the backend clj server.)
Since I need this at compile time reader-features do not work, they always choose :clj
. On the deps.edn backend I can have different source-paths depending on build.
How can I either point to a different file with the same namespace to get different implementations or have a var, or reader conditional set in the compile time environment to emit different code? I also tried using the reader-features in a cljc file to require the macros from different namespaces but I could not get this to work. Has anyone done this?
it isn't clear what you are trying to do, but seems like reader-features is not what you are looking for. they apply to the entire build, not the module?
When I target a browser-window and a webworker should I put this into different builds? I need either a macro to expand differently in webworker and browserwindow or a require pointing two two different macros depending on whether I am in the webworker or the browserwindow.
why does the MACRO need to expand differently? doesn't seem like a macro should be aware of this at all?
maybe you want to introduce a namespace that only runs in the worker and only does what the worker needs
Fulcro mutations use fully qualified symbols as names that play nice if they live in namespaces that match their names. I just duplicated a lot of functionality from the server to the worker. So the worker and browser should do different stuff with the same data in the same namespaces. So maybe the worker and the browser need to be different builds.
this tells me absolutely nothing about what problem you are actually trying to solve
they of course can be, but macro and reader-features do NOT play together at all. they solve two entirely separate problems
so whatever it is you are trying to do, when it involves a macro then reader conditionals are not the solution
if you care to describe what you are actually trying to do I can maybe make suggestions
I think I am not communicating clearly when I talk of the (defmacro defmutation)
and when I talk about (:require [defmutation]) (defmutation my-mutation)
I have a lot of code duplication between server, worker and browser. The namespaces for fulcro mutations should be the same on server and client.
I have three different implementations of (defmacro defmutation)
for server, worker and browser.
(defmutation my-mutation ...)
combines what my data does from database asserts to server-push to ui-sorting-follow-up.
The three implementations of (defmacro defmutation)
ignore the stuff their environment does not need and add house-keeping and other things.
In deps.edn I would solve this by using three extra-paths so server, worker and browser get the three different flavors of (defmacro defmutation).
Another aproach would be to have (defmacro defmutation)
call three sepearte implementations defmutation*
depending on the build. But to do this I would need compile-time awareness of the build.
A third approach would be to have (:require #?(:client [my-client :refer [defmutation]] :worker [my-worker :refer [defmutation]]))
in the cljc file where (defmutation my-mutation ..)
lives.
I will probably have to abandon the common namespace and separate the one namespace into two, one browser only and one shared between server and worker. Between worker and server I can use different paths.
After more thinking in circles I always come back to the same thing. I want defmutation to to basically the same thing in the browser and worker. But some of the resulting actions will only be called in the worker and they pull in a database that I do not want the browser to pull in since it will never call it. So I want to delegate this decision to compile time. So either I (:require []) two different implementations of the macro defmutation, one having the performance optimization of leaving out what the environment will not use, or I would like the macro to be aware of the build so it can decide what to leave out.
This will make almost no difference at dev time but advanced build should not pull in a database it will not use.
in my head this all makes no sense, as in all my setups the stuff backend does looks drastically different than what frontend does. so I wouldn't want that in the same ns or even less single form
it might make total sense in your head, but I don't know what that looks like and I still don't know what problem you are actually trying to solve
is it that you want to emit different code for CLJ and CLJS? that is an easy answer. for workers/browser not so much.
if you are experimenting with something that moves all database actions to a worker then I recommend putting those into a separate namespace
Thank you! I have some half baked musings here https://markusgraf.net/2024-03-11-The-Big-Macro.html
and as someone who knows nothing about what this actually does, I can't tell which parts are supposed to end up on the server/worker/browser?
I would very very strongly recommend NOT doing this btw. I do not think this is a good idea. There is no value in forcing this into one form. IMHO, YMMV.
partial solution is checking (:ns &env)
in the macro, this is true-ish for CLJS but not CLJ. so easy way to separate the output
for browser/worker this is not possible since the namespace can only exists once in the build, if it is shared between the worker and browser it'll end up in the shared module. the modules don't get their own version each
FWIW you can figure this out at runtime. so could just emit (if (is-in-worker?) (do-a) (do-b))
from the macro
The differentiation between worker and browser tripped me up. The worker/server differentiation works. I just wanted it to follow the same model as the browser/worker differentiation to have consistent code.
I’m trying to get custom colors to work with shadow-css, I’ve added colors to the repl function utility that builds the css…
(defn generate-css []
(let [result
(-> @css-ref
(cb/generate '{:qrart {:include [qrart.*]}
:colors {:primary "#A83C3A"
:secondary "#375155"
:light "#F4EDD9"
:dark "#07081E"}})
(cb/write-outputs-to (io/file "public" "css")))]
(prn :CSS-GENERATED)
(doseq [mod (:outputs result)
{:keys [warning-type] :as warning} (:warnings mod)]
(prn [:CSS (name warning-type) (dissoc warning :warning-type)]))
(println)))
And then I’m trying to use in situ like [:div {:class (css :bg-primary)}]
But I’m not seeing the colors appear. The built in colors, e.g. (css :bg-red-100)
work fine. What am I missing?
UPDATE: Oh, are the colors supposed to be merged into the css-ref? I missed the thread first arrow
UPDATE: Oh, no, that’s still not it. Also tried having the colors as strings rather than keywords…. I’m missing something important I think
see this line in start
https://github.com/thheller/shadow-css/blob/e1ec8099910357e99014575a3e400652c2489fa1/src/main/shadow/css/build.cljc#L513
or just take what the start fn does, put it into your build and just set the colors before calling it
also look at the structure of the original colors, since you need to keep that structure for anything to work https://github.com/thheller/shadow-css/blob/e1ec8099910357e99014575a3e400652c2489fa1/src/main/shadow/css/colors.edn
Ah, yep, got that, thanks 🙂
So I need to set them before cb/start
otherwise the aliases won’t be generated
no. either you do not use start
at all, and just do what it does manually in your code, so you can set it before it tries to generate the aliases
`(defn start
([]
(start (init)))
([build-state]
(-> build-state
(load-preflight-from-classpath)
(load-default-aliases-from-classpath)
(load-colors-from-classpath)
(load-indexes-from-classpath)
(generate-color-aliases)
(generate-spacing-aliases))))`
Is start - if I call it with {:colors …
won’t it generate the aliases?
(defn css-release [& args]
(let [build-state
(-> (cb/start)
(cb/index-path (io/file "src" "main") {})
(cb/generate
'{:ui
{:include
[*]}})
(cb/write-outputs-to (io/file "public" "css")))]
(doseq [mod (:outputs build-state)
{:keys [warning-type] :as warning} (:warnings mod)]
(prn [:CSS (name warning-type) (dissoc warning :warning-type)]))))
> note that I switched my projects all away from doing this incremental stuff oh, how come
(defn css-release [& args]
(let [build-state
(-> (cb/init)
(cb/load-preflight-from-classpath)
(cb/load-default-aliases-from-classpath)
(cb/load-colors-from-classpath)
(update :colors merge {"primary" {"" "red"}})
(cb/load-indexes-from-classpath)
(cb/generate-color-aliases)
(cb/generate-spacing-aliases)
(cb/index-path (io/file "src" "main") {})
(cb/generate
'{:ui
{:include
[*]}})
(cb/write-outputs-to (io/file "public" "css")))]
(doseq [mod (:outputs build-state)
{:keys [warning-type] :as warning} (:warnings mod)]
(prn [:CSS (name warning-type) (dissoc warning :warning-type)]))))
Oh nice, thanks!
I just switched to the code you linked - I noticed that you have server/start and server/stop as function calls rather than metadata {:shadow/requires-server true} like in the shadow-css readme. What’s the difference there? I’ve noticed that if I don’t include {:shadow/requires-server true} the call to start exits
my workflow is running npx shadow-cljs server
in a terminal, then connecting a REPL and hitting my keybind which executes (require 'repl) (repl/go)
but yes, if you run via npx shadow-cljs clj-run repl/start
then you'd need :shadow/requires-server
ahah cool, I’ll try your workflow
same end result I guess, for me its just habit. clj-run
is actually better if you ask me, just too lazy to switch my setups
It's possible to https://shadow-cljs.github.io/docs/UsersGuide.html#NameHashing and while https://shadow-cljs.github.io/docs/UsersGuide.html#js-provider-external and have hash on libs and the main js file?
Maybe my question is more like is there any way to configure this to work without any custom hooks, but reading the docs I think it's not possible.
Would be cool to module-hash-names
has and extra config where you could set a list of custom js files, even css and shadow generate an copy with the hash name and declare then on the manifest.edn
I don't quite understand the question. :module-hash-names
works for the shadow-cljs output yes. besides that shadow-cljs has no knowledge of what happens to the :external-index
it generated, and as such doesn't care whether you assign a hashed name to it or not
I yeah sorry, I was wondering if was possible to add custom files on the hash name task, probably I will write a custom hook to do this.
seems easier to me if you just create a function that reads the manifest.edn
, adds whatever you want and writes a new file? independent, as part of whatever builds your external-index?
yeah I will probably I will go into this direction
Btw, not totally related, my friend was doing some experiments with esbuild
to tree shake the release using :external-index
and got good reduction in the bundle size, thanks for the help in the other thread
you can add the --metafile=something.json
to the esbuild and then upload to the site