Bit of a follow up to https://clojurians.slack.com/archives/C6N245JGG/p1736127162988209; in a different project that has ESM dependencies, I'm able to get the project running with node nicely with :target :esm and :js-options {:js-provider :import}with "type": "module" in the package.json.
However, I'm running into issues getting the tests to work. It seems like :target :node-test only wants to generate a common JS file, and because of the "type":"module" I can't run itβeven if I changed the package type, I wouldn't be able to access the ESM dependencies since I'm not using import .
I was able to get pretty far with :target :esm-filesand creating a test runner by hand, eg:
(ns ci
(:require [cljs.test :as test]
[my.module-test]))
(test/run-all-tests #".*-test$")
but I'd really like to generate this file instead of having to remember to manually add all the test namespaces. I've got a build-hook that sorta works, but I'm not sure how to update build-state so that shadow-cljs will compile it in the same step. (If I just rerun the compile then it'll pick up the source file and compile it, but I'd like to have it all a single step)
Is there a good way to add generated sources to the build-state? Or, is there a better way to do what I'm trying to do?
Thanks!! πI don't have any immediate thought on this, but let me break down how :node-test works
basically the build has a custom "resolve" stage. resolve in general being responsible for discovering which files need to be compiled in what order. so usually builds like :browser take :entries (or :init-fn) to know which namespace to start with and just follow the :require structure
https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/build/targets/node_test.clj#L41
instead :node-test starts out with to hardcoded :entries at all, and instead looks at the filesystem to find all files matching the regex -test
it then injects all those namespaces as extra dependencies for the test-runner namespace
https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/build/targets/node_test.clj#L62
beyond that is all just normal compilation
you cannot reliably do this via build hooks and you absolutely shouldn't modify :build-sources in :compile-prepare. that is too late and essentially asking for a lot of trouble π
as you can see there isn't much to the :node-test target at all. it would be entirely feasible to create a :esm-test target or something
I just have never written any kind of test setup using esm and I'm not entirely sure how I would go about doing that
:node-test falls back on :node-script to get the actual output of the same structure
:esm on node needs some work overall, so not a 1:1 conversion
generating the test file might be the best option, but you shouldn't do it from the hook. just generate it before even starting the build
https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/build/test_util.clj it isn't much code and when not constrained with how the build-state works could be much simpler
https://github.com/dhleong/saya/pull/4 is now functional but I imagine there's a better way to do this. Instead of outputting saya.ci.js it's just outputting .js π€
Ah okay, adding :ns to my resource fixed that filename issue. Now getting a warning about failing to write cache due to "no immediate deps" but at least everything is basically working as expected
@thheller I finally had some time to revisit my cursed hack here and https://github.com/dhleong/saya/blob/1ada10950e9d1863522a0f4e6229552d0e6c03e4/src/hooks/shadow/build/targets/node_esm_test.clj a :node-esm-test build target that seems to work fine for my purposes. Not sure whether this would be something you'd be interested in cleaning up and pulling into the main repo, and also curious whether you have some insight into what I ran into https://github.com/dhleong/saya/blob/1ada10950e9d1863522a0f4e6229552d0e6c03e4/src/hooks/shadow/build/targets/node_esm_test.clj#L17 where I needed to set :js-provider both at the top level "state" and under ::build/config as expected π
:esm has a :runtime default of :browser, since you are running node it would be correct to set :runtime :node in the build config. that addresses the WebSocket global problem. for tests I need to think about it for a bit.