shadow-cljs

pez 2025-09-18T09:19:57.496609Z

Hello. Continuing the discussion from https://clojurians.slack.com/archives/C06MAR553/p1758141056002619 here. Specifically about the runtime description label. Today we have client-id and either desc or user-agant, afaiu. desc and user-agent do not distinguish very well between different runtime instances. I have the app running in Brave, Chrome, and inside VS Code’s simple-browser, and they all display the same user agent. And someone like @hoppy has it running on a lot of rapberry pis at once, all with the same desc (as long as they have the same node version running). I really have no idea what could be done about it, but want to at least explore it together with you people.

Matthew Davidson 2025-09-18T11:52:25.636379Z

Is there a solution to the lack of :preamble support? I've inherited a very old cljs code base that uses it with lein-cljsbuild, and I'm in the process of modernizing it with shadow. The production build uses preamble to prepend a dozen plain .js files, half of which are old enough that they're not on npm and don't even use modules; they just set a bunch of globals we refer to. I saw prepend-js, but these are definitely not GCC compatible. prepend looks like what I want, but it only takes strings. I found https://clojurians.slack.com/archives/C6N245JGG/p1568024913425000, is that still recommended, or is there something I should do with hooks instead (maybe :optimize-finish)? I'd prefer to switch to shadow, get it working as-is, and only then start updating libraries, if possible. Thanks for any suggestions!

Matthew Davidson 2025-09-22T04:43:13.300019Z

I ended up adding a preamble hook for both dev and release builds, as too much of the existing setup expects one concatenated file, since that's what we deliver to clients, anyway. Trying to separate them just makes it harder to test the builds the same way. In case anyone needs it, here's what we did:

(ns shadow.hooks
  (:require [clojure.java.io :as io]))

(def preamble
  (apply str
         "// Preamble start\n\n"
         (slurp (io/resource "this"))
         "\n"
         (slurp (io/resource "that"))
         ...
         "\n\n// Preamble end\n\n"))

(defn preamble-hook
  {:shadow.build/stage :configure}
  [build-state & args]
  (println "Prepending preamble")
  (let [stage (:shadow.build/stage build-state)]
    (-> build-state
        (assoc-in [:shadow.build.modules/config :your-module-name :prepend] preamble))))
;; in shadow-cljs.edn:

{...
 :builds {:your-module-name {:build-hooks [(shadow.hooks/preamble-hook)]
  ...

Matthew Davidson 2025-09-19T07:45:17.767959Z

Any further thoughts? Sorry to bug you.

thheller 2025-09-19T07:58:31.615139Z

(-> (shadow/get-build-config :your-build) (update-in [:modules :main] assoc :prepend (slurp "whatever.doc")) (shadow/release*)) seems like the best option?

thheller 2025-09-19T07:59:03.810159Z

for local testing I'd just use a separate script tag and for release just prepend it

thheller 2025-09-19T07:59:22.471989Z

you can use the above via https://shadow-cljs.github.io/docs/UsersGuide.html#clj-run

Matthew Davidson 2025-09-19T07:59:45.537069Z

Thanks! You recommend the above over a hook fn?

thheller 2025-09-19T07:59:57.943359Z

(defn release []
  (-> (shadow/get-build-config :your-build)
      (update-in [:modules :main] assoc :prepend (slurp "whatever.doc"))
      (shadow/release*)))

thheller 2025-09-19T08:00:10.692969Z

yes

Matthew Davidson 2025-09-19T08:00:23.666959Z

Got it. Will try this. Thank you very much for your help

thheller 2025-09-18T17:46:35.928449Z

seems like it would be easier to just leave the extra .js files as they are, or concatenated together into one .js file. and then just add an extra script tag to your html to load it? or any particular reason shadow even needs to know about it?

Matthew Davidson 2025-09-19T01:38:19.038879Z

@thheller Sorry, to clarify, we produce one js artifact for clients to install on their own websites. We don't control the pages it's installed on. And realistically, I don't think I can convince them all to add another dozen <script> tags 😄

Matthew Davidson 2025-09-18T11:53:18.855069Z

I also found a suggestion to do something like (assoc-in build-state [:shadow.build.modules/config :main :prepend] licenses)

grav 2025-09-18T15:31:27.834369Z

I ended up getting the @aws-sdk/client-s3 and @aws-sdk/s3-request-presigner node modules (which are part of https://github.com/aws/aws-sdk-js-v3) to compile with ShadowCLJS by adding

:js-options {:entry-keys ["module" "browser" "main"]}
as per https://shadow-cljs.github.io/docs/UsersGuide.html#js-entry-keys

grav 2025-09-18T15:32:57.084539Z

Still not sure I understand what's going on. But it works 🙂

grav 2025-09-18T15:34:26.067669Z

It did however reduce my bundle size from 10MB to 1.8MB

thheller 2025-09-18T15:51:44.636719Z

you probably also want to add :export-conditions ["module" "import" "browser" "require" "default"] to the :js-options map. that ensures packages with "exports" also take the esm files, since that is pretty common these days

grav 2025-09-18T18:19:17.077469Z

Ah right, saw it here in Slack but couldn’t find it in the Shadow-CLJS guide

grav 2025-10-05T17:38:55.659779Z

Pretty sure this could be ported to Cljs. Would probably be even smaller: https://github.com/jacobemcken/aws-simple-sign/blob/main/src/aws_simple_sign/core.clj

borkdude 2025-09-18T18:46:32.915479Z

:compiler-options {:source-map true} is the default in shadow right? I do see generated .map files but no mention of //# sourceMappingURL in my module .js file

thheller 2025-09-19T05:35:09.380219Z

its the default for dev builds, release builds no

👍 1
borkdude 2025-09-19T05:36:25.100269Z

The release build still produces maps but doesn’t link them or so?

thheller 2025-09-19T05:37:32.927189Z

if you have the build-report hook active yes, because thats working off source maps it enables them but doesn't link them

borkdude 2025-09-19T05:53:33.327039Z

Ah now I got it then, thanks!

borkdude 2025-09-19T05:54:41.290639Z

Is there a disadvantage of including source maps for release builds? Does a browser greedily download them?

thheller 2025-09-19T05:55:17.157329Z

source maps contain all the sources. so if you don't mind users getting access to your sources then no. browsers only download with devtools open.

borkdude 2025-09-19T05:55:52.147789Z

That’s fine, it’s open source anyway. Thanks!