This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
Is there a way to check if some top-level code is being executed during a hot reload? I'd like to add some assertions that should only be triggered on the very first load or in a production build, but not on hot reload during development.
:init-fn
exists so that there are never any side-effects during loading of a namespace. if you still have them you need to build something yourself to prevent that loading, or you something like defonce
Yeah, I'm using defonce
. That's for global addEventListener
which I want to be overriden during development without any issues and with a warning/error in production or when it happens in dev but during initial load.
my tip is adding this in :init-fn
via (js/document.addEventListener "whatever" (fn [e] (the-actual-event-handler e))
that can be changed and hot-reloaded just fine with no need to ever add the event listener again
note the extra wrapper fn to ensure this works, just (js/document.addEventListener "whatever" the-actual-event-handler)
doesnt work
Mm, hmm, right. Will probably go that route, thanks.
Re-frame has a similar problem of having to warn people about overriding events. But they decided to just check for DEBUG
and never throw.
And given that some side-effecting things have to be top-level, is there a good pattern to make sure that some code gets executed before everything else? Currently, the main ns just requires the ns with such code as the very first one. But that's kinda brittle.
Maybe compiling that code as a separate module and mentioning it first in index.html
? :) Quite a hassle though, probably not worth it.
(assuming the order can be maintained and that ns not requiring others to move them in front)
That actually sounds like the best approach so far.
And :init-fn
can also be specified then, right?
Something like
:modules {:main {:entries [app.instrumentation app.core]
:init-fn app.core/init}}
Hello,
I wanted to upgrade a dependency of a webapp from "materialize-css" to "@materializecss/materialize". In order to avoid going through all the code and replace the require statements I added a resolve js-options to keep the same name (and also switch to a cdn instead of installing it locally).
"materialize-css" {:target :global :global "@materializecss/materialize"}
However I end up with an error during the compilation. Any idea on what I a missing?
Closure compilation failed with 1 errors
--- global$module$materialize_css.js:2
Parse error. Character '@' (U+0040) is not a valid identifier start char
:global
resolves to a global variable name, you want :require
there to basically redirect those requires
otherwise it'll literally emit @materializecss/materialize
as a JS variable name, which is not valid and why you are getting that error
As I said I wanted to see if I can use the cdn version too... But I guess I am not familiar enough with the javascript ecosystem to make it work. Indeed redirecting "require" works too if I use the non package. Thank you very much for your quick answer
Has anyone gotten https://github.com/cjohansen/portfolio up and running with shadow-cljs and reagent? I have managed to connect enough up to get the portfolio UI to show me my button docs, but the button itself is not visible and the css files are not being found (404 in the console logs), despite setting them in the portfolio initial config path vector. Folder structure: portfolio-resources/public/index.html | js/compiled resources/public/css | index.html | js/compiled src/app/core src/portfolio/core I use shadow-cljs with deps.edn for deps and :portfolio alias.
I think I found the problem. Initially I had this in my shadow-cljs.edn file.
:dev-http {9800 ["public" "classpath:public"]}
I then changed it to this, but this just made shadow-cljs serve the index.html in resources/public
:dev-http {9800 ["resources/public" "classpath:public"]}
I then removed index.html from resources/public and everything worked.
But this is a problem. Our production index.html is in resources/public. I can't remove it just to have portfolio work. Portfolio needs to be able to see my css files etc in resources/public but without serving the index.html in the folder.
Update:
I added each folder individually like this and now it works.
:dev-http {9800 ["resources/public/css" "resources/public/fonts"
"resources/public/3D" "resources/public/assets"
"resources/public/images" "classpath:public"]}
Thank you for your time.adding all those paths as "roots" will mean that everything in those folders is accessible at the root of the server
:dev-http {9800 ["public" "classpath:public"]}
seems fine to me? you could also do :dev-http {9800 ["public" "resources/public" "classpath:public"]}
it tries left to right until the first match, so that will take public/index.html
over resources/public/index.html
, but still serve the images from resources/public
and so on
You are right. I had to shift everything around to make this work with this. Is there any way to serve "resources/public" but not index.html that is in the folder? Like exlude that file? I thought maybe I could exclude the index.html by making shadow-cljs look for a index.html with a name that doesn't exist. I found this in the docs, but don't know how to use it properly.
:push-state/index
(optional) The file to serve. Defaults to index.html.
there is no need to use :dev-http
at all, it is entirely optional. if you want your http server to do something specific you should create your own
I want my index.html that is in portfolio-resources/public to access everything in resources/public excluding html and js files. Those don't matter. But I think the easiest thing for me to do is actually to just create symlink from resources/public folders into portfolio-resources/public. That way it will all be sorted and I don't need to duplicate folders and files. Update: Creating symlinks works great. Now I just need
:dev-http {9800 ["classpath:public"]}
if you use portfolio-resources/public
as the first entry it will use that index.html
over the later ones
I tried
:dev-http {9800 ["resources/public" "classpath:public" "portfolio-resources/public"]}
But it still loads the index.html that is in "resources/public" and not "portfolio-resources/public":dev-http {9800 ["portfolio-resources/public" "resources/public" "classpath:public"]}
I am sorry for misunderstanding!
Yes, that works perfectly. I for some reason thought that the last index.html it finds is what it serves. š
Thank you very much. As always, your help is much appreciated. Thank you!
I understand. That is perfect!
How can I connect to the repl if Iām serving the app from a non-shadow-cljs server?
same way as with a shadow-cljs server (assuming you are talking about the http server)
the REPL runs over its own server shadow-cljs always starts (you'll see a websocket connect to it, default on port 9630)
Makes sense now thanks