shadow-cljs

Lane Spangler 2025-01-23T16:32:21.818749Z

hey all, I'm wondering if it's possible to check the build configuration (target) when expanding a macro. Maybe this is also the wrong approach to solving my problem (more context in the thread).

Lane Spangler 2025-01-23T16:34:55.597879Z

I'm trying to create one Clojurescript codebase for both web and mobile (using react-native). The app initialization logic varies between targets, so my idea was to create a macro to render the root component depending on the build target.

thheller 2025-01-23T16:35:22.849329Z

don't do that

thheller 2025-01-23T16:35:44.686789Z

instead create a dedicated namespace per target, so your.app.web and your.app.native or something

thheller 2025-01-23T16:36:24.567729Z

then one build for each using the dedicated namespace, not including the other at all

thheller 2025-01-23T16:37:10.508009Z

could do something like this if you want to abstract it further https://gist.github.com/thheller/fa044450a6470fdd1afdbcf3f37a65e3

Lane Spangler 2025-01-23T16:40:07.060349Z

ok, thank you

bru 2025-01-23T17:25:39.403039Z

Hi there! For the first time in a long long time, I'm getting the infamous "x(...).yy is not a function" error in advanced compilation when calling some (but not all) functions from an external library. Any hints on where to start debugging this? the relevant portion of my shadow-cljs.edn file looks something like this:

:js-options
   {:js-provider :external
    :external-index "target/libs.js"
    :external-index-format :esm}

thheller 2025-01-23T18:51:10.816949Z

did you properly handle all extern inference warnings?

thheller 2025-01-23T18:51:35.074079Z

best way to quickly identify what .yy was is using npx shadow-cljs release the-build --pseudo-names

bru 2025-01-23T18:51:43.245049Z

I think so, in the sense that I had none.

thheller 2025-01-23T18:52:07.093119Z

that'll make that propery something like .$something$ when it was .something origninally. usually that is pretty distinct and should lead you to the problem quickly

bru 2025-01-23T18:52:12.148949Z

I'm now trying to figure out what's changed in the library 🙃

bru 2025-01-23T18:52:29.695249Z

a-ha, thanks for that one liner, I'll check immediately

bru 2025-01-23T19:01:16.493669Z

hm, the "missing" method has been there for a while... I wonder if I anything changed in vite (that's what orchestrates the bundling), but it's code I haven't touched in ages

thheller 2025-01-23T19:02:21.369369Z

if you updated the dependencies it is very common for JS libs to just change their api randomly

thheller 2025-01-23T19:02:36.463169Z

but the vite parts have absolutely zero to do with externs issues?

bru 2025-01-23T19:04:20.376789Z

yeah, I learned that the hard way one time too many 🙂 regarding vite... ok I may be looking at this from the wrong angle then

thheller 2025-01-23T19:05:28.900469Z

I'm assuming that you actually get a renamed reference. since you mentioned x(...).yy is not a function. so the advanced compiled bits renamed the function access, but vite still only provides the actual old name

thheller 2025-01-23T19:06:09.776169Z

so there is a mismatch and the name cannot be found. only way to fix it is to have the advanced compile not rename that property. normally externs inference should have warned you about it.

bru 2025-01-23T19:10:04.279149Z

why is it all so clear when you explain it? 🙂

bru 2025-01-23T19:11:31.639479Z

the object I'm trying to call that function from lives in an atom. Can that explain the lack of warnings?

thheller 2025-01-23T19:12:09.476389Z

not without some code. atom part is pretty much irrelevant

bru 2025-01-23T19:12:28.884649Z

that's what I thought

thheller 2025-01-23T19:13:18.940429Z

dunno which shadow-cljs version you are using. maybe try upgrading. there have been a couple tweaks for externs inference of the years

bru 2025-01-23T19:14:43.398999Z

yeah, I'm on the latest. The thing that surprises me the most is that method is not special at all. There are plenty like that one that I call elsewhere in the app 🤔 having said that, I'll actually verify this assumption next

thheller 2025-01-23T19:15:55.691269Z

did you identify the actual name? via --pseudo-names? don't assume, verify before doing anything else. extern issues can be tricky to track down when following from the wrong start 😉

👍 1
bru 2025-01-23T19:16:30.710549Z

yes, I have the name

bru 2025-01-23T19:18:54.566149Z

uuuh... there is one thing that's special: it's one of a bunch of methods that are added to the object by another class (to give you minimal context, it's a modular editor of sorts, each module enriches the main View object)

thheller 2025-01-23T19:19:16.278279Z

none of that matters

bru 2025-01-23T19:19:27.995399Z

great

thheller 2025-01-23T19:20:06.273479Z

it is literally only that there is a x.something but the advanced code is looking for x.yy. it doesnt matter what it comes from

bru 2025-01-23T19:23:55.512799Z

of course, apologies for mixing things up. I'll re-read the user guide section

bru 2025-01-23T19:25:51.930639Z

it's definitely all type hinted though 😕 this is the line that fails: (defn get-match-index [] ^number (.findGetActiveMatchIndex ^js @view))

thheller 2025-01-23T19:27:03.624269Z

hmm try moving the deref out, not entirely sure this typehint transfers correctly for the @. I assume it does, just not sure

bru 2025-01-23T19:27:23.806279Z

hang on...

thheller 2025-01-23T19:27:31.690149Z

(let [^js x @view] (.findGetActiveMatchIndex x))

bru 2025-01-23T19:28:08.528509Z

It looks like it's the ^number hint! If I remove it works

thheller 2025-01-23T19:28:41.854349Z

hmm odd

bru 2025-01-23T19:28:57.285909Z

I'll do some more tests

thheller 2025-01-23T19:28:58.790679Z

(defn get-match-index ^number [] (.findGetActiveMatchIndex ^js @view)) should be ok with the same effect

bru 2025-01-23T19:30:49.546649Z

yes, that works 🎉

bru 2025-01-23T19:33:06.913209Z

thanks aplenty. Time to look for other similarly misplaced hints 👋

👍 1