Fork me on GitHub
#shadow-cljs
<
2024-05-14
>
Roman Liutikov11:05:18

Question about shadow wrt Cloudflare: is there a way to (:require ["cloudflare:workers" :refer [DurableObject]]) such that JS import statement is emitted for "cloudflare:workers" require? Also shadow should not try to resolve the dependency since it's injected at runtime in CF env

thheller11:05:16

which :target do you use? or which :js-provider if you set one?

thheller11:05:04

depending on which the answer is either :js-options {:keep-as-require #{"cloudflare:workers"}} or :keep-as-import (e.g. for :esm)

Roman Liutikov11:05:15

Whichever is better really. Should I use :esm?

Roman Liutikov11:05:11

Hm, when I use target :esm, it seems to be compiling fine, but then CF complains about eval

▲ [WARNING] Using direct eval with a bundler is not recommended and may cause problems [direct-eval]

    out/cljs-runtime/shadow.dom.js:1439:0:
      1439 │ eval(script_body_45595);

Roman Liutikov11:05:06

actually those are just warnings, the actual error is this one

✘ [ERROR] service core:user:realtime2: Uncaught Error: Disallowed operation called within global scope. Asynchronous I/O (ex: fetch() or connect()), setting a timeout, and generating random values are not allowed within global scope. To fix this error, perform this operation within a handler. 

    at null.<anonymous> (main.js:81002:219) in shadow$cljs$devtools$client$shared$init_runtime_BANG_
    at null.<anonymous> (main.js:82802:42) in
  out/cljs-runtime/shadow.cljs.devtools.client.browser.js
    at null.<anonymous> (main.js:11:50) in __require
    at null.<anonymous> (main.js:86256:58)

Roman Liutikov11:05:07

hmm, out/cljs-runtime/shadow.cljs.devtools.client.browser.js suggests that shadow loads browser runtime here, but it's not relevant for me since the script is loaded into CF runtime

Roman Liutikov11:05:17

so I guess what I need is esm+node-script or something

thheller12:05:47

never looked at cloudflare stuff, so dunno what would be best but definitely not :browser 😛

thheller12:05:01

you can set :devtools {:enabled false} to remove all injected devtools

👀 1
thheller12:05:01

quick glance at the cloudflare docs suggests :esm might be best target

thheller12:05:47

possibly even :js-options {:js-provider :import} and letting their tools take care of bundling all JS deps https://shadow-cljs.github.io/docs/UsersGuide.html#_third_party_tool_integration

thheller12:05:35

just remember that I actually did look at it before 😛 https://github.com/thheller/cljs-cf-worker

Roman Liutikov14:05:52

nice, disabling devtools works!

janezj12:05:13

Today I solved the advanced compilation problem i. But I can not explain why the code is now properly compiled.

(defn polygon->array [^js polygon-ref]
  ;; ------------------
  ;; there is a compiler warning, when all in one expression
  #_(some->> polygon-ref
             .-current
             .-state
             .-polygon
             .getPath
             .getArray
             (map (fn [ll] [(.lat ll) (.lng ll)])))
  ;; ------------------ this part is ok
  (let [^js polygon (some-> polygon-ref
                            .-current
                            .-state
                            .-polygon)
        _ (set! js/ppp polygon)                  ;; checked on console, there are .getPath and .getArray
   ;; -- but this part must be evaluated separately
         #_#_coor-ring (some->> polygon
                 .getPath
                 .getArray
                 (map (fn [ll] [(.lng ll) (.lat ll)])))
   ;; this works     
        ^js pp (.getPath polygon)
        arr (.getArray pp)
        coor-ring (map (fn [ll] [(.lng ll) (.lat ll)]) arr)
   ;; this is not problematic   
        f (first coor-ring)
        coor-ring (if (not= f (last coor-ring))
                    (concat coor-ring [f])
                    coor-ring)]
        (into [] coor-ring)))

thheller12:05:50

did you not get extern inference warnings?

thheller12:05:34

externs are needed and the compiler should warn you where

janezj12:05:49

No, I did for the first version. But polygon-ref (hooks/use-ref ) is ^js tagged. (some->> polygon-ref .-current .-state .-polygon .getPath .getArray (map (fn [ll] [(.lat ll) (.lng ll)])))

thheller12:05:32

I don't think I have ever used some->>, so could be that it maybe not properly propagates the ^js tag

janezj13:05:41

is there a way how to check if ^js is propagated, sometjong like assert-js, or spy-js? so it can be injected in thread macros. (some->> polygon-ref .-current .-state .-polygon .getPath .getArray `spy-js` (map (fn [ll] [(.lat ll) (.lng ll)])))

thheller13:05:35

if you get warnings that means its not propagated

thheller13:05:39

thats your check

thheller13:05:13

^js is purely a compiler thing. it has no meaning whatsoever at runtime

thheller13:05:51

I'd say just don't use some->>. In interop forms its best to be a bit defensive

thheller13:05:14

or if you insist you can take this over to http://ask.clojure.org and turn it into a proper ticket for CLJS itself

thheller13:05:19

this is likely not something shadow-cljs specific

janezj14:05:30

you are right, some-> is problematic, but it is strange, that in my case real case code is compiled without warning. I can not reproduce it in a simple case. But it is a surprise, that I have to tag towel to compile in the first expression. and symbols must have a bit longer names to trigger minification. (let [`^js` towel (`clj->js` {:aaaaa {:bbbbb {:ccccc {:ddddd 42}}}})] (pr-str [(-> towel .-aaaaa .-bbbbb .-ccccc .-ddddd) (->> towel .-aaaaa .-bbbbb .-ccccc .-ddddd) #_(some-> towel .-aaaaa .-bbbbb .-ccccc .-ddddd) #_(some->> towel .-aaaaa .-bbbbb .-ccccc .-ddddd)]))

thheller14:05:34

no clue what this is supposed to be

janezj14:05:10

towel is javascript object towel.aaaaa.bbbbb.ccccc.ddddd === 42 and then i am extracing 42 with 4 macros towel is not recognized as ^js but it is created by clj->js

thheller14:05:09

yes but what are you trying to show? all of those should yield inference warnings

thheller14:05:53

we have externs inference since the compiler cannot know if it should preserve the property names or if its safe to let them get renamed

thheller14:05:10

so ^js tells the compiler to not rename stuff

thheller14:05:42

using clj->js does not automatically mean "don't rename any of this", which also the compiler couldn't possibly determine since most uses will be (clj->js some-data) and not a hardcoded nested structure 😛