Hi, I'm running into a strange error I can't seem to resolve:
(NOBRIDGE) WARN The shadow-cljs Websocket was disconnected.
(NOBRIDGE) ERROR shadow-cljs - remote-error {"isTrusted": false, "message": null}
Error: Unable to resolve module ./app/shadow.cljs.devtools.client.shared from /Users/alexispurslane/Development/yact/mobile/.:
None of these files exist:
* app/shadow.cljs.devtools.client.shared(.native.ts|.ts|.native.tsx|.tsx|.native.mjs|.mjs|.native.js|.js|.native.jsx|.jsx|.native.json|.json|.native.cjs|.cjs|.native.scss|.scss|.native.sass|.sass|.native.css|.css)
* app/shadow.cljs.devtools.client.shared
at ModuleResolver.resolveDependency (/Users/alexispurslane/Development/yact/mobile/node_modules/metro/src/node-haste/DependencyGraph/ModuleResolution.js:114:15)
at DependencyGraph.resolveDependency (/Users/alexispurslane/Development/yact/mobile/node_modules/metro/src/node-haste/DependencyGraph.js:248:43)
at /Users/alexispurslane/Development/yact/mobile/node_modules/metro/src/lib/transformHelpers.js:165:21
at Server._resolveRelativePath (/Users/alexispurslane/Development/yact/mobile/node_modules/metro/src/Server.js:1104:12)
at Server._explodedSourceMapForBundleOptions (/Users/alexispurslane/Development/yact/mobile/node_modules/metro/src/Server.js:1052:35)
at async Promise.all (index 1)
at Server._symbolicate (/Users/alexispurslane/Development/yact/mobile/node_modules/metro/src/Server.js:1009:26)
at Server._processRequest (/Users/alexispurslane/Development/yact/mobile/node_modules/metro/src/Server.js:419:7)
(NOBRIDGE) LOG shadow-cljs #4 ready!
I've tried a few different things, including deleting .shadow-cljs/ and updating shadow-cljs, then updating its version in project.clj, but to no availwell. does the file exist? /Users/alexispurslane/Development/yact/mobile/app/shadow.cljs.devtools.client.shared.js?
dunno why you'd get the disconnect message but then LOG shadow-cljs #4 ready!? this message most definitely wouldn't exist if the shared.js file actually failed to load?
what is the build config used?
@thheller I figured out the problem
Apparently on Android you need to use adb reverse to port forward, essentially, any ports you want your Android device to be able to access from your development workstation or vice versa
which is odd since its browser can access those ports just fine, but whatever 🤷♀️
good to know
sorry for the delayed reply, I've never used Slack before and I didn't see the thread until just now xD anyway, no, that file does not exist, and neither does the app/ directory. I just don't know why it thinks it needs that file – where that dep is coming from
> this message most definitely wouldn't exist if the shared.js file actually failed to load?
right, but shadow-cljs doesn't seem to be working properly, so I'm more inclined to say something didn't load that was required, and it's just incorrectly printing something that indicates it did
> what is the build config used? Here's my shadow-cljs.edn:
{:source-paths ["src" "../src/cljc" "../src/commonjs"]
:dependencies [
[reagent "1.2.0"]
[functionalbytes/sibiro "0.1.4"]
[re-frame "1.2.0"]
[dk.cst/xml-hiccup "0.1.5"]
[com.cognitect/transit-cljs "0.8.280"]
]
:builds
{
:mobile {:target :react-native
:output-dir "out"
:asset-path "out"
:init-fn yact.mobile/init
;; :devtools {:after-load yact.mobile/init}}}
:devtools {:autoload true
:preloads [shadow.expo.keep-awake]}}}
:js-options {
;;:resolve "node_modules"
;;:resolve {"react" "node_modules/react"
;; "react-dom" "node_modules/react-dom"}
;;:js-package-dirs ["react-native/node_modules"]
}
:compiler-options {
:output-feature-set :es5
:infer-externs :auto
}
}
and you have a running watch for the :mobile build? npx shadow-cljs watch mobile?
yes
Sometimes, but not consistently, I also get these errors from the npx expo process:
(NOBRIDGE) WARN The shadow-cljs Websocket was disconnected.
(NOBRIDGE) ERROR shadow-cljs - remote-error {"isTrusted": false, "message": "Failed to connect to /192.168.254.14:9630"}
(NOBRIDGE) WARN The shadow-cljs Websocket was disconnected.
(NOBRIDGE) ERROR shadow-cljs - remote-error {"isTrusted": false, "message": "Failed to connect to /192.168.254.14:9630"}
(NOBRIDGE) WARN shadow-cljs: giving up trying to connect to
these always seem to come around 10-30mins after the first errors
what is unclear is why it is trying to refernence files from the app dir when shadow-cljs is generating the files into the out dir
and normally it shouldn't refer to those individual files at all since everything is loaded from the out/index.js directly
interesting
I've tried deleting .shadow-cljs to wipe any leftover cache or configuration or whatever, but that didn't seem to help
let me try doing a project-wide grep to see if I've hardcoded this somewhere
under which circumstances does the error happen? maybe triggered over the REPL? or hot-reload? or does it happen directly on load?
As soon as I run npx shadow-cljs watch :mobile and then npx expo run:android -d
it can't even begin to hot reload at all, that's actually why I'm trying to track this issue down in the first place
since otherwise, every change I make takes 1-2 mins to see on the device
the only file anything should be referencing is out/index.js the other files basically only exists for REPL purposes
I'm totally new to Clojure, let alone React Native or anything, and this is someone else's project I've been brought on to help with, so there may be stray config files or something I'm missing
> the only file anything should be referencing is out/index.js the other files basically only exists for REPL purposes
hmmmm
its been many years since I looked at anything react-native/expo, so not even sure how configs look on that side these days
either the expo config should directly refer to out/index.js
or some other JS file
I'll try to find it
one other possible factor is that I did try to connect to shadow-cljs through cider – so, presumably the repl, if I understand the byzantine architecture of all this correctly – once or twice, but it errored out both times so I gave up and decided to just use figwheel for close-enough editor support and run shadow-cljs in the background
so maybe there's some kind of left over half-built JS or some conflict going on
🤷
{
"expo": {
"name": "yact",
"slug": "yact",
"version": "1.0.0",
"icon": "./assets/icon.png",
"userInterfaceStyle": "light",
"splash": {
"image": "./assets/splash-icon.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"newArchEnabled": true,
"ios": {
"supportsTablet": true,
"bundleIdentifier": "yact"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"package": "com.yact"
},
"web": {
"favicon": "./assets/favicon.png"
},
"plugins": [
[
"expo-build-properties",
{
"android": {
"compileSdkVersion": 35,
"targetSdkVersion": 34,
"buildToolsVersion": "35.0.0",
"kotlinVersion": "1.9.25"
}
}
],
[
"react-native-ble-plx",
{
"isBackgroundEnabled": true,
"modes": ["peripheral", "central"],
"bluetoothAlwaysPermission": "Allow $(PRODUCT_NAME) to connect to bluetooth devices"
}
]]
}
}this is the expo config
no mention to app/ or anything that I can see
maybe package.json?
or just <project>/index.js
it just says "main": "index.js"
hmm
ok, so <project>/index.js it is
and that file does exist
and likely has a import "./out/index.js" or require
if its referencing anything else in the out dir that should be rmeoved
Yeah, it's importing...
man, I hate codebases I didn't write
it's importing Blah from ./out/index.js
anyway yeah, and the out directory has all the shadow-cljs related files that the program is looking for in app for some reason
seems fine to me
yeah, so why is it trying to pull from app/...
what if I just change the output dir in shadow-cljs.edn
maybe something in the code trying to do something clever? kinda hard to debug this without seeing anything
yeah that's 100% fair
let me see if just changing where it sends all the output makes the error go away at least; I'd like to understand what's /causing/ this, but we can't have everything in life
you can check the out/index.js, there should be a line starting with SHADOW_ENV.evalLoad("shadow.cljs.devtools.client.shared.js" ...
OKay, wait this is progress
okay, so replacing out/index.js with app/index.js, and setting the output and assets directories in shadow-cljs.edn to app/ has eliminated the error about not being able to find a module
but the other errors, and the underlying problem I'm trying to fix, remain
so the big error was a red herring
not a good strategy IMHO. best to identify first what is trying to load that file, since that is the thing that shouldn't be happening in the first place. just accepting that it happens is no good
right but if accepting that it happens and eliminating /that/ error still leads to the main thing I was trying to fix, that does tell us something useful at least?
but yeah I should probably figure out why it's happening. I usually would but this whole project is a clusterfck and I don't want to lose any more sanity points lol
what error is that?
right, so having everything shadow-cljs generates end up where it expects (in the app/ directory) eliminates the big error where it can't find the shared devtools module
now all I get is this:
(NOBRIDGE) WARN The shadow-cljs Websocket was disconnected.
(NOBRIDGE) ERROR shadow-cljs - remote-error {"isTrusted": false, "message": null}
(NOBRIDGE) LOG shadow-cljs #8 ready!shadow.cljs.devtools.client.* are all the namespaces related to hot-reload/REPL. so if for some reason they get loaded twice the connection will be unreliable at best I'd say
there's only one such line in app/index.js
thats correct. just wanted to check its actually there.
yup I was confirming
that I found it
it's definitely there, and it's not duplicated, so hopefully that narrows it down a bit. I'm gonna take a look at SHADOW_ENV and see where it's getting its value from and what's in it, maybe that'll have a hint as to where it's getting app from
ah ok no luck there, that happens prior it looks like
if it gets to LOG shadow-cljs #8 ready! then everything seems fine. that has loaded all the code and the websocket connected
you can run npx shadow-cljs clj-repl and then (shadow/get-server-addrs)
right, but it says websocket disconnected and remote error before it says ready, which is odd. that seems like a race condition almost
that'll give you a list of addrs the client will attempt to connect to. if there is more than one that may explain the disconnect msg
ok, lemme take a look
the connect logic will try them all in sequence until it finds one it can connect to
nope, only one address, my computer's IP address
hmm ok then I don't know why it would fail and then succeed
oh hey that's interesting. killing the watch and starting the repl gave me a few more errors
(NOBRIDGE) WARN The shadow-cljs Websocket was disconnected.
(NOBRIDGE) ERROR shadow-cljs - remote-error {"isTrusted": false, "message": null}
(NOBRIDGE) WARN The shadow-cljs Websocket was disconnected.
(NOBRIDGE) ERROR shadow-cljs - remote-error {"isTrusted": false, "message": "Failed to connect to /192.168.254.14:9630"}
(NOBRIDGE) WARN The shadow-cljs Websocket was disconnected.
(NOBRIDGE) ERROR shadow-cljs - remote-error {"isTrusted": false, "message": "Failed to connect to /192.168.254.14:9630"}
(NOBRIDGE) WARN The shadow-cljs Websocket was disconnected.
(NOBRIDGE) ERROR shadow-cljs - remote-error {"isTrusted": false, "message": "Failed to connect to /192.168.254.14:9630"}
(NOBRIDGE) WARN shadow-cljs: giving up trying to connect to is there maybe another instance of shadow-cljs still running?
let me see
just 2 instances fighting with each other? I added protection for this a while ago, but dunno which version you are running
if this is a case of duplicate shadow-cljs servers, with one connecting and one not, that wouldn't explain why hot reloading is breaking though would it?
> just 2 instances fighting with each other? I added protection for this a while ago, but dunno which version you are running
shadow-cljs - config: /Users/alexispurslane/Development/yact/mobile/shadow-cljs.edn
=== npm package
cli: 2.28.23
config-version: 2.28.23
=== shadow-cljs version (via npm)
shadow-cljs version: 2.28.23
=== Java
openjdk version "23.0.2" 2025-01-21
OpenJDK Runtime Environment Homebrew (build 23.0.2)
OpenJDK 64-Bit Server VM Homebrew (build 23.0.2, mixed mode, sharing)
=== Source Paths
/Users/alexispurslane/Development/yact/mobile/src
/Users/alexispurslane/Development/yact/src/cljc
/Users/alexispurslane/Development/yact/src/commonjsit all depends 😛
it's old because that's what the project used
I could try updating it, but I'm afraid to do that lol
that is fairly recent, definitely has that check
okay... it looks like there may be another shadow-cljs instance. but then that's odd, since the ones I was starting werent' complaining or anything
zombies are no good, so kill that one just to be sure
it's a java process with a massive classpath list?
aw fuck no that was my figwheel instance lol
it was just loading shadow-cljs related stuff...?
well let's see if that helps
unlikely, but dunno what figwheel is doing in this setup 😛
definitely better to keep it away while debugging this
oh man you don't wanna know. I disavow any and all things related to this fucked dev environment
I was /not/ consulted
basically we have a react (reagent/re-frame) app and a react native app conjoined at the hip, sharing not just core business logic but also a lot of UI code via wrappers that are compiled from different modules based on the architecture compiled for
so I need to keep figwheel and shadow-cljs going at once so that when I make a change for web, I know it doesn't break mobile, or vice versa
we can talk about that later. for now just don't run it 😛
okay, let me rerun everything now that figwheel is gone and see what happens
just to confirm, I'm supposed to be running the shadow-cljs command, and then the expo run android command one after the other, right?
I'd wait till shadow-cljs finishes the build, then run expo
yeah that's what I'm doing
okay, no, figwheel being gone doesn't change anything
so change :output-dir "foo" and index.js to use ./foo/index.js
i.e. a completely empty new dir
still getting "android bundled ... some initial app debug logs... [big app hang] ... [the errors]"
ok will do
app/ was completely new and empty tbf
but it was somehow expected previously, so yeah
well, yeah we still need to verify that nothing references the app dir anymore
well, I assume stuff does, since I eliminated the error temporarily by just putting things in app/ where it expected them and... oh so this is interesting
okay, so I switched the output and assets dirs, then started shadow-cljs, waited for it to finish building, then started expo
and I got this message:
(NOBRIDGE) ERROR Stale Output! Your loaded JS was not produced by the running shadow-cljs instance. Is the watch for this build running?could be that expo is caching something somewhere? i.e. not using that latest output?
let me see if there are any sneaky cache directories
:asset-path is btw not an option for :target :react-native so you can just remove that. it does nothing.
ah okay
alright, I could just delete .expo again
deleting .expo does not resolve the cache message, let me look somewhere else
but! interestingly, there doesn't seem to be any error about not being able to find a module anymore
so there's that
ohhhhh
it's because when we switched to foo/ I forgot to change that in <projectdir>/index.js. Okay, back on track
nope, okay, it's still looking for things in ./app, and we still get the strange "websocket disconnected" "remote-error" /then/ "shadow-cljs #4 is ready!" stuff
so, just to verify. there is only the shadow-cljs watch running. you are not connected to the REPL via your editor or anything else?
yes
so then a grep or whatever to find app/ should show up somewhere?
I mean it must be coming from somewhere
just grep all .js files
maybe search for shadow.cljs.devtools.client.shared but that should have a lot of hits, so requires more filtering
what else is in the <project>/index.js?
maybe reference https://github.com/thheller/reagent-expo if you haven't?
okay so yeah when I ran the grep originally I didn't realize it was obeying .gitignore. there are a lot of hits looking for localhost:8081/app/<various source files, including shadow.cljs.devtools.client.shared> in out/index.js
but if it's coming from somewhere, at least so far it's way too lost in the results. I'll keep trying to filter
likely only the sourceURL for source map purposes? otherwise dunno where localhost would be coming from
yeah
e.g. # sourceURL\x3d
I didn't spot the sourceURL there at first, so I was hoping for it to be moreuseful
honestly I have no clue how any of this works even looking at https://github.com/thheller/reagent-expo
https://github.com/thheller/reagent-expo/blob/master/index.js
makes fuck all sense that this is referencing a default export that doesn't exist at all
pain
maybe just try running npx shadow-cljs compile mobile once (with no watch running)
alright, let's see
just to see if it still tries to load that file at all
it shouldn't attempt to connect to anything
makes sense given what the reagent docs say
let's see.
my computer isn't slow, neither is my phone, but this whole round trip is lke tryihng to download a 4K video over dialup
okay, so yeah, when properly compiled instead of watched, it doesn't try to reference anything external
then my only guess is that the expo stuff for some reason makes use of the sourceURL and gets the app/ from there, since that is hardcoded I guess https://github.com/thheller/shadow-cljs/blob/40d9ae9d27bc61f83e3afc76771fc17f9aa68be9/src/main/shadow/build/targets/react_native.clj#L190
just use :output-dir "app" I guess
full circle lol
FWIW the compile will also still reference that, but it won't have any reference to the shadow.cljs.devtools.client.... stuff
okay, so what about the shadow cljs server being both ready and failing to connect? I don't have a firewall on or anything
and that IP address that cljs is looking to connect to is accessible on the local wifi network
alright then lol
this is the code doing the connect logic
you can take this file and put it into your classpath into the proper location
so src/main/shadow/cljs/devtools/client/react_native.cljs or whatever source path you use
you can then add more logging to maybe figure this out
I give up 😛
thanks for your help! I'll do that and see if I'm able to figure anything out
it shouldn't even get to that line if there really is only one address
if you can repro this I can take a look, but going over this blind makes this rather hard
yeah, I'll check back if I figure out a way to reproduce this
but even replicating this escheresque project structure would be a multi-day project /hj
yeah no clue why anyone would use figwheel and shadow-cljs at the same time
😭
I'm quite inexperienced with this stuff so I'd really appreciate some pointers