shadow-cljs

https://github.com/thheller/shadow-cljs | https://github.com/sponsors/thheller | https://www.patreon.com/thheller
grav 2020-09-04T07:45:33.087800Z

When I want to hack on my node app, I first start up Shadow in watch mode. Then I need to wait a bit until Shadow is done compiling, before starting the node process. Can I automate this in some way?

Chris McCormick 2020-09-04T07:48:15.088500Z

@grav you can try something like this:

srv=build/server.js
# run the server under node
( rm -f ${srv}; while [ 1 ]; do if [ -f ${srv} ]; then node ${srv}; else sleep 1; fi; done ) &
# watch-and-compile the server
( npx shadow-cljs watch server ) &
here the node script artifact being built is build/server.js

grav 2020-09-04T07:49:03.089500Z

Ah, good idea. So simply remove the build artifact and then wait for it to show up!

👍 1
Chris McCormick 2020-09-04T07:49:06.089700Z

at the end of the script i have a wait and run everything as background tasks. at the start of the script i have this:

trap killgroup SIGINT

killgroup(){
  echo killing...
  kill 0
}
which kills everything launched in the script when ctrl-C is run

Chris McCormick 2020-09-04T07:49:19.090Z

probably i should document this somewhere

grav 2020-09-04T07:50:35.090400Z

Great hack! Thanks a bunch @chris358 🙂

👌 1
thheller 2020-09-04T07:51:57.091100Z

or use shadow-cljs node-repl and go from there 😉

grav 2020-09-04T08:05:27.092800Z

@thheller So you mean use Clojure instead of Bash? Sounds tempting :-) I haven't used the shadow api much, apart from (shadow/watch :my-app). But that doesn't seem to work in a node-repl? Am I mis-reading https://shadow-cljs.github.io/docs/UsersGuide.html#node-repl?

thheller 2020-09-04T08:11:23.093100Z

I do not know what you read from that

thheller 2020-09-04T08:12:21.094100Z

you just get a blank CLJS REPL that isn't tied to your :my-app build but can still just (require '[<http://my.app|my.app> :as x]) and (x/main "foo" "bar") or so (emulating a regular :node-script build for example)

thheller 2020-09-04T08:13:00.094600Z

node-repl just manages the node process so you don't have to use hacks to wait for files to appear or so

thheller 2020-09-04T08:13:14.094900Z

just gives you the regular clojure-like REPL experience

hoppy 2020-09-04T11:14:23.096100Z

probably doing something horribly wrong, but this seemed like it used to work.

hoppy 2020-09-04T11:15:04.096700Z

now getting TypeError: ia.format is not a function in release, but works in repl. Obviously getting minified away. Any good way to avoid?

thheller 2020-09-04T11:53:12.097500Z

@hoppy you were probably relying on some of your :preloads loading goog.string.format

thheller 2020-09-04T11:53:25.097900Z

just add it to your :require in the ns

thheller 2020-09-04T11:53:59.098500Z

format is actually it its own "namespace". looks a bit weird but works

hoppy 2020-09-04T12:10:48.098600Z

ok, this works. I'm not sure I understand why, or whether I need to.

hoppy 2020-09-04T12:10:56.099Z

but thanks

thheller 2020-09-04T12:17:43.099200Z

...

thheller 2020-09-04T12:17:48.099400Z

dont remove the first one

thheller 2020-09-04T12:18:07.099600Z

(ns my-app.core
  (:require [goog.string :as gstring]
            [goog.string.format]))

thheller 2020-09-04T12:18:13.099800Z

I know its weird .. blame the closure library

thheller 2020-09-04T12:18:46.100500Z

you need to because goog.string and goog.string.format format are basically 2 namespaces

thheller 2020-09-04T12:18:57.100800Z

but for some reason goog.string.format is not actually a namespace, only a function

thheller 2020-09-04T12:19:20.101200Z

but it is in its own file so it needs to be required properly

hoppy 2020-09-04T12:20:28.101900Z

neato 😜

hoppy 2020-09-04T12:21:06.102600Z

you are probably right though, I dug that code out of a different working project, so it was probably osmosis of some sort.

hoppy 2020-09-04T12:21:12.102800Z

thanks again for the help

thheller 2020-09-04T12:21:54.103300Z

yeah it works by accident if goog.string.format was required anywhere else but its not something you should rely on so the :require fixes that

Jakub Holý 2020-09-04T15:24:49.105500Z

Hello! When I make a simple change to my app, it takes Shadow 3-7 seconds to recompile the change, after which the app re-renders. Is that duration normal? Or do I use too many libraries or is the changed UI namespace too large? What can I do to speed it up, so that I can change the code (add a new dom element, change button label, ...) and see the change "at once"? Thank you!!!

wilkerlucio 2020-09-04T15:46:11.106200Z

IME keeping files small makes a good difference for compilation times, so it potentially has less things to compile

wilkerlucio 2020-09-04T15:47:14.106400Z

3-7 seconds seems a very high time for me, in the biggest project I worked on (30k+ LOC), we were still getting compilations in 500ms avg (except when touching some of the big files, there it could go up to 3 seconds, but rarely more than that)

thheller 2020-09-04T16:37:11.107600Z

@holyjak that seems excessive and shouldn't be that slow. complex macros can significantly impact recompile speeds. maybe try running with shadow-cljs watch app --verbose or use the UI to see where it spends its time

❤️ 1
Jakub Holý 2020-09-05T18:31:28.117200Z

No. no big EDN. kostnadsdeling/ui has 593 lines, 31KB, and 13 direct macro calls, namely Fulcro's defsc . minbedrift/ui has 3KB and 75 lines (and includes the kostnadsdeling.ui namespace and others).

Jakub Holý 2020-09-05T18:35:05.117500Z

After really upgrading to 2.11.1 I get

&lt;- Cache write: minbedrift/ui.cljc (709 ms)
&lt;- Compile CLJS: minbedrift/ui/kostnadsdeling/ui.cljc (1339 ms)
&lt;- Cache write: minbedrift/ui/kostnadsdeling/ui.cljc (552 ms)
after a trivial code change

thheller 2020-09-06T18:52:00.127200Z

source file size doesn't necessarily mean much if there is a macro in it expanding to something huge

thheller 2020-09-06T18:52:12.127400Z

check the generated .js file for the size

thheller 2020-09-06T18:56:30.127600Z

it might also just be something in your system intefering with file writing

thheller 2020-09-06T18:56:41.127800Z

anti virus or that kind of stuff is often the cause

thheller 2020-09-06T18:56:51.128Z

scanning all newly written files making everything slow

👀 1
thheller 2020-09-06T18:57:42.128200Z

I'm not on macos but on windows the windows defender thing is causing such issues and performance goes up significantly if the project dir is just ignored

Jakub Holý 2020-09-07T16:09:07.143900Z

Thanks, I will try that!

Jakub Holý 2020-09-04T16:46:25.107800Z

Thanks! Perhaps something is wrong with my setup, I will clean up everything and upgrade shadow to latest.

Jakub Holý 2020-09-04T17:49:38.110200Z

I guess my shadow issues are related to the following problem logged in the browser console, which I have not seen before (on a project I haven't used for a 2-3 months): > failed to parse websocket message {:type :repl/init, :repl-state {:shadow.cljs.repl/repl-state true, :current-ns cljs.user, :repl-sources [...], :repl-actions []}} #error {:message "Invalid reader tag: :type. Reader tags must be symbols.", :data {:type :reader-exception, :ex-kind :reader-error}} Any idea what could be wrong / where to look? I have just upgraded to shadow 2.11.1, deleted node_modules and .shadow-cljs, and installed/started from scratch.

Jakub Holý 2020-09-04T17:54:20.110300Z

Here is the verbose log:

[:main] Compiling ...
&lt;- Resolving Module: :main (171 ms)
&lt;- Compile CLJS: minbedrift/ui.cljc (118 ms)
&lt;- Compile CLJS: minbedrift/ui/kostnadsdeling/ui.cljc (1460 ms)
&lt;- Cache write: minbedrift/ui.cljc (852 ms)
&lt;- Cache write: minbedrift/ui/kostnadsdeling/ui.cljc (1370 ms)
&lt;- build target: :browser stage: :compile-finish (312 ms)
&lt;- Flushing unoptimized modules (2066 ms)
&lt;- build target: :browser stage: :flush (2465 ms)
[:main] Build completed. (1076 files, 2 compiled, 0 warnings, 6.64s)
I think I saw much better compile times on this app before summer so something in the environment must have changed...

thheller 2020-09-04T19:19:22.110700Z

@holyjak uhm that doesn't look like 2.11.1? do you use project.clj or deps.edn and didn't upgrade there?

😅 1
thheller 2020-09-04T19:39:12.110900Z

well thats defienitely slow. what does minbedrift/ui/kostnadsdeling/ui.cljc do? macro heavy stuff? maybe including huge edn data?

thheller 2020-09-04T19:40:08.111100Z

Cache write: minbedrift/ui.cljc (852 ms) is also quite slow

thheller 2020-09-04T19:40:13.111300Z

how big are these files?

Jakub Holý 2020-09-04T19:47:13.111600Z

thank you! What about package.json? Does the version been manually synced between this and deps?

thheller 2020-09-04T19:52:46.111800Z

if you use deps.edn then you need to update deps.edn

thheller 2020-09-04T19:53:15.112Z

the npm version in package.json should be somewhat close since things may break if they are too far apart

👍 1