Fork me on GitHub
#shadow-cljs
<
2022-06-10
>
johndoe13:06:49

Does clojurescript compile modules independent from each other? I couldn't resolve qualified symbol inside my macros - it's constantly nil. (All modules are cljc). Unqualified symbols are resolve properly. Although namespace of that symbol is mentioned in require section of namespace from which I call macros.

johndoe13:06:32

Short snippet for context

(ns cxa.core
  (:require [cx.backend.web :as cx]
            [cxa.todomvc]
            [cxa.counters]))

(defonce root (atom nil))

(cx/def<> app #{example}
  [:div
   [:div
    [cx/for [[key title] [[:counters "counters"]
                          [:todomvc "todomvc"]]]
     [:label
      [:input {:name "example"
               :type "radio"
               :value key
               :on/change #(cx/!! (fn [{:keys [key]}]
                                    {:example key}))}]
      title]]]
   [cx/case example
    :counters [cxa.counters/app]
    :todomvc  [cxa.todomvc/app]
    "nothing selected"]])

(defn rebind [old]
  (when old (doto old (cx/detach) (cx/dispose)))
  (doto (cx/create app)
    (cx/attach (.-body js/document) nil)))

(defn main []
  (swap! root rebind))
I couldn't resolve particularly cxa.counters/app and cxa.todomvc/app inside cx/def<> macro. Everything works correct only if move all stuff to single namespace.

thheller16:06:53

what do you mean by resolve? I mean what does your macro look like?

johndoe16:06:28

By resolve i mean literally (clojure.core/resolve sym) call. My macro is a compiler of hiccup-like trees doing same stuff as svelte. I keep a bit of compile-time information about generated components for some checks to ensure they correctly used.

johndoe16:06:15

I know that clojure and cljs namespaces are completely isolated, so keep compile-time info in clojure namespace with same names and vars with same symbols as in cljs.

johndoe16:06:02

By the way I think problem is not where I thought.

johndoe16:06:57

Seems like a tree-shaking eliminates my namespaces for some reason and I even can't stable reproduce it. Issue with unresolvable symbols arises randomly between restarts of cljs watch.

johndoe16:06:54

Have no idea how to debug this 😞

johndoe16:06:29

Successful build after restart, have added empty lines (!) in one of namespaces, and it blow up. And it could vise versa.

shadow-cljs - config: /mnt/dataf/projects/stuff/shadow-cljs.edn
shadow-cljs - HTTP server available at 
shadow-cljs - server version: 2.16.7 running at 
shadow-cljs - nREPL server started on port 42155
shadow-cljs - watching build :app
[:app] Configuring build.
[:app] Compiling ...
[:app] Build completed. (142 files, 0 compiled, 0 warnings, 2.12s)
[:app] Compiling ...
[:app] Build failure:
------ ERROR -------------------------------------------------------------------
 File: /mnt/dataf/projects/stuff/src/cxa/core.cljc:9:1
--------------------------------------------------------------------------------
   6 |
   7 | (defonce root (atom nil))
   8 |
   9 | (cx/def<> app #{example}
-------^------------------------------------------------------------------------
An error occurred while generating code for the form.
ExceptionInfo: failed compiling constant: cx.trees.specials.core$reify__28843@19b2a12b; cx.trees.specials.core$reify__28843 is not a valid ClojureScript constant.
        cljs.compiler/fn--3374 (compiler.cljc:306)
        cljs.compiler/fn--3374 (compiler.cljc:303)
........
        cljs.compiler/emit-let/fn--3750 (compiler.cljc:1099)
        cljs.compiler/emit-let (compiler.cljc:1085)
        cljs.compiler/emit-let (compiler.cljc:1081)
        cljs.compiler/fn--3761 (compiler.cljc:1106)
        cljs.compiler/fn--3761 (compiler.cljc:1105)
        clojure.lang.MultiFn.invoke (MultiFn.java:229)
        cljs.compiler/emit (compiler.cljc:204)
        cljs.compiler/emit (compiler.cljc:184)

--------------------------------------------------------------------------------
  10 |   [:div
  11 |    [:div
  12 |     [cx/for [[key title] [[:bmi "BMI calc"]
  13 |                           [:counters "counters"]
--------------------------------------------------------------------------------

johndoe17:06:57

I keep a comp-time info in atom and have changed def to defonce and a problem have gone :thinking_face: It's strange because this namespace clj-only (not cljc) and I have not expect it would suddenly reload (with erase of previously accumulated info in the atom) without obvious reason like changed code inside of it. In the same time cljs watch doesn't look into required namespaces that haven't change and there is no chances to re-accumulate info again.

johndoe17:06:12

cljs macros is a mess

thheller17:06:43

cljs macros are not a mess

thheller17:06:49

using them incorrectly creates a mess

thheller17:06:11

without knowing what you are doing I can't give advice on what might be wrong

thheller17:06:41

> Seems like a tree-shaking eliminates my namespaces

thheller17:06:53

watch does no tree-shaking whatsoever. not even attempts to.

thheller17:06:25

> cx.trees.specials.core$reify__28843 is not a valid ClojureScript constant

thheller17:06:47

means that you can't use the result of a CLJ (reify ..) call and expect that to produce JS

thheller17:06:55

so likely you are missing a quote or so

thheller17:06:21

> I keep a comp-time info in atom and have changed def to defonce and a problem have gon

thheller17:06:36

don't do this

thheller17:06:03

if you want to you must disable all caching, as otherwise compilation results may be cached

thheller17:06:14

and that wouldn't re-populate whatever extra atom you have

thheller17:06:44

also clojure.core/resolve only knows how to resolve CLJ vars

thheller17:06:59

it has no knowledge or concept of CLJS vars, so it can never resolve them

thheller18:06:06

for that there is cljs.analyzer/resolve-var

johndoe18:06:17

> don't do this But this works somehow :thinking_face: Is this wrong assumption that defonce atom inside clojure namespace (not cljs namespace) will be preserved during cljs compilation (and cljs watch lifetime)? > cljs.analyzer/resolve-var I use this one too for translate cljs symbols into qualified ones and using them resurrect a comp-time info generated by my macro.

thheller18:06:25

as I said. you must disable caching if you do this. the cache will not restore whatever is in your atom

thheller18:06:37

so if you stop a watch and start a new one things will be missing

thheller18:06:47

during a watch it stays available yes

johndoe18:06:23

quickly looked at documentation and it's surprising but this caching issue mentioned there and even with library example - clara-rules. thank you

thheller18:06:37

what are you storing in the atom? maybe you don't actually need the atom and can just look stuff up in the analyzer data?

johndoe18:06:22

a set of slots (https://svelte.dev/tutorial/slots) which component accepts for every previously compiled component. so it's a mapping {ns/sym -> #{slots}}

thheller19:06:20

if its just data you can get it from the analyzer data

thheller19:06:35

and get it into there via metadata on the created var

johndoe19:06:52

metadata will be erased in resulted js? I need this info only for compile time

johndoe19:06:44

also slots set is result of hiccup analyzing

thheller19:06:06

yes, metadata does not make it into the JS

thheller19:06:50

I assume you create some (def ~name-of-something ...)

thheller19:06:11

you can (var-meta name-of-something assoc :slots the-hiccup-data)

thheller19:06:39

and then get it from the compiler env in [:cljs.analyzer/namespaces that.ns :defs name-of-something :meta]

thheller19:06:52

that data would be safe in cache

johndoe19:06:45

wow. i'll try. thank you very much!

salam15:06:59

is there a way to override a configuration item in shadow-cljs.edn (e.g., nrepl: false) with a command line argument to shadow.cljs.devtools.cli?

thheller16:06:13

@abdusalam no, not currently. there is --config-merge for overriding build config stuff but not global options like nrepl

salam19:06:15

ok. thanks, Thomas.