Fork me on GitHub

Is there a way to get a REPL for a build with target :esm and runtime :node? The build configuration:

{:target           :esm
   :js-options       {:js-provider :import}
   :runtime          :node
   :output-dir       "out/esm"
   {:script {:entries [my.script.core]
             :exports {init my.script.core/init}}}}
The output produced by npx shadow-cljs watch ... for this build seems to not connect to the server and node out/esm/script.js exists immediately. I have tried to make it connect to the server by requiring the namespace shadow.cljs.devtools.client.node in my.script.core . But then running the output with node ... reports the following error:
var socket = (new shadow.esm.esm_import$ws(ws_url,({"rejectUnauthorized": false})));

TypeError: shadow.esm.esm_import$ws is not a constructor
    at shadow$cljs$devtools$client$node$start (file:///.../out/esm/cljs-runtime/shadow.cljs.devtools.client.node.js:122:15)
    at Object.attempt_connect_BANG_ (file:///.../out/esm/cljs-runtime/shadow.cljs.devtools.client.shared.js:482:128)
    at Object.shadow$cljs$devtools$client$shared$init_runtime_BANG_ [as init_runtime_BANG_] (file:///.../out/esm/cljs-runtime/shadow.cljs.devtools.client.shared.js:970:16)
    at file:///.../out/esm/cljs-runtime/shadow.cljs.devtools.client.node.js:431:36


I also tried to use node-script as a target but that doesn't seem to be an option with some npm packages that are ESM only (e.g., the latest version of chalk).


@davidst I didn't try to get the node repl running with :esm yet. you can try setting :runtime :custom :devtools {:client-ns some.ns} where some.ns is just a copy of with the ["ws" :as ws] changed to ["ws$default" :as ws]. maybe thats enough?


I suspect there might be more changes necessary though


Thank you. Following your suggestion I was able to connect to the repl. Unfortunately, when evaluating anything, I was getting errors about undefined SHADOW_IMPORTED and SHADOW_IMPORT. It looks like these are defined in node_bootstrap.txt for node targets. It seems shadow/boot/esm.js is supposed to replace (some of) that. I have tried to fix these errors. It seems to work alright so far but it is clearly a nasty hack:

;; these implementations replace the first three functions in shadow.cljs.devtools.client.node

(defn node-eval [{:keys [js source-map-json] :as msg}]
  (let [result (js* "(0,eval)(~{});" js)]

(defn is-loaded? [src]
  (true? (js/SHADOW_ENV.setLoaded src)))

(defn closure-import [src]
  {:pre [(string? src)]}
  (js/console.log src)
  (when-not (= src "goog.base.js")
    ;; goog base doesn't work with this kind of import?
    (js/globalThis.shadow_esm_import (str "./cljs-runtime/" src)))
  (js/SHADOW_ENV.setLoaded src))

;; this interface implementation replaces the current one for the type cljs-shared/Runtime
(-js-eval [this code]
  (js* "(0,eval)(~{});" code))


this probably needs many more adjustments. the regular node impl assumes it can do sync imports but the shadow_esm_import is async so all of the code needs to be adjusted to not assume sync


might need to go with loading the file from disk using fs/readFileSync and then eval'ing


haven't spend much time on node with esm so not sure what kind of restrictions exist. might even require modifying the source get get rid of import statements. I opened


not sure when I can get to it though. pretty busy currently.


The hack to prepend "./cljs-runtime" to src seems especially fragile. Is there a better way to do that?


Complete newbie using the default shadow-cljs setup in luminus. App loads fine but test throws a fit. Is this a 'need to be using :broswer-test instead of :node-test' type issue? I'm struggling to figure out where to even look to troubleshoot what wrong beyond an import expects the browser 'window' object to exist. Its one test file for a re-frame subscription if that helps at all

ReferenceError: window is not defined
    at [path]/.shadow-cljs/builds/test/dev/out/cljs-runtime/accountant/core.cljs:21:35
    at [path]/.shadow-cljs/builds/test/dev/out/cljs-runtime/accountant.core.js:16:3
    at global.SHADOW_IMPORT ([path]/target/test/test.js:64:44)
    at [path]/target/test/test.js:1701:1
    at Object.<anonymous> ([path]/target/test/test.js:1781:3)
    at Module._compile (node:internal/modules/cjs/loader:1097:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1149:10)
    at Module.load (node:internal/modules/cjs/loader:975:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)


perhaps more of an interop issue. window or js/window?


I'm not calling window anywhere but I suppose one of the libraries I'm using must be. I swapped to :browser and am at least past ^ error message. I was hoping to avoid having to set up Karma and a browser-driven test suite for now by just testing my re-frame logic with :node-test but its been more of a hassle to troubleshoot than it is to just launch Karma. Anyways, thanks for taking a look!


this library is using js/window. so it just isn't compatible with anything that doesn't have that. from the looks of it there are many other things that expect a full browser


if you can move the require for that lib to some other place yuo might be able to run it in node. can't say without seeing code.

👍 1

ahhh thanks thheller, I mistakenly assumed 'accountant' was some shadow-cljs interal, but its an internal dependency of my routing lib. Sorry haha I'm still struggling with the normal clj stacktraces so I kinda just assumed this was another opaque one 😅. I'll deps :tree next time