Fork me on GitHub
#shadow-cljs
<
2020-02-03
>
mkarp15:02:18

Hey everyone! I’m trying to figure out how I can send forms to be evaluated in the ClojureScript REPL while I’m in a Clojure REPL. I know I can run (shadow/repl :app) and then type in cljs commands, but is it possible to evaluate a single cljs form through Shadow’s API without interacting with the cljs REPL? Thanks!

thheller16:02:32

@me1676 what would that look like? there is no command for that currently but it wouldn't be hard to add one

mkarp16:02:28

@thheller Something like (shadow/eval-cljs :my-build-id '(js/console.log "Hello world")) would be awesome

mkarp16:02:34

Does it make sense?

thheller16:02:52

depends on what you want to use that for. lots of "context" to consider when evaling forms, eg. (shadow/eval-cljs :my-build-id '(foo/bar "Hello world"))

thheller16:02:23

might need to be able to resolve foo (if its an alias)

thheller16:02:47

(shadow/eval-cljs :my-build-id '(foo ::bar)) would also turn ::bar into :user/bar (or whatever CLJ ns you are currently in)

mkarp16:02:50

Right. What about passing a string input? (shadow/eval-cljs :my-build-id "(js/console.log \"Hello world\")")

thheller16:02:16

that would still need to take at least one additional parameter for the ns that should be compiled in

thheller16:02:35

and the overall problem that there may be multiple runtimes you need to deal with

thheller16:02:00

eg. you are building a browser app and have it open in chrome and firefox

thheller16:02:13

which one does the eval go to? 😛

thheller16:02:43

I'm currently working on some REPL related things ...

thheller16:02:54

it is a lot more complicated than it looks on the surface 😛

mkarp16:02:00

Totally. After looking at the code, I walk away with a defeat for now 🙂 You know, I’d like to “just simply call” some cljs code 🙂

mauricio.szabo03:02:48

I don't know if you're still looking for a way to evaluate code, and I probably am using internal APIs that are not meant to be used, but I just implemented it on Chlorine. So if you want to take a look: https://github.com/mauricioszabo/repl-tooling/blob/master/resources/shadow_commands.clj#L1-L28

mkarp13:02:20

Oh wow, thanks! I’ll try it out

thheller16:02:13

would help to know what you want to use this for in the first place

thheller16:02:34

like how smart does this need to be. do you need the result?

mkarp16:02:26

Yes, getting the result would be great

yenda16:02:50

When building with shadow, is there a way to get the list of all dependencies (including transitive?)? Even something like this when I do compile but this only shows what isn't cached yet

Retrieving reagent/reagent/0.9.1/reagent-0.9.1.pom from 
Retrieving cljsjs/react/16.9.0-1/react-16.9.0-1.pom from 
Retrieving cljsjs/react-dom/16.9.0-1/react-dom-16.9.0-1.pom from 
Retrieving cljsjs/react-dom-server/16.9.0-1/react-dom-server-16.9.0-1.pom from 
Retrieving re-frame/re-frame/0.11.0/re-frame-0.11.0.pom from 
Retrieving reagent/reagent/0.9.1/reagent-0.9.1.jar from 
Retrieving cljsjs/react-dom-server/16.9.0-1/react-dom-server-16.9.0-1.jar from 
Retrieving cljsjs/react-dom/16.9.0-1/react-dom-16.9.0-1.jar from 
Retrieving cljsjs/react/16.9.0-1/react-16.9.0-1.jar from 
Retrieving re-frame/re-frame/0.11.0/re-frame-0.11.0.jar from 

thheller16:02:38

what for specifically? the list you'd get would include shadow-cljs and all its deps?

yenda16:02:50

yes, I need it because we use a pure environment for our builds wit nix

thheller16:02:52

not sure what nix has to do with this but you can get a list via shadow-cljs classpath?

yenda16:02:03

we have a script that gets all the deps from lein build and create a .nix where they are like this:

"" =
  {
    host = repositories.maven;
    path =
      "args4j/args4j/2.33/args4j-2.33";
    type = "jar";
    pom = {
      sha1 = "168b592340292d4410a1d000bb7fa7144967fc12";
      sha256 = "046pab6gz1bh6w1jfbabgxvkrnvncrj93lnmaya5qs6a1z7mccn2";
    };
    jar = {
      sha1 = "bd87a75374a6d6523de82fef51fc3cfe9baf9fc9";
      sha256 = "1mlyqrqyhijwkjx4sv2zfn2ciqfwpc08qq8w55rcxb941fxfmpci";
    };
  };

yenda16:02:09

it's for reproducible builds

yenda17:02:08

classpath could potentially do the trick

yenda17:02:22

there is no way to have the repo it's coming from?

thheller17:02:07

you said lein so you gonna need to use lein? (assuming :lein set in shadow-cljs.edn)?

yenda17:02:39

no I'm replacing lein by shadow-cljs entirely

thheller17:02:00

and how did you do it with lein?

yenda17:02:21

lein with-profile prod cljsbuild once

_lein_cmd='yarn app:compile:android'
_repo_path=$(mktemp -d)

function filter() {
  sed -E "s;Retrieving ([^ ]+)\.(pom|jar) from $1.*;$2\1;"
}

echo "Computing maven dependencies with \`$_lein_cmd\`..." > /dev/stderr
trap "rm -rf ${_repo_path}; [ -f ${_project_file_name}.bak ] && mv -f ${_project_file_name}.bak ${_project_file_name}" HUP ERR EXIT INT

cd $GIT_ROOT

# Add a :local-repo entry to project.clj so that we always start with a clean repo
sed -i'.bak' -E "s|(:license \{)|:local-repo \"$_repo_path\" \1|" ${_project_file_name}
rm -rf ./${_repo_path}
$_lein_cmd 2>&1 \
  | grep Retrieving \
  | filter clojars  \
  | filter central  # NOTE: We could use `lein pom` to figure out the repository names and URLs so they're not hardcoded

thheller17:02:23

the url things are coming from isn't currently saved anywhere. the closest thing to "data" that is currently available would be in .shadow-cljs/classpath.edn

thheller17:02:48

it should be possible to include the URLs in that

yenda17:02:51

so basically just piping and filtering the output of the line command

thheller17:02:43

btw you could skip all that with one "trick"

thheller17:02:23

it is a bit madness IMHO but you can set :maven {:local-repo "local-m2"} and keep the <project>/local-m2 files in git

thheller17:02:46

or zip/unzip in some way when packaging

yenda17:02:53

so you mean have all the jars in the repo?

yenda17:02:16

we have them in the nix store

thheller17:02:40

I know absolutely nothing about nix so no idea what a store is

yenda17:02:51

adding the URLs in the classpath looks promising

thheller17:02:04

just saying that if this way the project is completely separate. it won't even talk to the internet when building

thheller17:02:23

it'll never fetch anything that isn't already present

thheller17:02:24

I'm not sure I can get the URL, need to check if pomegranate provides it

thheller17:02:03

open an issue or I'll forget. working on other stuff currently

yenda17:02:30

ok thanks

aisamu12:02:49

Just saying, a blog post on cljs+shadow+nix would be terrific!

lilactown18:02:58

for some reason when I try and use a namespaced keyword in a macro, shadow-cljs throws an error

lilactown18:02:27

[:dev] Build failure:
------ ERROR -------------------------------------------------------------------
 File: /Users/lilactown/Code/helix/src/helix/hooks.cljc:115:41
--------------------------------------------------------------------------------
 112 |      (cond
 113 |        ;; warn on typical errors
 114 |        (and (= (count body) 1) (symbol? (first body)))
 115 |        (do (hana/warn ::hana/simple-body env)
-----------------------------------------------^--------------------------------
helix/hooks.cljc [line 115, col 41] Invalid keyword: ::hana/simple-body.

--------------------------------------------------------------------------------
 116 |            nil)
 117 | 
 118 |        ;; deps are passed in as a vector
 119 |        (vector? deps) (deps->hook-body `(cljs.core/array ~@deps)
--------------------------------------------------------------------------------
this is in a :clj reader-conditional, and the hana namespace alias does exist in clojure (but not cljs)

lilactown18:02:45

writing out the fully qualified namespace for the keyword works

thheller19:02:47

code must still be readable as CLJS. tools.reader must still be able to read the full form (and then throw it away). don't ask me why that is. has nothing to do with shadow-cljs

lilactown19:02:36

I see. only in .cljc files I’m assuming?

thheller19:02:10

not really sure I understand that question. clj and cljs must both the readable always?

thheller19:02:35

(comment ::foo/bar)
Syntax error reading source at (REPL:1:19).
Invalid token: ::foo/bar

thheller19:02:12

(that is CLJ)

lilactown19:02:54

like I said above, in my namespace I have required another ns and aliased it to hana . I can evaluate ::hana/foo using a REPL

lilactown19:02:16

my question is trying to make sure that I understand the problem which is: I am trying to use a shorthand namespaced keyword in a .cljc file where I have not required/aliased that namespace in the CLJS portion, which is why it can’t be read

lilactown19:02:50

it was poorly stated

thheller19:02:06

it must be resolvable for CLJS and CLJ. try to flip it and see what clojure does, ie. create an alias an CLJS and use it in CLJ (in a :cljs conditional)

thheller19:02:25

if that is different open an issue with tools.reader. if thats the same then thats just is how its supposed to be.

thheller19:02:51

either way there is nothing shadow-cljs can possibly do here

lilactown19:02:04

understood, thanks

thheller19:02:27

$ clj test.cljc
Exception in thread "main" Syntax error reading source at (/mnt/c/Users/thheller/code/tmp/test.cljc:3:31).
        at clojure.lang.Compiler.load(Compiler.java:7642)
        at clojure.lang.Compiler.loadFile(Compiler.java:7573)
        at clojure.main$load_script.invokeStatic(main.clj:452)
        at clojure.main$script_opt.invokeStatic(main.clj:512)
        at clojure.main$script_opt.invoke(main.clj:507)
        at clojure.main$main.invokeStatic(main.clj:598)
        at clojure.main$main.doInvoke(main.clj:561)
        at clojure.lang.RestFn.applyTo(RestFn.java:137)
        at clojure.lang.Var.applyTo(Var.java:705)
        at clojure.main.main(main.java:37)
Caused by: java.lang.RuntimeException: Invalid token: ::str/foo

thheller19:02:41

$ cat test.cljc
#?(:clj ::foo :cljs ::str/foo)