shadow-cljs

wombawomba 2025-02-15T13:24:04.617139Z

I have a dependency from x.cljs -> y.clj (using a macro that builds a data structure) -> z.clj (in a separate library, included via a lein checkout). Shadow-cljs doesn't recompile when I modify z.clj, so I don't get hot reload for changes to z.clj – in fact I need to restart shadow-cljs for the changes in z.clj to be reflected in x.cljs. Is there some trick I can use to get hot reload here?

wombawomba 2025-02-15T13:25:00.926499Z

FWIW the code in y.clj is basically

(def route-data
  (set (map (fn [] ...) z/all-routes)))

(defmacro make-href
  "Variant of make-href* that tries to validate the route at compile time."
  [route]
  (if-let [kw (if (keyword? route)
                route
                (as-> (:route route) $ (when (keyword? $) $)))]
    (if (contains? route-ks kw)
      `(make-href* ~route)
      (-> (str "Failed to build href for route: " (fmt/ppr-inline route)
               "\nDefined routes: " (fmt/ppr-inline route-ks))
          (ex-info {})
          throw))
    `(make-href* ~route)))

thheller 2025-02-15T13:37:22.223129Z

CLJ reloading is limited, so I'd recommend something like clj-reload to get something that is more optimized for CLJ

thheller 2025-02-15T13:37:35.829949Z

or you can always just edit the file and reload it from the REPL directly

thheller 2025-02-15T13:38:01.038809Z

but it still has limits in how far shadow-cljs follows CLJ dependency graphs

wombawomba 2025-02-15T21:16:30.952009Z

cool, thanks

wombawomba 2025-02-15T21:17:06.457589Z

I didn't know about clj-reload; here I am still using tools.namespace like a caveman

Oliver Marks 2025-02-15T16:39:26.966039Z

Wondering if some one can help, I am stuck with a stale build error which I can't figure out the cause of I am running

clj -M:cljs:cljs-dev:portfolio:shadow-run watch portfolio
shadow-cljs - HTTP server available at 
shadow-cljs - server version: 2.28.20 running at 
shadow-cljs - nREPL server started on port 40763
shadow-cljs - watching build :portfolio
[:portfolio] Configuring build.
[:portfolio] Compiling ...
[:portfolio] Build completed. (852 files, 0 compiled, 0 warnings, 7.40s)
Which seems to work modifying and saving triggers a rebuild, I have this shadow config
{:deps {:aliases [:cljs]}
 :jvm-opts ["-Xms1g" "-Xmx1g" "-XX:+UseG1GC"]
 :dev-http {8090 ["projects/frontend-web/resources/public/" "classpath:public" "components/"]}
 :nrepl {:middleware [refactor-nrepl.middleware/wrap-refactor]}
 :builds {:app {:output-dir "projects/frontend-web/resources/public/cljs-out"
                ;:asset-path "projects/frontend-web/resources/public/"
                :target :browser
                :compiler-options {:infer-externs :auto :output-feature-set :es6}
                :modules {:base {:entries []}
                          :main {:init-fn com.app.example-web.dev/launch
                                 :depends-on #{:base}}
                          :portfolio {:init-fn com.app.portfolio-components.core/launch
                                      :depends-on #{:base}}}
                
                :devtools {:after-load app.main/reload!}}

          :worker  {:output-dir "projects/frontend-web-worker/resources/public/js-worker"
                :asset-path "js-worker"
                :target :browser
                :compiler-options {:infer-externs :auto :output-feature-set :es6}
                :modules {:web-worker {
                                       :init-fn com.app.web-worker.core/init-worker
                                       :web-worker true}}
                :devtools {:after-load app.main/reload!}}


          :portfolio {:output-dir "projects/frontend-web/resources/public/cljs-out/"
                      :asset-path "."
                      :target :browser
                      :compiler-options {:infer-externs :auto :output-feature-set :es6}
                      :modules {:main {:init-fn com.app.portfolio-components.core/launch}}
                      :devtools {:after-load app.main/reload!}}}}
What is the mechanism that makes shadow reload the app ? feel free to point me at documentation that explains this reloading the browser shows any code changes but shadow is not doing its hotreload magic and always shows the build as stale what ever I change so just trying to debug what stale build actually means.

thheller 2025-02-15T16:50:51.220049Z

that error usually means that there is a "competing" shadow-cljs instance. could be that its running twice? maybe in a second terminal or so?

thheller 2025-02-15T16:52:51.470229Z

or it could be an old file you are actually loading because of some old references. did you maybe change the :output-dir or :modules config recently?

thheller 2025-02-15T17:02:03.745469Z

make sure your html is loading the files this is actually generating, so the cljs-out/base.js and cljs-out/main.js files

thheller 2025-02-15T17:03:11.983929Z

dunno why there is a :portfolio module in the :app build when there is an extra :portfolio separate build? seems like that isn't needed?

thheller 2025-02-15T17:03:43.747729Z

also why are you downgrading to :output-feature-set :es6? you really target 2015 browsers?

thheller 2025-02-15T17:04:05.245979Z

:infer-externs :auto is the default and does not need to be set

thheller 2025-02-15T17:05:15.381859Z

seems like this config for :app would suffice

{:output-dir "projects/frontend-web/resources/public/cljs-out"
 :asset-path "/cljs-out"
 :target :browser
 :modules {:main {:init-fn com.app.example-web.dev/launch}}
 :devtools {:after-load app.main/reload!}}

Oliver Marks 2025-02-15T20:34:11.913759Z

Thanks for these suggestions, I know I do not have another instance of shadow running. So I will try the other suggestions, also if you just watch without connecting any idea I would expect it would not be stale, not at a machine to test but will let you know, if nothing else may help others or myself when searching :)

thheller 2025-02-15T20:36:30.487289Z

what you need to verify is that the .js files you are loading are produced by the actual shadow-cljs

thheller 2025-02-15T20:37:03.668319Z

so best is to shut down shadow-cljs, delete all generated files and start, verifying that the files you deleted actually get generated and that there are no duplicates in other folders

thheller 2025-02-15T20:37:49.795279Z

could also just be browser cache is thats not setup properly, but :dev-http usually does that by default

thheller 2025-02-15T20:38:06.304709Z

if a service-worker is involved that might different

Oliver Marks 2025-02-15T21:01:48.125799Z

Awesome think I understand now, its where I have changed things over time I think I started of having portfolio as a separate build, then realized I could use the modules to code split to make the app and portfolio run at the same time by having index.html and portfolio.html and loading the relevant js files in each. I have not worked on the project for a while and come back to it and forgot that, you are correct though removing the cljs-out folder cleared up everything then I could see that portfolio.js was not created but main.js was which is whats specified in the :portfolio build where as :app generates base.js main.js and portfolio.js. Thanks so much @thheller I will make the other changes as well, most likely it me copying and pasting on some of the settings from known working configs.

thheller 2025-02-15T21:02:52.719079Z

I recommend leaving portfolio stuff out of the main build. it'll just get you in trouble for production builds.

thheller 2025-02-15T21:03:20.104379Z

npx shadow-cljs watch app portfolio can just build 2 builds in parallel, so multiple builds is no issue

Oliver Marks 2025-02-15T21:15:27.350759Z

that's awesome it had never occurred to me I could chain them