Fork me on GitHub
#shadow-cljs
<
2022-12-30
>
michihuber14:12:37

I'm currently migrating to shadow-cljs (from using cljsbuild directly for prod, lein-figwheel for dev) and have some issues with promises that I handle through <p!. I require core.async like this:

[cljs.core.async :as async :refer [go >! <!]]
            [cljs.core.async.interop :refer [<p!]]
and work with promises like this (heavily abridged)
(let [p+ (.readFile ^js (.-promises ^js FS) dict-path)]
  (try (go (let [p (<!p p+)] ...))
       (catch default e (println e)))
which prints the error
TypeError: aa.setTimeout is not a function
so it feels like I'm missing externs for core.async? any ideas? /cc @thheller

thheller16:12:27

hard to say. core.async does not require externs. what is the full stacktrace? not sure where setTimeout is used? and which build :target is this?

michihuber16:12:23

build target is browser, though that could be it - this is the main process script for an electron app

michihuber16:12:31

would nodejs be more suitable?

thheller17:12:19

I don't know. electron has a bunch of different contexts. not all have the regular JS primitives like setTimeout available

thheller17:12:54

is this a release build or a watch/compile dev build?

michihuber17:12:49

this is a release build. it used to run with a vanilla cljs.build build, so I feel browser should work as a target?

thheller17:12:32

try running the build with npx shadow-cljs release app --pseudo-names to figure out what the aa is supposed to be

thheller17:12:54

for the regular electron "renderer" process a :browser build is fine

michihuber17:12:06

ah, scratch that, we used :target :nodejs

michihuber17:12:19

should this be :node-script then?

thheller17:12:19

yeah, that won't work for the renderer

michihuber17:12:32

no, this is for the main process, not renderer

thheller17:12:34

:target :nodejs doesn't exist in shadow-cljs

thheller17:12:44

that should be :node-script yes

michihuber17:12:50

ok, will try that

michihuber17:12:49

I think it worked 🎉 thanks so much

michihuber17:12:19

one more thing (well, I'm sure there will be more)... some externs aren't inferred, but also don't complain on compilation

michihuber17:12:22

what could cause that?

thheller17:12:18

I can't say. not enough info

michihuber17:12:00

we often pass in js objs (e.g. node Path) as args, could this be the culprit?

thheller17:12:37

I can't say. need actual code examples. there are a billion things you could be doing

michihuber17:12:28

(defmethod integrant/init-key :app.system/x [_ system]
  (let [{:keys [App]} system]
    (.setAsDefaultProtocolClient App "foo")

michihuber17:12:42

e.g. this did not warn about App

thheller17:12:05

seems like it should

michihuber17:12:35

ok, will dig deeper

michihuber17:12:43

next year 🙂 guten rutsch!!

🎉 1
mkvlr16:12:03

what’s the simplest way to compile some cljs snippet from the clojure repl? Or asked differently, could I call cljs.analyzer.api/emit and cljs.analyzer.api/analyze and with what state/env args so it knows symbols from my running shadow build?

thheller16:12:56

compile or eval?

mkvlr16:12:09

only compile

mkvlr16:12:53

(I’ve used shadow.cljs.devtools.api/cljs-eval but I only want the js code, not the result)

thheller16:12:15

best open is probably using the shadow.build api directly

thheller16:12:37

after that there is a :repl-state key in the build state, which contains a bunch of :repl-actions

thheller16:12:03

basically all of those need to happen before the last repl/process-input can be eval'd

thheller16:12:15

but its all just compiled, no eval JS env required

thheller16:12:03

very low level though

mkvlr16:12:16

can I also use the running shadow watch and compile a string as if came in the end of my file?

thheller16:12:18

but there aren't many repl-actions and they are sort of self explanatory

thheller16:12:00

I mean in theory yes, but none of the targets have the necessary hooks or functionality to do that

mkvlr16:12:21

and there’s no cljs.analyzer.api/analyze compatible state/env available either with shadow, is that right?

thheller16:12:05

well the context matters here

thheller16:12:13

you cannot just mess with a watch and expect it to work

thheller16:12:25

watch after all manages a build-state in a very specific way

thheller16:12:56

if you just take it out and mess with it there is no way to "put it back"

thheller16:12:04

but yes, you can take it out and mess with it

mkvlr16:12:21

so for Clerk’s render functions are currently quoted form that are evaluated through sci

mkvlr16:12:23

now trying to figure out if I can alternatively support proper compiled cljs

mkvlr16:12:36

which means I need to compile some of those quoted forms…

thheller16:12:38

well you can do anything with the shadow.build api, its just not documented much

borkdude16:12:09

@mkvlr if the quoted form is known at compile time, why do you even quote it and not just compile it as regular cljs?

mkvlr16:12:41

@borkdude that’s all I’m trying to do in a first step

mpisanko16:12:32

seems like that's a recurring problem, but.. trying to use @openfin/excel - and getting the following problem:

WARN:
shadow-cljs - failed to load module$node_modules$$openfin$excel$openfin_excel
shadow.js.jsRequire @ js.js:74
shadow.js.require @ js.js:113
eval @ app.excel.js:2
goog.globalEval @ main.js:566
env.evalLoad @ main.js:1659
(anonymous) @ main.js:2574

main.js:1661 An error occurred when loading app.excel.js
env.evalLoad @ main.js:1661
(anonymous) @ main.js:2574

ReferenceError: fin is not defined
    at shadow$provide.module$node_modules$$openfin$excel$openfin_excel (:3900/js/cljs-runtime/module$node_modules$$openfin$excel$openfin_excel.js:17:34)
    at shadow.js.jsRequire (:3900/js/cljs-runtime/shadow.js.js:34:18)
    at shadow.js.require (:3900/js/cljs-runtime/shadow.js.js:59:20)
    at eval (:3900/js/cljs-runtime/app.excel.js:2:64)
    at eval (<anonymous>)
    at goog.globalEval (main.js:566:21)
    at env.evalLoad (main.js:1659:12)
    at main.js:2574:12
using shadow-cljs 2.11.5 tried changing https://shadow-cljs.github.io/docs/UsersGuide.html#js-provider and https://shadow-cljs.github.io/docs/UsersGuide.html#alt-node-modules any ideas?

thheller16:12:10

sorry never used that lib. don't know what fin is supposed to be. looks to be expecting to be running in excel? but looks like you are running this in a browser?

mpisanko08:01:15

it's excel adapter - translating JS to some .net API i think. it's present when you run with the openfin container - but this happens when loading code that simply requires the dependency (invocation is wrapped in an (exists? js/fin) check - so it never gets called).

mpisanko15:01:20

solved the issue by splitting modules (so i can isolate those dependencies which require special runtime) - and including that from a HTML script element - when needed. potentially could have done shadow-cljs https://shadow-cljs.github.io/docs/UsersGuide.html#_dynamic_module_import? but using target :browser so will just stick with this approach. cheers!

seanstrom17:12:08

I have a question about avoiding these kind of errors: throw new Error('Namespace "' + name + '" already declared.'); I'm basically trying to use ViteJS and ShadowCLJS together but the hot reloading of Vite wants to recall goog.provide for everything when my ShadowCLJS ESM modules changes. I found an https://github.com/minimal-xyz/minimal-shadow-cljs-webpack/blob/master/lib/page.js#L1-L5 that might workaround the issue, but I wanted to check with anyone if that seems correct, or if there is a better way to avoid calling all of the goog.provide functions again. Thanks in advance 🙏

thheller17:12:54

I don't recommend using the vite reloading together with shadow-cljs. it is very likely to break everything. why not just let shadow-cljs reload its code?

seanstrom17:12:47

Well I'm trying to hot reload custom JS components with Vite but ignore the Shadow-CLJS ESM module somehow and just let Shadow handle that. But that's tricky because Vite sees the shadow module changing and triggers a recall of those provide functions. Is there a reason to not always override goog.provide?

thheller17:12:22

should be fine for dev but might mess up release builds

seanstrom17:12:58

Okay sounds good, would I patch goog in my main entry point for CLJS?

thheller17:12:17

anywhere before the first vite reload kicks in is fine

seanstrom17:12:24

okay sounds good! thank you for helping

seanstrom08:12:56

Hey do you mind if I clarify something about how to patch goog?

thheller12:12:57

you just put the code I linked in a file and call it

zalky17:12:59

Hey there, I have two builds, each with an http dev server defined. But they both appear to launch, even when I'm only launching one build:

{:test {:target   :browser-test
        ...
        :devtools {:http-port 8021 ...}}
 :dev  {:target   :browser
        ...
        :devtools {:http-port 8022 ...}}}
Only launching :dev:
$ clojure -M:cljs/dev:cljs/client watch dev
shadow-cljs - HTTP server available at 
shadow-cljs - HTTP server available at 
shadow-cljs - server version: 2.20.2 running at 
shadow-cljs - nREPL server started on port 60050
shadow-cljs - watching build :dev
[:dev] Configuring build.
[:dev] Compiling ...
[:dev] Build completed. (512 files, 0 compiled, 0 warnings, 4.21s)
Am I doing something wrong?

thheller17:12:54

http servers are not build related and the config in the build config has been deprecated for 5+ years now. use https://shadow-cljs.github.io/docs/UsersGuide.html#dev-http instead

👍 1
thheller17:12:03

they are meant to always run, so you can use them for release or compile builds as well as watch

zalky18:12:29

Gotcha, thanks for the clarification.