shadow-cljs

mitchelkuijpers 2025-05-20T13:09:02.738549Z

Now I am fighting with nodejs built-in modules, keep running into these errors when loading the compiled nodejs script:

shadow-cljs - failed to load module$node_modules$$google_cloud$firestore$build$src$index

Module not provided: shadow.esm.esm_import$process

node:internal/modules/esm/module_job:387
    const namespace = this.module.evaluateSync();
                                  ^

Module not provided: shadow.esm.esm_import$process
This is with :target :esm :runtime :node

thheller 2025-05-20T13:15:29.109739Z

with :js-provider :import or :keep-as-import #{"process"}?

mitchelkuijpers 2025-05-20T13:15:45.628919Z

:js-options {:keep-native-imports true
                                   :keep-as-import 
                                   #{"trace_events"
                                     "async_hooks"
                                     "wasi"
                                     "perf_hooks"
                                     "request"
                                     "inspector"
                                     "diagnostics_channel"
                                     "fs"
                                     "os"
                                     "path"
                                     "http"
                                     "http2"
                                     "https"
                                     "zlib"
                                     "stream"
                                     "crypto"
                                     "tty"
                                     "net"
                                     "tls"
                                     "querystring"
                                     "child_process"
                                     "dns"
                                     "worker_threads"
                                     "module"
                                     "constants"


                                     ;; Weird and annoying libraries
                                     "re2"
                                     "canvas"
                                     "jsdom"

                                     "firebase-admin/app"
                                     "firebase-admin/auth"
                                     "firebase-admin/storage"
                                     "firebase-admin/functions"
                                     "@google-cloud/firestore"
                                     "@elastic/elasticsearch"
                                     }

                                   :ignore-asset-requires true}

mitchelkuijpers 2025-05-20T13:16:02.377509Z

But yeah with :keep-as-import

thheller 2025-05-20T13:17:14.655979Z

I might be blind but "process" is not in that set?

thheller 2025-05-20T13:17:25.640179Z

:keep-native-imports is not an option that exists

mitchelkuijpers 2025-05-20T13:17:53.204049Z

Oh my bad I added this into shadow.build.resolve

(or
      (str/starts-with? require "esm:")
      (str/starts-with? require "https://")
      (str/starts-with? require "http://")
      (and
        (:keep-native-imports js-options)
        (or (contains? native-node-modules require) (str/starts-with? require "node:")))
      (contains? (:keep-as-import js-options) require)) 

thheller 2025-05-20T13:18:29.898729Z

ah

mitchelkuijpers 2025-05-20T13:18:48.092139Z

I can remove it and fix the :keep-as-import list

mitchelkuijpers 2025-05-20T13:19:27.051389Z

For some reason it broke with all of these libs:

"firebase-admin/app"
                                     "firebase-admin/auth"
                                     "firebase-admin/storage"
                                     "firebase-admin/functions"
                                     "@google-cloud/firestore"
                                     "@elastic/elasticsearch"

mitchelkuijpers 2025-05-20T13:19:39.611119Z

That is why I was adding them

thheller 2025-05-20T13:19:50.513279Z

"broke"?

thheller 2025-05-20T13:20:11.518349Z

I assume you are not using :js-provider :import because of this css stuff?

mitchelkuijpers 2025-05-20T13:20:32.580929Z

I got the same error for all of the libs about shadow.esm.esm_import$process

mitchelkuijpers 2025-05-20T13:20:48.237239Z

And yes you are correct because of the css stuff

thheller 2025-05-20T13:24:42.232339Z

what confuses me is failed to load module$node_modules$$google_cloud$firestore$build$src$index

thheller 2025-05-20T13:24:56.454979Z

that is not a file it should be loading if you have excluded it

thheller 2025-05-20T13:25:18.990249Z

so it should just import "@google-cloud/firestore" directly from node

mitchelkuijpers 2025-05-20T13:25:23.596559Z

Oh yeah sorry I added that later

mitchelkuijpers 2025-05-20T13:25:28.702109Z

currently it is:

shadow-cljs - failed to load module$node_modules$agentkeepalive$lib$agent

Module not provided: shadow.esm.esm_import$process
shadow-cljs - failed to load module$node_modules$agentkeepalive$index
Module not provided: shadow.esm.esm_import$process

node:internal/modules/esm/module_job:387
    const namespace = this.module.evaluateSync();
                                  ^

Module not provided: shadow.esm.esm_import$process

mitchelkuijpers 2025-05-20T13:25:33.184869Z

So sorry about that

thheller 2025-05-20T13:27:05.043439Z

did you restart the build sometime inbetween changing all those exludes?

mitchelkuijpers 2025-05-20T13:27:27.523279Z

Yes and als did a clean of the .shadow-cljs folder and the target folder

mitchelkuijpers 2025-05-20T13:28:03.020129Z

I do have multiple builds running so I could try to only run the one build

thheller 2025-05-20T13:28:37.233279Z

nah builds don't share anything, so should not matter

thheller 2025-05-20T13:28:43.595389Z

unless of course they use the same :output-dir?

mitchelkuijpers 2025-05-20T13:28:54.871579Z

No they don't

mitchelkuijpers 2025-05-20T13:29:06.284029Z

But I am now only running the one build to be sure

thheller 2025-05-20T13:29:08.591639Z

ok, then they can't affect each other

mitchelkuijpers 2025-05-20T13:30:32.515189Z

Still running into exactly the same error

thheller 2025-05-20T13:31:34.121919Z

maybe I need to add an inverse like :only-bundle #{"that-css-thing"} 😛

mitchelkuijpers 2025-05-20T13:31:46.342849Z

Yeah I was just thinking the same thing

mitchelkuijpers 2025-05-20T13:31:56.510339Z

only bundle the @atlaskit crap

thheller 2025-05-20T13:32:02.483659Z

its always a bit sketchy to only bundle partially because some of the included things may end up using the same things and end up with the unbundled stuff

thheller 2025-05-20T13:32:08.964129Z

two versions of the same thing is never good

mitchelkuijpers 2025-05-20T13:32:16.091229Z

yeah that is never a good idea

mitchelkuijpers 2025-05-20T13:32:36.793539Z

And that is a very easy trap to fall into

mitchelkuijpers 2025-05-20T13:33:00.257519Z

I don't really get why a shadow.esm.esm_import$process is created I thought it would keep those import calls as is

thheller 2025-05-20T13:33:17.527839Z

you could do a quick test and try :js-provider :import but then run the final result through something like ncc

thheller 2025-05-20T13:33:33.245619Z

https://github.com/vercel/ncc

mitchelkuijpers 2025-05-20T13:33:47.281309Z

I did the same with rsbuild

mitchelkuijpers 2025-05-20T13:33:51.273289Z

And then the project works

thheller 2025-05-20T13:33:57.497729Z

hmm ok

thheller 2025-05-20T13:34:21.130659Z

would help to have a reproducible example so I can check what exactly is wrong

mitchelkuijpers 2025-05-20T13:34:35.927609Z

Sure I'll work on that

mitchelkuijpers 2025-05-20T13:51:49.340079Z

I reproduced it:

shadow-cljs - failed to load module$node_modules$agentkeepalive$lib$agent
Module not provided: shadow.esm.esm_import$process
shadow-cljs - failed to load module$node_modules$agentkeepalive$index
Module not provided: shadow.esm.esm_import$process

node:internal/modules/run_main:129
    triggerUncaughtException(
    ^
Module not provided: shadow.esm.esm_import$process
(Use `node --trace-uncaught ...` to show where the exception was thrown)
I'll create a repo

👍 1
mitchelkuijpers 2025-05-20T13:57:49.953209Z

https://github.com/mitchelkuijpers/shadow-playground

mitchelkuijpers 2025-05-20T17:10:32.354139Z

Btw I got the same error for other built-in stuff if it tried to require that

thheller 2025-05-21T06:23:46.349329Z

fixing this is unfortunately a bit involved. not quite sure how to go about it. currently for esm shadow-cljs will leave esm_import$... references in the code. as part of :advanced optimizations there is an extra closure pass that'll collect these and add the actual required JS import. problem is the sources for the :keep-as-import stuff are :shadow-js, so like any other npm source only runs through :simple and not this path

mitchelkuijpers 2025-05-21T06:53:58.167859Z

It currently breaks without advanced optimizations though? Or is it more related to the pass that get's added regardless of the optimizations?

thheller 2025-05-21T06:54:22.556789Z

making dev builds work is trivial

mitchelkuijpers 2025-05-21T06:57:03.468679Z

Ah ok I did not get that far

thheller 2025-05-21T06:59:22.634509Z

problem is making this work without breaking the reasons I did this compiler pass in the first place

thheller 2025-05-21T07:02:05.085659Z

I think I have a plan though

🙏 1
thheller 2025-05-21T09:26:33.108349Z

try 3.1.3. Module not provided: shadow.esm.esm_import$process should be gone

mitchelkuijpers 2025-05-21T09:26:43.830149Z

Damn that was fast

thheller 2025-05-21T09:28:27.754589Z

its not the cleanest solution, but should be fine

mitchelkuijpers 2025-05-21T09:29:02.306549Z

I will test it out today and report back, if it all works I can remove a lot of crap from our projects

janezj 2025-05-20T13:39:29.028639Z

I want to port node class. It works in repl, but release build is crashing. (btw. in my setup in calva no longer works async print from node)

const { TeamsActivityHandler } = require("botbuilder");
class TeamsBot extends TeamsActivityHandler {
  constructor() {
    super();
      this.onMessage(async (context, next) => {
      await context.sendActivity("robotox!");
     await next();
    });))
with defclass
(ns teams-bot
  (:require
   ["botbuilder" :refer [^js TeamsActivityHandler TurnContext]]
   [promesa.core :as p]
   [shadow.cljs.modern :refer [defclass]]))

(defclass TeamsBot
  (extends TeamsActivityHandler)
  (constructor [this]
               (super)
               (.onMessage this (fn [^ĵs context next]
                                  (on-message context)
                                  (p/then (next) identity)))))
It works in repl (btw in calva no longer works async print). but in release build with debug there is crash. I tried ^js, js/*, and :simple
/app/bot.js:11843
    this.$onMessage$(function($context$jscomp$15$$, $next$jscomp$6$$) {
         ^

TypeError: this.$onMessage$ is not a function
    at new $teams_bot_cljs$classdecl$var6$$ (/app/bot.js:11843:10)
    at Function. (/app/bot.js:11995:3)
    at $cljs$core$apply$cljs$0core$0IFn$0_invoke$0arity$02$$ (/app/bot.js:3586:179)
    at /app/bot.js:11991:2
    at Object. (/app/bot.js:11999:3)
    at Module._compile (node:internal/modules/cjs/loader:1364:14)
I aslo don't know how to do await next(); this is my best guess (p/then (next) identity)

thheller 2025-05-20T13:42:12.524069Z

you should be getting an extern inference warning?

thheller 2025-05-20T13:42:23.619419Z

onMessage is getting renamed

thheller 2025-05-20T13:43:42.676879Z

the ^js needs to be on the this in this case

thheller 2025-05-20T13:43:52.558559Z

so (.onMessage ^js this ...)

thheller 2025-05-20T13:46:05.387159Z

(defclass TeamsBot
  (extends TeamsActivityHandler)
  (constructor [this]
    (super)
    (.onMessage ^js this
      (fn [^js context next]
        (js-await [_ (.sendActivity context "robotox!")]
          (js-await [_ (next)]
            nil))))))

thheller 2025-05-20T13:46:06.276019Z

maybe

thheller 2025-05-20T13:46:37.721699Z

dunno exactly that the next is doing there or why its waiting for it, probably can just by (next) without await

thheller 2025-05-20T13:47:14.136519Z

or (-> (.sendActivity context ...) (.then next))

janezj 2025-05-20T13:48:40.717419Z

thanks I tried (constructor [^ĵs this] and it got renamed, thanks,

thheller 2025-05-20T13:49:26.021869Z

hmm that should be fine too

janezj 2025-05-20T14:01:35.200049Z

this await chaining is very strange to me. i am guessing that this is so confusing to me, because clojure return last eval as function result, but js hacks something with await

janezj 2025-05-20T14:02:55.002609Z

So I am getting "router deprecated handlers that are Promise-like are deprecated, use a native Promise instead at node_modules/router/lib/route.js:157:13"

thheller 2025-05-20T14:04:08.376439Z

that might be complaining about promesa. that has its own weird promise type

janezj 2025-05-20T14:07:51.003369Z

yes it is something in p/let because without p/let and just returning (p/promise nil) there are no warns

thheller 2025-05-20T14:09:00.909199Z

so probably need to remove promesa

thheller 2025-05-20T14:09:39.058749Z

FWIW async functions in JS just implicitly always return a promise

janezj 2025-05-20T14:09:47.801939Z

I read somewhere that yours js-await is just for repl?

thheller 2025-05-20T14:09:58.605829Z

so without an actual return that just returns a promise that resolves to undefined

thheller 2025-05-20T14:10:05.797469Z

no?

thheller 2025-05-20T14:11:03.969119Z

doesn't make much sense to use the in the REPL. there was talk about a specific "primitive" in the REPL to make dealing with async code a bit easier

thheller 2025-05-20T14:11:23.103029Z

but that doesn't exist yet

janezj 2025-05-20T14:12:59.599709Z

i don't see async output in calva, no logss, and prints, so it is quite painfull to do repl dev.

mitchelkuijpers 2025-05-20T14:14:34.633239Z

We do

(p/handle promise-thing (fn [res err] (def _res [res err]))
This kinda works for repl dev

janezj 2025-05-20T14:16:39.518749Z

Great, But all log statements are not printed when they are invoked in express handlers.

mitchelkuijpers 2025-05-20T14:17:13.015159Z

Yeah I just have a console open for that

janezj 2025-05-20T14:26:32.049549Z

I am investigating if this is just my problem, because i am running shadow-cljs watch ;bot, and I am connected from calva to nrepl, and there is no output. And I tried different output destinations. but just for node.

janezj 2025-05-20T15:31:10.340879Z

It is interesting that (TeamsBot.) is not marked as JS,. and .run is renamed.

(defn run-teams-bot [^js context]
  (let [^js b (TeamsBot.)]
    (.run b context)))

thheller 2025-05-20T15:33:01.191099Z

hmm that is very clearly marked?

thheller 2025-05-20T15:33:53.887539Z

which shadow-cljs version do you use? could be that the js tag is removed because the type is inferred by other code? could just be a bug

thheller 2025-05-20T15:34:56.544159Z

or do you mean that it gets renamed if the ^js tag is not there. that would be expected than and should produce an inference warning

janezj 2025-05-20T15:36:33.494309Z

3.1.1 in case (.run (TeamsBot.)) .run was renamed, even (.run ^ĵs (TeamsBot.)) got renamed wo warnings

janezj 2025-05-20T15:45:21.887559Z

but now i have bigger problem:

/app/node_modules/botbuilder-core/src/turnContext.ts:557
                    this.responded = true;
                                  ^


TypeError: Cannot perform 'set' on a proxy that has been revoked
    at Proxy.<anonymous> (/app/node_modules/botbuilder-core/src/turnContext.ts:557:35)
    at Generator.next (<anonymous>)
    at fulfilled (/app/node_modules/botbuilder-core/src/turnContext.ts:4:4)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

janezj 2025-05-21T10:18:38.623529Z

I tried some other unusual ^js annotations .run is recognised in this case

(defn async-run-teams-bot
  [^js context]
  (let [b (TeamsBot.)]
    (p/let [_ (.run ^js b context)])))
this case is also ok:
(let [b (TeamsBot.)]
    (js-await [_ (.run ^js b context)]))
but not
(js-await [_ (.run (TeamsBot.) context)])

(js-await [_ (.run ^js (TeamsBot.) context)])

(let [b (TeamsBot.)]
  (js-await [_ (.run ^js (TeamsBot.) context)])

(let [b (TeamsBot.)]
  (p/let [_ (.run ^js  b context)])))
 (p/let [_ (.run (new TeamsBot) context)]))
 (p/let [_ (.run (TeamsBot.) context)])
 (p/let [_ (.run ĵs (TeamsBot.) context)])
 (p/let [_ (.run (new TeamsBot) context)])
And this is also strange (:require ["botbuilder" :refer [TurnContext]]) ok (.getConversationReference ^js *TurnContext* (.-activity context)) not ok: (*TurnContext*.getConversationReference (.-activity context))

thheller 2025-05-21T10:21:03.359789Z

(TurnContext.getConversationReference (.-activity context)) this not working is sort of expected since this is syntax that only accidentally works

thheller 2025-05-21T10:21:25.451089Z

(.getConversationReference TurnContext (.-activity context)) this should be fine and not require ^js hints?

janezj 2025-05-21T10:21:43.430439Z

It is a must