Fork me on GitHub
#shadow-cljs
<
2020-04-28
>
Lucy Wang02:04:43

@pshar10 I think kaocha and shadow-cljs doesn't work well together at the moment

Lucy Wang02:04:31

@thheller do you think it's a good idea to add support of a "pre/post-css-update-hook"? I have some animation defined in css and each time the css is live updated, the page would go through the animation process which is time consuming.

Lucy Wang02:04:15

The idea is to I want to call some custom code before handle-asset-watch , e.g. add a '.disable-animation' class to the html body to make sure the animation rules is not in effect, and remove this class after the css update.

thheller06:04:28

@pshar10 no kaocha-cljs does not work with shadow-cljs yet. talked with the author yesterday and there are plans to get this working but nothing as of yet.

andre06:04:45

hi is this something known ?

andre06:04:59

in edn i have

:http-port  3000

thheller06:04:37

@andre this is caused by a core.async dependency conflict when using deps.edn/project.clj

thheller06:04:55

make sure you don't use an ancient core.async version, should be [org.clojure/core.async "1.1.587"]

andre06:04:19

yeah i have [org.clojure/core.async "0.7.559"] in project.clj, thanks

andre06:04:56

but I have only one terminal with the project on port 3000 why does it say 3000 and 3001 are in use ?

andre06:04:57

"1.1.587" didn't help, same Exception

thheller06:04:01

because something is running on those ports 😛 can't tell you what

thheller06:04:02

make sure you don't have any other conflicts too. maybe you have some leftover AOT cache as well?

andre06:04:10

this Exception started to happen when these ports appears, but the interesting thing I can open these ports and I can see another shadow-cljs project but they are not running in any terminal

thheller06:04:34

every time someone has reported an error like this it was related to some dependency conflict. not sure what else it would be

thheller06:04:55

and maybe just kill those processes if you don't want them?

thheller06:04:15

@wxitb2017 wouldn't it be more practical if you start with a <body class="load-anim"> or so and then remove that class yourself at some point? I didn't even know that replacing the css would restart animations? do you have an example of that so I can reproduce and test?

Lucy Wang06:04:12

> then remove that class yourself at some point? That need to be manually and breaks the modify => wait for css reload => evaluate new design => .. loop

Lucy Wang06:04:20

> I didn't even know that replacing the css would restart animations one sec

andre06:04:19

yeah there are no processes, and i found it was a browser cache If i clean it ,i can see the same project on these ports, so for some reason it runs same project on different ports

andre06:04:02

and i still work with my project on port 3000 even if it says last one is 3002, but i can live with that , not critical 🙂

thheller07:04:17

there must be something blocking those ports

thheller07:04:25

which OS are you on?

andre07:04:18

macos, btw it worked just fine, but at some point i was running several projects in parallel , one was on 3000 and another on 3001, probably after that this project started to show these ports and exceptions, btw it shows exception only if i open browser on port 3001 if i open it on 3000 there are no exceptions

thheller07:04:30

try lsof -i -nP | grep LISTEN

4
thheller07:04:49

that should show which process is listening on that port. if I remember the command correctly 😛

thheller07:04:23

but selecting different ports really shouldn't cause that core.async error

thheller07:04:56

you can try shadow-cljs clj-repl and then ( "clojure/core/async.clj") to see which version you get

thheller07:04:35

and maybe ( "clojure/core/async__init.class") to see if there are some AOT files that would break this as well

andre07:04:12

yes for some reason this project starts 3 ports, if i start it i can see 3 java listeners (3000, 3001 ,3002) if i stop it there are no listeners

Lucy Wang07:04:36

@andre the last resort is to pkill -f java to kill all java process

Lucy Wang07:04:12

@thheller you can see the demo I recorded. After removing the link node and recreating it (by undo) the animation (transition actually) is performed again.

andre07:04:13

there are no java processes

4
thheller07:04:55

then just configure a different port for shadow-cljs if 3000 is used 😛

thheller07:04:30

@wxitb2017 I meant the CSS to make this happen 🙂

Lucy Wang07:04:40

* {
    margin: 0;
    padding: 0;
    text-align: center;
}
html {
    background: white;
    width: 100%;
    height: 100%;
}
body {
    height: 100px;
    background-color: red;
    position: absolute;
    transition: background-color 3s linear 50ms;
    width: 100%;
}
h3 {
    margin-top: 1em;
}

Lucy Wang07:04:58

html is deadly simple


<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Static Template</title>
    <link href="csb.css" rel="stylesheet">
  </head>
  <body class="">
    <h3>This shall move when reloading css</h3>
    <h3>(removing the css link node then undo it)</h3>
  </body>
</html>

thheller07:04:33

interesting that this animates the background-color. wouldn't have expected that.

Lucy Wang07:04:05

not only bg, any animatable css attribute would do

Lucy Wang07:04:30

actually by talking with you I got some inspiration. The transition rule shall be added to a special selector instead of on the base.

thheller07:04:52

I guess its because html bg white is first applied and then body with transition

kirill.salykin07:04:58

Goodmorning, when I am trying to launch shadow-cljs using deps.edn alias I see this error:

shadow-cljs - starting via "clojure"

Unknown option: "-m"

Usage:
  shadow-cljs <action> <zero or more build ids>

Supported actions are:

     compile - ...
       watch - ...
       check - ...
     release - ...
   classpath - ...
   node-repl - ...
browser-repl - ...
   cljs-repl - ...
    clj-repl - ...
    clj-eval - ...
     clj-run - ...
         run - ...
        info - ...
         pom - ...
    npm-deps - ...
        test - ...
         aot - ...
        init - ...
        help - ...
      server - ...
       start - ...
        stop - ...
     restart - ...
shadow-cljs.edn
{:deps     {:aliases [:frontend]}
 :dev-http {8080 "public"}
 :builds   {:app {:target     :browser
                  :output-dir "public/js"
             ... }}}

thheller07:04:30

looks like you have a clojure on your classpath thats not from the official tools.deps dist?

thheller07:04:48

try clojure -m shadow.cljs.devtools.cli help manually

thheller07:04:11

or what did you run to begin with?

thheller07:04:22

did you run shadow-cljs -m something?

kirill.salykin07:04:53

> try `clojure -m shadow.cljs.devtools.cli help` manually this works but If I invoke via shadow-cljs - doesnt

thheller07:04:11

shadow-cljs -m is not supposed to work. what are you actually calling?

kirill.salykin07:04:23

{  :frontend
  {:deps
   {org.clojure/clojure       {:mvn/version "1.10.1"}
    org.clojure/clojurescript {:mvn/version "1.10.742"}
    thheller/shadow-cljs      {:mvn/version "2.8.106"}
    reagent                   {:mvn/version "0.10.0"}
    re-frame                  {:mvn/version "0.12.0"}}
   :main-opts ["-m" "shadow.cljs.devtools.cli"]}}

kirill.salykin07:04:29

this is from the deps.edn

kirill.salykin07:04:51

I just invoke shadow-cljs compile app

thheller07:04:51

remove the :main-opts thats redundant

👍 4
thheller07:04:12

only need that if you want to run via clj -A:frontend compile app

thheller07:04:15

yes, if you intend to run with clj directly.

thheller07:04:16

> Running with clj directly.

thheller07:04:22

I guess that could be clearer

kirill.salykin07:04:16

right, but now same alias cant be used for both scenarios

thheller07:04:18

you can just add another alias if you want to be able to run from clj

kirill.salykin07:04:41

is it possible to specify that I want start cljs repl via clj? (using cider)

thheller08:04:21

cider uses nrepl so not sure what you mean with regards to clj

kirill.salykin08:04:04

ignore me, I’ve found that it is CIDER decides how to start shadowcljs repl

andre07:04:45

:builds       {:dev            {:target           :browser
                                 :output-dir       "public/js"
                                 :asset-path       "/js"
                                 :devtools         {:autoload   true
                                                    :http-root  "public"
                                                    :http-port  3000}}
               :dev1            {:target           :browser
                                 :output-dir       "public/js"
                                 :asset-path       "/js"
                                 :devtools         {:autoload   true
                                                    :http-root  "public"
                                                    :http-port  3000}}
               :dev2            {:target           :browser
                                 :output-dir       "public/js"
                                 :asset-path       "/js"
                                 :devtools         {:autoload   true
                                                    :http-root  "public"
                                                    :http-port  3000}}
interesting if i have such config, and run shadow-cljs watch dev I'll see this
shadow-cljs - HTTP server available at 
[2020-04-28 09:43:53.975 - WARNING] TCP Port 3000 in use.
shadow-cljs - HTTP server available at 
[2020-04-28 09:43:54.004 - WARNING] TCP Port 3000 in use.
[2020-04-28 09:43:54.009 - WARNING] TCP Port 3001 in use.
shadow-cljs - HTTP server available at 

andre07:04:08

if i remove :dev1 and :dev2 i don't see warnings

andre07:04:58

so for some reason shadow runs listeners for all builds when i run one

yenda07:04:25

the http port isn't a listener per build

yenda07:04:00

shadow only needs to run one and then you can monitor all builds on the http endpoint

yenda07:04:35

maybe there should be a check when reading config that it's not defined more than once

yenda07:04:39

or maybe I'm wrong 😛

andre07:04:50

hey dude, when shadow-cljs ? 😛

yenda07:04:11

@thheller btw confirmed, inline requires are only lazy loaded in release, so it's normal that you see them loaded early in dev. I think :chunks should be added to the shadow docs, module just works.

yenda07:04:45

@andre we are going to work with Jakub today to collects the maven deps used by shadow and put them in the nix pkgs

yenda07:04:36

but it's a lot of bash you get just the deps then you have to look for the sources and signatures in the m2 directory, very rough 😄

Spaceman07:04:13

I have this following idiom in my code:

(deftest my-test
   (run-test-sync
       (is (= 1 2)) ;; etc.
   )
And it seems like a good idea to create a macro which would replicate this like so:
(deftest-sync my-test
   (is (= 1 2))
)
And I have tried this:
(defmacro deftest-sync [name test]
  `(deftest ~name ~(run-test-sync ~test))
  )
But on doing in the shadow repl:
(macroexpand '(deftest-sync some-test (is (= 1 1))))
I simply get the result:
(deftest-sync some-test (is (= 1 1)))
But I seem to get the correct result in a clojure repl. Why would this be?

thheller08:04:56

@andre hehe yeah the dev-http stuff isn't per build and they always run. instead use https://shadow-cljs.github.io/docs/UsersGuide.html#dev-http so you just do :dev-http {3000 "public"} once at the top level

👍 4
thheller08:04:07

no :http-root stuff in :devtools needed

thheller08:04:28

:autoload true is also the default so you can skip the entire :devtools entries

thheller08:04:02

also don't name your builds :dev. each build already has dev/release notion built-in, shadow-cljs release dev is just weird 😛

4
thheller08:04:27

@yenda wow, thats neat. surprised that it works but thanks for confirming 🙂

andre08:04:58

btw i have an idea but i don't know if I'll have time any soon, but it would be cool to embed re-frisk into shadow dashboard and utilize shadow's websockets

andre08:04:28

or shadow dashboard could have something like plugins idk

thheller08:04:25

plugins are pretty much impossible due to :advanced but I'd be happy to add a route that just delegates to a re-frisk ring handler when called?

thheller08:04:47

the server supports plugins though, just not the UI. so you could hook into the shadow-cljs lifecycle if needed

thheller08:04:00

its not documented since I'm still not sure how I feel about plugins 😛

yenda10:04:27

@thheller is there a way to specify a local maven repo directory to shadow?

thheller10:04:05

:maven {:local-repo "maven"} in shadow-cljs.edn top level. assuming you aren't using deps/project.clj or course

yenda11:04:54

how does shadow-cljs decides to use the shadow-cljs aot compiled jar? any clue why maven is downloading the sha1 signature of the jar and not the aot jar?

thheller11:04:39

hmm? it defaults to using the AOT jar when using shadow-cljs.edn to manage dependencies

thheller11:04:45

:aot false to turn that off

yenda11:04:51

is there a way to build without going through maven deps resolution again? i.e we already have classpath and deps downloaded, but don't want to rerun dependencies resolution because it will ask for tons of different version of each deps

thheller11:04:58

remove any deps that use version ranges? 😛

yenda11:04:21

I mean when you run shadow-cljs classpath you get all the deps the project needs

yenda11:04:41

but actually when building you need all the intermediate versions to calculate the classpath

thheller11:04:04

isn't that all taken care of if you have the maven repo cached?

yenda11:04:05

we already have the classpath and final deps so is there a way to get straight to the building step

thheller11:04:27

I mean it shouldn't do anything remote once its filled and there are no snapshot deps or ranges?

thheller11:04:34

a pre-calculated classpath is not currently supported otherwise

thheller11:04:52

do lein/deps provide something like that?

yenda11:04:10

no but with lein deps when starting from an empty m2 repo we were basically taking all the downloads printed by the command to have a list of all the deps

yenda11:04:21

but most of them aren't even needed for the actual build

thheller11:04:48

not sure what you are actually trying to do with this

thheller11:04:03

I mean how do you get the shadow-cljs classpath? compute that elsewhere?

thheller11:04:43

you can literally run java -cp <that-classpath> clojure.main -m shadow.cljs.devtools.cli release app yourself if you want 😛

yenda11:04:52

yeah we generate nix derivation is a stateful env then we do offline builds with them

thheller11:04:41

don't know enough about nix to know how that all works 😛

yenda11:04:35

basically think of it as building offline

yenda11:04:46

all you have is a disk so you need everything on that disk

thheller11:04:24

yes. if I run lein deps once to get everything and then disconnect my network and lein repl or whatever it works?

thheller11:04:38

doesn't do anything remote?

yenda11:04:24

yes indeed but it would have downloaded a ton of useless intermediate deps

yenda11:04:31

I think your command with java above works

thheller12:04:19

yeah basically all the tools do is construct the classpath and ensure the files are actually downloaded

thheller12:04:35

otherwise if you have the classpath you don't need anything else and can just run java

thheller12:04:04

maybe need to adjust some extra args if you have :jvm-opts or so configured since they won't be taken into account

thheller12:04:20

build wise it doesn't matter how things were started

yenda12:04:43

is shadow making a call to yarn/npm during the build process?

yenda12:04:45

running: npm install --save --save-exact [email protected] [email protected]
npm ERR! code ENOTFOUND
npm ERR! errno ENOTFOUND
npm ERR! network request to  failed, reason: getaddrinfo ENOTFOUND 
npm ERR! network This is a problem related to network connectivity.
npm ERR! network In most cases you are behind a proxy or have bad network settings.
npm ERR! network
npm ERR! network If you are behind a proxy, please make sure that the
npm ERR! network 'proxy' config is set properly.  See: 'npm help config'

thheller12:04:37

only if your package.json doesn't contain all the packages that were required by cljs deps via deps.cljs

thheller12:04:16

I guess I could add a flag so it always skips that?

yenda12:04:28

might be related to

NPM dependency "react" has installed version "16.9.0"
"16.13.0" was required by jar:file:/home/yenda/.m2/repository/reagent/reagent/0.10.0/reagent-0.10.0.jar!/deps.cljs
` then

yenda12:04:00

seems like there is a mismatch between react version required by reagent and the one required by react-native

thheller12:04:54

thats just a warning

yenda12:04:43

yeah but then our node_modules won't contain 16.13.0 and reagent will require it in deps.cljs?

thheller12:04:59

that doesn't matter

thheller12:04:10

thats the code triggering the npm install

yenda12:04:44

but the npm error says it tried to install 16.13.0 running: npm install --save --save-exact [email protected] [email protected]

thheller12:04:57

and your package.json contains those dependencies?

thheller12:04:08

thats the only question you need to answer

thheller12:04:23

if it is in there it should skip trying to install it, regardless of the versions. that check is done at a different point and does NOT trigger another install

yenda12:04:45

my package.json contains "react": "16.9.0", "react-dom": "^16.4.2",

yenda12:04:01

and they are locked in yarn.lock

thheller12:04:33

and it is in dependencies?

thheller12:04:47

and the package.json is in the same dir as shadow-cljs.edn?

thheller12:04:21

the check is dumb ... so it must be in package.json "dependencies" or "devDependencies"

thheller12:04:31

it does not understand any other complicated setup

yenda12:04:20

ok will check, we do have the package.json in a different dir, might not be properly symlinked at that point

thheller12:04:19

you can open an issue to just disable that check entirely if you want. it is somewhat naive anyways.

yenda12:04:44

looks good, it works now, that was because the package.json wasn't there

👍 4
yenda12:04:14

getting a weird error in CI with deftype that doesn't happen locally:

[2020-04-28T12:32:47.944Z] [:android] Compiling ...
[2020-04-28T12:33:34.658Z] ------ ERROR -------------------------------------------------------------------
[2020-04-28T12:33:34.658Z]  File: /build/status-react-source-jsbundle/src/status_im/utils/multihash.cljs:53:1
[2020-04-28T12:33:34.658Z] --------------------------------------------------------------------------------
[2020-04-28T12:33:34.658Z]   50 | ;; - `hex-digest` is a string holding the hex-encoded algorithm output.
[2020-04-28T12:33:34.658Z]   51 | ;;
[2020-04-28T12:33:34.658Z]   52 | ;; Multihash values also support metadata.
[2020-04-28T12:33:34.658Z]   53 | (deftype Multihash [code hex-digest _meta]
[2020-04-28T12:33:34.658Z] -------^------------------------------------------------------------------------
[2020-04-28T12:33:34.658Z] Error in phase :compilation
[2020-04-28T12:33:34.658Z] Cannot infer target type in expression (. (. Multihash -prototype) --equiv)
[2020-04-28T12:33:34.658Z] {:warning :infer-warning, :line 53, :column 1, :msg "Cannot infer target type in expression (. (. Multihash -prototype) --equiv)"}
[2020-04-28T12:33:34.658Z] ExceptionInfo: Cannot infer target type in expression (. (. Multihash -prototype) --equiv)

thheller12:04:07

do you use :warnings-as-errors or so?

thheller12:04:52

normally these wouldn't throw otherwise?

yenda12:04:22

but I don't get the warning when building locally

yenda12:04:02

well it's building now so yolo

yenda13:04:34

it's weird the error actually happens intermittently

Spaceman14:04:07

I have an myapp.environment namespace like so in an environment.clj file.

(ns myapp.environment
  (:require  [myapp.config :refer [env]]))

(defmacro myapp-url [] (:myapp-url env))
Then I require this in an events.cljs file like
[myapp.environment :refer-macros [myapp-url]]
I get the error in shadow
The required namespace "myapp.environment" is not available, it was required by "myapp/events.cljs".
"myapp/environment.clj" was found on the classpath. Should this be a .cljs file?
when using it like so:
(http/get (str (myapp-url) "/somepath"))
How do I fix this?

Spaceman15:04:17

Say I have a macro in the clj file to be used in a cljs file

(defmacro defelem [name element]
  `(defcard ~name
     (ct.react/react-card
      (r/as-element
       [~element]
       )
      )
     )
  )
and the dependencies are ct.react and r. Should the dependencies be required in the clj or the cljs files? I tried both but neither worked.

Spaceman15:04:46

I get the error in shadow:

(defelem cart-card cart)
-------^------------------------------------------------------------------------
Use of undeclared Var vendo.workspaces.cards/react-card
--------------------------------------------------------------------------------

Felipe Marques16:04:49

Probably in the CLJS

Felipe Marques16:04:40

Your macro is depending on specific alias like ct.react and r I believe this must be available at the file you are using it. Or you should require it in the macro. Or use the full namespace like reagent.core/as-element .

thheller16:04:47

@pshar10 use fully qualified names in the macro and require as normal in the CLJS file. CLJ macros can't see the CLJS aliases so you need to do it manually. I mention this in the blog post.

Pavel Klavík16:04:14

Hi, is there some project for generating static web using Shadow-cljs? I really love hot code reloading (including CSS), so I am thinking to building the static web as a trivial React app in dev and generating static web using hiccup for the production.

Spaceman17:04:57

@thheller this is what I have now, but it doesn't work still: In myapp.workspaces.cards (clj)

(ns myapp.workspaces.cards)

(defmacro defelem [name element]
  `(nubank.workspaces.core/defcard ~name
     (nubank.workspaces.card-types.react/react-card
      (reagent.core/as-element
       [~element]
       )
      )
     )
  )
In myapp.events (cljs) where I use this defelem macro
(ns myapp.workspaces.cards
  (:require
   [nubank.workspaces.core]
   [nubank.workspaces.card-types.react]
   [reagent.core]
   [myapp.cart :refer [cart]]
   
   ))

(defelem cart-card cart)
But I get:
(defelem cart-card cart)
--------^-----------------------------------------------------------------------
Can't take value of macro myapp.workspaces.cards/defelem
Why would this be?

thheller17:04:31

read the blog post again

thheller17:04:38

it literally is just three steps you need to do 😛

thheller17:04:31

(ns myapp.workspaces.cards
  (:require-macros [myapp.workspaces.cards :refer (defelem)])
  (:require
    [nubank.workspaces.core]
    [nubank.workspaces.card-types.react]
    [reagent.core]
    [myapp.cart :refer [cart]]
    ))

thheller17:04:51

the CLJS namespace that also has macros MUST require itself via :require-macros in its ns-form

thheller17:04:09

in your case since you are also using that macro in the very same namespace you also need the refer

mkarp20:04:42

Hey there! I’ve got a question: if shadow watch is running, and I have an app opened in a browser, how can I trigger reload from a command line?

mkarp15:04:53

Yes, sorry for being ambiguous. So let’s say there are a bunch of functions marked with ^:dev/after-load, and I’d like to call all of them via command line. Similar to CSS file watcher — when CSS changes, reload the app in the browser

thheller15:04:45

hmm no there is nothing like that. you can always call those functions from the REPL though?

thheller15:04:14

what are you trying to do though? why is calling that from the command line important?

mkarp16:04:57

We’re generating some js files along with the shadow build and would like to load them in a hot reload fashion

mkarp16:04:28

REPL always works, but I’d like to do it via a file watcher for better usability

thheller16:04:44

you mean you generate js files that aren't part of the build and are loaded via separate <script> tag?

mkarp16:04:32

Yes, exactly

mkarp16:04:50

We don’t want to bundle them together with the application code (translations)

thheller16:04:50

well the easiest way is to just trigger a cljs compile

mkarp16:04:56

We’ve came up with a hacky solution of touching an empty cljs file in src/dev directory

thheller16:04:03

touch path/to/your/sources/some/ns.cljs

mkarp16:04:09

Yes, that’s what we did 🙂

eccentric J21:04:41

There's an going issue with suitable which sits somewhere between cider, and shadow-cljs. https://github.com/clojure-emacs/cider/issues/2808 the author of suitable suggests it was working and is not now. Could someone familiar with the shadow-cljs internals take a quick look and see if anything sticks out? https://github.com/rksm/clj-suitable/blob/master/src/main/suitable/complete_for_nrepl.clj#L207