shadow-cljs

thheller 2026-01-20T18:10:53.583179Z

sorry, can't help with anything duct related. no clue how it works.

Ahmed Hassan 2026-01-20T22:31:49.372439Z

Debugger and console output brings us to this file. /devtools/client/shared.cljs

thheller 2026-01-21T07:07:19.734309Z

yeah I can explain this error. you seem to have a :server build (in shadow-cljs.edn). you once started a watch for that. the output still lives and gets loaded in the browser. it tries to connect to the server for hot-reload/repl, but the watch is no longer running.

👍 1
weavejester 2026-01-22T18:01:10.405919Z

Well spotted!

weavejester 2026-01-21T17:56:51.400539Z

Apologies for the noise - I should really fork shadow-cljs and remove the logs that direct people here. Duct tries to use shadow-cljs as a library for compiling/hot-loading CLJS, but shadow-cljs is designed as a command-line tool and doesn't do well when taken out of its natural environment. I've been resisting forking shadow-cljs into a "library friendly" version that pulls out the CLI stuff - largely because that sounds like a lot of work! - but it might be time for me to bite the bullet.

thheller 2026-01-21T18:28:30.194269Z

I wouldn't really say its designed as a command line tool, given that I never use it like that myself 😛

weavejester 2026-01-21T18:31:39.778899Z

Oh, I mean in terms of that it expects configuration to come from a particular file, for hot-reloading to occur via a file-system watcher, things like that. I found it hard to use if I wanted to supply a configuration directly, or if I wanted to control reloading. shadow-cljs seems to have been designed as a tool first, rather than as a library with a tool sitting on top, if that makes sense.

weavejester 2026-01-21T18:32:29.172759Z

Which is fine, of course. It's designed for a particular use-case and I'm trying to use it in a way it wasn't designed to be.

thheller 2026-01-21T18:32:47.756569Z

yes, that is true. it is designed to be a tool. an embeddable one, but nonetheless not customizable in the things you mentioned

thheller 2026-01-21T18:33:34.276929Z

I mean technically all that is possible, just has no official API

weavejester 2026-01-21T18:36:14.605959Z

Yeah, and I've delved into the code, but there's a lot of hard-coded stuff around what it expects that make it difficult to use in that way. Hence my thought to try and and separate out the "tool" parts from the "library" parts.

weavejester 2026-01-21T18:38:17.591719Z

And trying to use the shadow-cljs in that way also sometimes produces error/warning messages with "shadow-cljs" in, which means people bother you and not me when things go wrong. Something I'd like to fix! 🙂

thheller 2026-01-21T19:08:29.566829Z

why separate it out though? I mean what is lacking with what it already does? Isn't it less work for you to just use what is there and be able to just follow what everyone else is doing? including all the existing docs and examples?

thheller 2026-01-21T19:09:44.567699Z

only to save a 10 line shadow-cljs.edn file? (or whatever the goal is)

weavejester 2026-01-21T19:43:38.870439Z

There are a few main reasons: a general one and a couple of more specific ones. The broadest reason is that tools in Clojure tend to exist on top of libraries with well defined APIs, which allows them to be used more flexibly than if they were tools alone, and aligns with Rich's ideas about simplicity. To give an example, Kaocha uses its own configuration file like shadow-cljs, but also has a kaocha.api namespace that makes it very pleasant to integrate with. This recently allowed me to write more complex and unusual test setups than would be possible with the tool alone. The first more specific reason is that I want to ensure that when a Duct application is reset (i.e. reloaded/refreshed), the client-side and server-side are reset at the same time. This keeps both sides of the application in sync. I also want control over when a reset happens: I don't want to reset when I'm in the middle of changing several files. Having a file watcher compile the ClojureScript separately every time I save a file works against my development process. The final reason is that Duct has "modules" which are ways of "expanding" a small, general configuration into a larger, more specific one, while still allowing the user to override specific parts of the expansion. For example, the ClojureScript module in Duct sets up shadow-cljs according to the environment, and also adds in a static file handler to serve the assets that shadow-cljs makes. Using a separate file for shadow-cljs configuration means I can't benefit from Duct's more sophisticated configuration management.

thheller 2026-01-21T19:57:47.652769Z

there is a :autobuild false option so that the file watch doesn't trigger an automatic compile. and then there is an api method to actually trigger it (shadow.cljs.devtools.api/watch-compile! :the-build)

weavejester 2026-01-21T20:47:24.444689Z

That's actually what I https://github.com/duct-framework/compiler.cljs.shadow/blob/37f6568cf60c26d1dc405e18571c46f5e1bc5709/src/duct/compiler/cljs/shadow.clj#L51, though the warning console message still pops up.

thheller 2026-01-21T21:21:18.214669Z

which warning?

thheller 2026-01-21T21:23:39.984619Z

the server not running? assuming this :server is the actual config and that it is running I'd suspect this to be a cache issue

thheller 2026-01-21T21:24:01.556919Z

your http server may serve the old files, or rather tell the browser it can continue to use them

thheller 2026-01-21T21:24:33.579359Z

or things are loaded out of order and the watch isn't actually running by the time the JS is loaded

weavejester 2026-01-21T22:15:57.288929Z

The warning about the watch server not running. I haven't had time to investigate the issue in detail - as far as I can tell the reloading all works - it compiles the files and hot-reloads them when triggered. Because of that I haven't bothered looking into why the warning message pops up.

thheller 2026-01-22T07:21:26.846589Z

still had the code open you linked yesterday. just noticed that there seems to be an extra config here https://github.com/duct-framework/compiler.cljs.shadow/blob/37f6568cf60c26d1dc405e18571c46f5e1bc5709/src/duct/compiler/cljs/shadow.clj#L28