Fork me on GitHub
#shadow-cljs
<
2022-06-29
>
sheluchin12:06:57

I'm running into an issue with UUIDs generated with (random-uuid), conditional upon requiring meander. Details in thread...

sheluchin12:06:52

This works fine:

$ clj -Sdeps '{:deps {meander/epsilon {:mvn/version "0.0.650"}}}'
Clojure 1.10.3
(require '[meander.epsilon :as m])
Reflection warning, meander/util/epsilon.cljc:758:24 - reference to field val can't be resolved.
nil
(identity #uuid "0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978")
#uuid "0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978"
But when using shadow:
shadow-cljs - starting via "clojure"
shadow-cljs - server version: 2.19.5 running at 
shadow-cljs - nREPL server started on port 9000
shadow-cljs - REPL - see (help)
To quit, type: :repl/quit
shadow.user=> (identity #uuid "0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978")
#uuid "0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978"
shadow.user=> (require '[meander.epsilon :as m])
Reflection warning, meander/util/epsilon.cljc:758:24 - reference to field val can't be resolved.
nil
shadow.user=> (identity #uuid "0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978")
Execution error (NumberFormatException) at shadow.user$eval36582/<clinit> (REPL:3).
Invalid number: 0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978

sheluchin12:06:04

And strangely enough, this works:

shadow.user=> (do #uuid "0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978")
#uuid "0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978"

rolt12:06:34

what's the value of cljs.reader/*tag-table* ?

sheluchin12:06:31

Sorry, I should have mentioned that it's a clj-repl started with:

npx shadow-cljs clj-repl -A:shadow-cljs

sheluchin13:06:31

shadow.user=> cljs.reader/*tag-table*
Syntax error (ClassNotFoundException) compiling at (REPL:0:0).
cljs.reader
I'm not sure if it worked..? Looks like it produced a syntax error and a value?

rolt13:06:47

i though it was cljs, in that case that would be default-data-readers and *data-readers*

rolt13:06:43

i tried to reproduce but couldn't, it works for me even after requiring meander :/

sheluchin13:06:21

shadow.user=> *data-readers*
{dbg #'cider.nrepl.middleware.debug/debug-reader, break #'cider.nrepl.middleware.debug/breakpoint-reader, light #'cider.nrepl.middleware.enlighten/light-reader, meander.epsilon/fail #'meand
er.strategy.epsilon/*fail*, meander.epsilon/pass #'meander.strategy.epsilon/*pass*}

rolt14:06:05

can't reproduce either, what's the java version ?

sheluchin14:06:19

@U02F0C62TC1

$ java --version
openjdk 11.0.15 2022-04-19
OpenJDK Runtime Environment (build 11.0.15+10-Ubuntu-0ubuntu0.21.10.1)
OpenJDK 64-Bit Server VM (build 11.0.15+10-Ubuntu-0ubuntu0.21.10.1, mixed mode, sharing)

rolt15:06:05

i'm using the same... sorry i'm at loss

sheluchin15:06:24

No worries, thanks for checking it out!

thheller17:06:48

hmm this is odd. will look into it. thanks for the repro

thheller17:06:24

hmm unfortunately I cannot repro it either. works as expected.

thheller17:06:05

can you run a *e eval after the error? maybe the stacktrace can provide some clues

thheller17:06:27

and just #uuid "0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978" without the (identity) works?

sheluchin17:06:47

shadow.user=> #uuid "0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978"
#uuid "0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978"
shadow.user=> (identity #uuid "0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978")
Execution error (NumberFormatException) at shadow.user$eval36931/<clinit> (REPL:5).
Invalid number: 0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978
shadow.user=> (prn #uuid "0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978")
Execution error (NumberFormatException) at shadow.user$eval36933/<clinit> (REPL:6).
Invalid number: 0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978
shadow.user=> 
Yep.

sheluchin17:06:27

Perhaps there's something extra running I'm not aware of? Is there some way to get more diagnostics or make it run with a bare config?

thheller17:06:28

that is very odd. don't have a guess what that might be really

thheller18:06:51

java.lang.ExceptionInInitializerError is always responsible for some very weird errors

thheller18:06:59

normally the trace has a clue though

thheller18:06:08

does this happen if you do it over nrepl?

thheller18:06:21

or just the clj-repl directly?

thheller18:06:14

also do you have something in your ~/.clojure/deps.edn or wherever that file is? maybe there is something in there contributing to this? no idea what but maybe?

thheller18:06:45

also you can set {:deps {:aliases [:shadow-cljs]}} in shadow-cljs edn so you don't have the pass the -A:shadow-cljs in case you didn't know that

👍 1
sheluchin18:06:50

~/.clojure/deps.edn has some aliases, but I'm not activating them here.

sheluchin18:06:24

/usr/local/lib/clojure/deps.edn is commented out.

sheluchin18:06:12

And yes, happens over nrepl too:

+14:16 $ clj -A:repl/cider
WARNING: Use of :main-opts with -A is deprecated. Use -M instead.
nREPL 0.9.0
Clojure 1.11.1
OpenJDK 64-Bit Server VM 11.0.15+10-Ubuntu-0ubuntu0.21.10.1
Interrupt: Control+C
Exit:      Control+D or (exit) or (quit)
#uuid "0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978"
#uuid "0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978"
(identity #uuid "0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978")
Execution error (NumberFormatException) at shadow.user$eval40895/<clinit> (REPL:1).
Invalid number: 0eb537e1-72bc-4d1a-89e0-8e3c2a7f8978
shadow.user=>

sheluchin18:06:44

I guess I could ask in #meander? It does seem related, since the identity call works before requiring it. Otherwise I too have no ideas. It's strange that it works with some forms, like do, and, or, but not most others. I guess those working ones don't evaluate it or something.

sheluchin19:06:02

I'm sorry, this is very frustrating because it has happened to me in the past. Somehow after deleting my .m2 folder and reinstalling Clojure, the problem is gone. I have no idea how my .m2 is getting screwed up or how I can detect that it's in a broken state to avoid another goose chase like this. I don't interact with that folder manually.

thheller19:06:02

maybe your PC is broken in same way? bad ssd, bad ram?

sheluchin20:06:29

@U05224H0W guess I can't rule it out completely. There was a lengthy https://clojurians.slack.com/archives/C053AK3F9/p1656530805008529 about this in #beginners. Unfortunately, didn't really come to a resolution because I deleted the evidence (~/.m2 folder), but there are some good guesses in there. Leaving it here for reference.

Franco Gasperino20:06:39

good afternoon. i'm experimenting w/ code splitting.

Franco Gasperino20:06:34

{:builds                                                                                                                                                                                                                                      
  {:dev                                                                                                                                                                                                                                        
   {:target :node-script                                                                                                                                                                                                                       
    :main shadowtest.core/main                                                                                                                                                                                                                 
    :output-to "build/shadowtest/app.js"                                                                                                                                                                                                                                                                                                                                                                                                                                                 
    :module-loader true                                                                                                                                                                                                                        
    :modules                                                                                                                                                                                                                                   
    {:hotload                                                                                                                                                                                                                                  
     {:entries [shadowtest.hotload]}}}
(ns shadowtest.core                                                                                                                                                                                                                           
  (:require                                                                                                                                                                                                                                   
   [shadow.loader :as loader]))                                                                                                                                                                                                               
                                                                                                                                                                                                                                              
(defn do-load!                                                                                                                                                                                                                                
  [n]                                                                                                                                                                                                                                         
  (println "Loading module '" n "'.")                                                                                                                                                                                                         
  (-> (loader/load n)                                                                                                                                                                                                                         
      (.then identity))) 
attempting to drive it in the repl:
(do-load! "hotload")
emits:
Execution error (Error) at (<cljs repl>:1).                                                                                                                                                                                                   
shadow.loader API was called before shadow.loader.init!                                                                                                                                                                                       
You are probably calling module loader too early before shadow-cljs got fully initialized.

Franco Gasperino20:06:56

was there a step i missed when attempting this?

thheller20:06:12

you are using :target :node-script but you want :target :browser I guess?

Franco Gasperino20:06:27

no, im hoping to run this via nodejs

thheller20:06:45

code splitting isn't supported by :node-script. neither is it very useful?

Franco Gasperino20:06:27

gotcha. i have a case for it, but that answer satisfies the question

Franco Gasperino20:06:53

i would like to have a similar effect of requiring-resolve on cljs on node (at the compile step)

thheller20:06:19

then you maybe want :npm-module?

thheller20:06:33

but really you can't have something like requiring-resolve

Franco Gasperino20:06:34

perhaps. will read up on it

Franco Gasperino20:06:01

ideally would like to have a generated shadow-cljs.edn file, which uses :modules and :entities like interfaces inside the application. user can swap out implementations at compile time w/o fooling with the cljs code

thheller20:06:14

but you are starting with optimizing load time?

thheller20:06:40

I mean just having all the code loaded and then using your own mechanism to switch between different impls would be easy

thheller20:06:44

and would not require require or resolve

Franco Gasperino20:06:08

i dont have any pre-sight into the actual namespace names

Franco Gasperino20:06:20

was hoping :modules would abstract it

Franco Gasperino20:06:07

i don't see that i can require up-front

thheller20:06:22

modules only abstract the splitting of one output file into many. the inputs are the same.

thheller20:06:24

so if I understand correctly the user will say "I want feature X, Y, Z" somehow

thheller20:06:33

and you want to generate a build out of that?

Franco Gasperino20:06:57

assume i'm going to take string messages from an ingress source. this may be kafka, jms, http, or other. these are expected to have a common entry point fn with the same signature (arity, etc). these may be in their own namespaces. I was originally thinking i could use :modules to identify "ingress" with :entities [the.actual.namespace], and shadow.loader/load "ingress" I can construct the shadow-cljs.edn file programically.

Franco Gasperino20:06:15

on the jvm i can do this w/ requiring-resolve

thheller20:06:28

what is :entities? do you mean :entries?

Franco Gasperino20:06:46

sorry yes, my mistake

thheller20:06:22

so you are triggering a shadow-cljs build dynamically and then somehow run the generated output?

thheller20:06:38

I mean there are several steps before shadow.loader/load even applies?

Franco Gasperino20:06:08

assume that each change or difference would involve a whole build step

thheller20:06:27

and it launches an entierely new process? you are not trying to load it some running script?

Franco Gasperino20:06:28

i don't expect it to happen at run time

Franco Gasperino20:06:30

the real target is to avoid (require '[some.namespace.i.dont.know :as ingress])

Franco Gasperino20:06:39

thats the whole task

thheller20:06:52

that the part I'm asking

thheller20:06:00

you have a running node application

thheller20:06:32

that in clojure would do ((requiring-resolve 'some/thing) :foo :bar) but can't in CLJS

Franco Gasperino20:06:34

it wont change after compile. assume that each customer that may change implementation has their own compilation, process, etc

thheller20:06:44

the "running node application" is the key question here

thheller21:06:15

if you just create a build and launch a new process things become simpler?

Franco Gasperino21:06:04

that is what will occur, yes. the selection of implementation, and therefore the generation of shadow-cljs.edn, will happen during a docker image build

thheller21:06:10

I mean instead of generating a build config you can just as well generate a namespace

thheller21:06:26

so hardcode a build config with {:target :node-script :main some.thing/main}

thheller21:06:43

and then generate (ns some.thing (:require [whatever.you.need])) (defn main [] ...) dynamically

Franco Gasperino21:06:52

thats not a bad idea..

Franco Gasperino21:06:22

let me consider that. thanks for the idea

Franco Gasperino21:06:36

and it'll be more explicit, too

thheller21:06:09

please be aware that shadow-cljs is a development tool. it is not meant to ever run in any kind of production environment.

thheller21:06:40

it will expose several sockets for nrepl, its own websocket server and so on which may compromise production envs

thheller21:06:54

so whereever you do this make sure its safe 😉

Franco Gasperino21:06:21

and thanks for your work on the project