Fork me on GitHub
#shadow-cljs
<
2022-01-16
>
Christopher Genovese03:01:04

I've been working on a project with shadow-cljs for the past month or two, without much issue besides occasional mysterious hangs. I did notice, however, that the watch was not recompiling on all changes (or even most). Still, it worked fine. Then this afternoon I made one change in my shadow-cljs.edn, changing the name of the exported symbol and that's it, with no other changes in the code. After that, recompiles occured on every change, as would be expected, but after every recompile things go catastrophically wrong. Sometimes all my namespaces become inaccessible at the repl, sometimes all previously defined symbols have disappeared, sometimes it's weirder -- a type that implements IFn (and gives ifn? true) has the right value but doesn't call -invoke and gives an error when used as a function, though only a moment before (pre-re-compile, with an unrelated change) it was fine. No errors are displayed at compile or in the log. I can't change anything without needing to restart. I've mostly worked in CIDER but I've tried it with the straight shadow-cljs repl too, same thing. I have no idea what's going on or why this single change to the shadow-cljs (with no other change to the code) would precipitate the problem. I've eliminated the builds and started again but after a few minutes, the problem happens again. I'm assuming that it's something else besides the config file but don't see any information pointing the right way. Perhaps I'm missing something obvious, but I'm not seeing it. Any ideas as to how to proceed would be most welcome! I can't get anything done as it is now, which is frustrating. My config is below. Let me know if there's something else I should show. Thanks for any help you can offer.

{:source-paths
 ["src/dev"
  "src/main"
  "src/test"]

 :dependencies
 [[better-cond             "2.1.0"]
  [binaryage/oops          "0.7.0"]
  [camel-snake-kebab       "0.4.2"]
  [data.deque              "0.1.0"]
  [instaparse              "1.4.10"]
  [metosin/potpuri         "0.5.3"]
  [com.rpl/specter         "1.1.3"]
  [net.cgrand/xforms       "0.19.2"]
  [org.clojure/algo.monads "0.1.6"]
  [org.clojure/core.match  "1.0.0"]
  [org.clojure/test.check  "1.1.1"]]

 :builds
 {:main {:target :node-library
         :output-to "out/yadayada.js"
         :exports {:createParser yadayada.core/create-parser}}
  :test {:target    :node-test
         :output-to "out/node-tests.js"
         :ns-regexp "-test$"
         :autorun   false}}

 :nrepl {:port 8777}

 :open-file-command ["emacsclient" "-n" ["+%s:%s" :line :column] :file]}

thheller06:01:42

@genovese do you have an actual error or so? this is all a bit abstract. config looks fine. I wrote https://code.thheller.com/blog/shadow-cljs/2019/08/25/hot-reload-in-clojurescript.html describing how hot-reload works. maybe you are doing something listed in the "things to avoid"?

Christopher Genovese15:01:31

Thanks for the reply. I realize it's abstract and seems vague. The thing is there are no specific error messages. I believe I am following all the provisos you mention in your blog post. This is a computational library so there's no persistent state, except for a debug atom I use with tap> from time to time. Here's a typical example of how things proceed: cljs.user> (nw/number-lookahead "one") "one" cljs.user> (nw/parse frame) ; unexpected result, make minor change ; like adding a tap> call [:main] Compiling ... [:main] Build completed. (82 files, 2 compiled, 0 warnings, 2.19s) cljs.user> (nw/number-lookahead "one") Execution error (TypeError) at (<cljs repl>:1). yadayada.number-words/number-lookahead is not a function At that point, everything is messed up. In this example number-lookahead is an IFn. I can see it's value but it no longer produces invoke just an error when used as a fn. Some functions or constants are seemingly inaccessible. Often, after the compile, nothing works, but it varies. I have noticed that the watch is not recompiling most of the time. The problems start when it does, but it seems odd in retrospect that the recompiles are so inconsistent. I'll grab a shot of everything that happens next time, though I'm not sure it will be much more. I'm monitoring the nrepl messages to see if something shows up there. I can work for a random stretch making changes without any recompiles and then suddenly it happens. There's a loose association with adding in tap> calls, but that neither makes sense as an explanation nor is definitive. I'm really not sure how to get a lead here. Again, I really appreciate the help and reply. Thanks. Let me know how I can further clarify. Sorry it's so vague...

thheller16:01:03

as a general tip maybe: I recommend sticking with a generic node-repl or browser-repl when doing mostly REPL driven stuff. the hot-reload tends to get in the way and is sort of at odds with the REPL

thheller16:01:15

are you changing the defn to a def with IFn maybe?

thheller16:01:22

also which shadow-cljs version is this? a few REPL bugs where fixed a while ago so older releases might still have some issues

Christopher Genovese17:01:14

Version 2.6.12. Not sure what you mean about def; it's a record that has -invoke methods on the IFn protocol. Generally works just fine then treating the object as a function, which I need in some contexts. So no defn or def in that case. On the repl type, that makes sense. The reason I've avoided it so far is that when I make changes in the code it becomes a pain to get the code up to date. If I do require :reload at the repl (or :reload-all), it often doesn't work. And I can't get namespace aliases to stick. (This seems to have something with the missing ns variable that is not defined at the repl but used in require, import, require-macros functions.) I suppose I can just reload my user.cljs. I'll try that to see if that is a workable workflow. I feel I'm doing something not quite right to have that problem.

thheller06:01:57

> Sometimes all my namespaces become inaccessible at the repl

thheller06:01:00

what does this mean?

thheller06:01:09

> sometimes all previously defined symbols have disappeared

thheller06:01:22

hot reload is expected to lose all symbols defined only in the REPL?

Christopher Genovese15:01:12

@thheller In the reply just how, I tried to clarify. Not repl-defined values but constants and functions defined in the namespace are no longer recognized at the repl. Some are, some not. Sometimes I can see them but they are not treated normally, like the IFn example I gave in reply.

Kurt Harriger03:01:10

If your browser window reloads you will loose all your state are you sure something is not causing the window to reload

thheller06:01:30

@U02RP8DDFLH the question was about a :node-library build so no browser

Kurt Harriger16:01:41

Oh I see… strangely enough I just noticed this issue this morning working on a node app for my logseq things3 plugin. Things 3 stores tasks in a local sqlite database and I wanted to query it to sync logbook to logseq, Logseq is an electron app, but plugins are sandboxed so I created this app allow me to query the database via http api instead of reading file from logseq. When I save the file, shadow-cljs recompiles and reloads the app. I need to eval the buffer again which isn’t that big a deal but my defonce vars are lost and so I need to reload the db. I cheat a bit my having a comment at the end of the code that I change from comment to do while developing which works reasonably find for me but seems is same problem. I’ve published the code at https://github.com/kurtharriger/logseq-things3-query-proxy not entirely sure how useful it is for reproducing the issue if your not using things 3 or a mac, but maybe its helpful

thheller17:01:37

its missing instructions or so? don't know what to do with this or what it is supposed to show?

Christopher Genovese15:01:11

Sorry and to clarify the first point. Namespace aliases are also all gone and often when I try to get a value in a require'd namespace it says it cannot find the namespace. (I require several namespaces with consistent aliases in my user.cljs function, which I manually load.) Those might go away on a hot reload, but when I reload the file, they are not restored. (Consistently, require at the repl also does not seem to properly define aliases, which is why I put them in user.cljs.) Does that make more sense?

Christopher Genovese15:01:22

just how -> just now