Fork me on GitHub
#shadow-cljs
<
2019-12-11
>
wiseman05:12:06

is there a way to specify a git dependency in shadow-cljs.edn ?

Saikyun06:12:08

@wiseman maybe not the answer you want, but you can do it through deps.edn šŸ™‚ https://shadow-cljs.github.io/docs/UsersGuide.html#deps-edn

Saikyun07:12:07

happy to help šŸ™‚

deas09:12:41

Almost x-mas, right? šŸŽ„ šŸ˜‰ ...

deas09:12:03

I am using cursive on a clj + cljs (+shadow-cljs) based project and I am aiming at a convenient way to get both repls up and jacked in - like running lein repl, just connecting to a single port and throwing clj/cljs forms from the editor against that single nrepl service. I may be missing something, but I am really having a hard time getting there (ugly :init-nsor even bypassing lein repland using lein run instead). How would you guys be doing this?

thheller09:12:52

Cursive doesn't allow that if I understand you correctly

thheller09:12:01

each connection can only be in one state CLJ or CLJS not both

thheller09:12:14

so you'd have a secondary connection

cfleming09:12:28

(which is something Iā€™m planning to fix, but have not got to yet).

thheller09:12:28

which you can't start from purely clojure

deas10:12:38

@cfleming IIRC - I had things working over a single repl session (with figwheel). Just had to switch the clj/cljs dropdown switch from time to time.

deas10:12:35

The issue with lein repl was that I found no way to get everything up without a manual step in between (launching shadow/watch). Hence, I stepped back from running lein repland started fiddling with lein run . However, I guess putting it all together may do the trick but still appears painful.

conan14:12:16

Don't know if it helps, but I run one repl for backend and one for shadow. to keep things fast, i set up a clojure.main run configuration in cursive and put the path to a file containing this in the parameters:

(require
  '[shadow.cljs.devtools.api :as api]
  '[shadow.cljs.devtools.server :as server])
(server/start!)
(api/watch :app)
(api/repl :app)
That kicks off the shadow compilation right there in the repl, and means i can restart shadow with a single click.

conan14:12:54

seems like it might be possible to kick off your backend in that same script file as well? i don't think you'd be able to access its clj repl though

Schpaa12:12:13

What does this error hint at? The result of a goog.define call must be assigned as an isolated statement. Only getting it at release build

thheller12:12:58

@schpaencoder bad closure-library version on the classpath that is incompatible with the shadow-cljs version you are using

thheller12:12:22

should be these

[com.google.javascript/closure-compiler-unshaded "v20191027"]

   [org.clojure/google-closure-library "0.0-20191016-6ae1f72f"]
   [org.clojure/google-closure-library-third-party "0.0-20191016-6ae1f72f"]

Schpaa12:12:27

@thheller, oh, you mean the globally installed is in conflict with the project specific

thheller12:12:01

dunno you should only be getting this error when using project.clj or deps.edn to manage dependencies?

thheller12:12:12

shadow-cljs itself should never have this conflict when using only shadow-cljs.edn?

Schpaa12:12:41

Iā€™m using the lein-shadow plugin

thheller12:12:52

those are dependencies you wouldn't normally specify but somehow you are getting different versions

thheller12:12:56

check lein deps :tree

thheller12:12:00

it'll tell you about conflicts

Schpaa12:12:46

Got a ton of recommened exclusions, not sure what I am doing now

Schpaa12:12:16

The first one was [org.clojure/clojurescript ā€œ1.10.520ā€]

Schpaa12:12:35

okay, I think Iā€™ll dabble with this first, thanks for the input

Schpaa12:12:01

odd, the error prevailes

Schpaa12:12:51

"user-namespace was evaluated"
[:fb] Compiling ...
Closure compilation failed with 18 errors
--- goog/array/array.js:42
The result of a goog.define call must be assigned as an isolated statement.
--- goog/array/array.js:50
The result of a goog.define call must be assigned as an isolated statement.
--- goog/asserts/asserts.js:48
The result of a goog.define call must be assigned as an isolated statement.
--- goog/base.js:213
The result of a goog.define call must be assigned as an isolated statement.
--- goog/base.js:236
The result of a goog.define call must be assigned as an isolated statement.
--- remaining errors ommitted ...

Schpaa12:12:50

relevant section from project.clj:

:builds {;; "firebase integration"
                         :fb {:target           :browser
                              :compiler-options {:infer-externs :auto}
                              :output-dir       "resources/public/fb/js"
                              :asset-path       "/js"
                              :infer-externs :yes
                              :modules          {:fb {:init-fn fb.core/init!
                                                      :entries [fb.core]}}
                              :build-hooks      []
                              :release          {:compiler-options {:optimizations :simple}}
                              :devtools {:http-port 8050
                                         :http-root "resources/public/fb"
                                         :watch-dir "resources/public/fb" :preloads [re-frisk.preload]}
                              :dev {:closure-defines {"re_frame.trace.trace_enabled_QMARK_" true}}}

thheller15:12:58

that section of project.clj is actually completely irrelevant šŸ˜›

thheller15:12:04

it is only your :dependencies that matter here

thheller15:12:26

somehow you are getting bad versions of the closure-compiler and/or closure-library

aisamu13:12:49

Hi! Should we expect source-maps to work for :npm-module targets? They appear to be almost correctly generated, both for development and release. For development (`compile`), the source-maps aren't taking into account the shimming preamble. Deleting that and inspecting the maps with source-map-visualization[1] works as expected: Here's an example of what I'm calling a preamble:

var $CLJS = require("./cljs_env");
var $jscomp = $CLJS.$jscomp;
require("./cljs.core.js");
var module$shadow_js_shim_module$$material_ui$styles$ThemeProvider=$CLJS.module$shadow_js_shim_module$$material_ui$styles$ThemeProvider || ($CLJS.module$shadow_js_shim_module$$material_ui$styles$ThemeProvider = {});
[...]
var shadow=$CLJS.shadow || ($CLJS.shadow = {});
[...]
var module$shadow_js_shim_module$$material_ui$icons$StarHalfRounded=$CLJS.module$shadow_js_shim_module$$material_ui$icons$StarHalfRounded || ($CLJS.module$shadow_js_shim_module$$material_ui$icons$StarHalfRounded = {});
// empty line
$CLJS.SHADOW_ENV.setLoaded("cljs.namespace.js");
// empty line
Source maps for :browser-test worked out of the box! (I couldn't check release builds - the tool complained about missing sources) [1] - https://sokra.github.io/source-map-visualization/#custom

tslocke15:12:31

Is it correct that shadow-cljs doesn't have configurable dev and release dependencies, because they're not needed in CLJS? I ask because this library provides two versions, in order to elide logging code in production: https://github.com/philoskim/debux#two-libraries

thheller15:12:13

@tslocke yes that is true and you need to use deps.edn or project.clj for that. unfortunately the debux library was written in a "bad" form that requires switching dependencies when it could have been written in a much "cleaner" style that didn't require that

thheller15:12:12

@aisamu I don't know about source maps. they are supposed to work BUT it is entirely depending on the tools to use when including that output somewhere else. since they are very likely going to process the JS again they need to take the "input" source maps (generated by shadow-cljs) into account when generating their own source maps for the output they produce

aisamu16:12:23

Yup! Those for :browser-test work flawlessly, but those for :npm-modules do not. They're loaded and served correctly (via source-map-loader on webpack) but the mappings are slightly off, and removing the preamble from the JS seems to fix the mapping (but breaks the file, of course) We never brought it up because we were using WP3 at the time, and attributed it to it!

thheller17:12:44

feel free to open an issue. I'll try to figure it out when I have a bit of time

šŸ‘ 4
aisamu17:12:11

Done! Thanks a lot!

thheller15:12:40

but if the source maps generated by shadow-cljs don't match then thats a bug

thheller15:12:33

it should be accounting for the "preamble" already but maybe thats not accurate anymore

aisamu16:12:23

Yup! Those for :browser-test work flawlessly, but those for :npm-modules do not. They're loaded and served correctly (via source-map-loader on webpack) but the mappings are slightly off, and removing the preamble from the JS seems to fix the mapping (but breaks the file, of course) We never brought it up because we were using WP3 at the time, and attributed it to it!

Filipe Silva17:12:34

@thheller it seems like you and @plexus talked about making Kaocha work with shadow-cljs back last january https://github.com/lambdaisland/kaocha-cljs/issues/2

Filipe Silva17:12:03

did you think more about how it could work?

thheller17:12:16

I did not no. didn't seem to fit very nicely into the entire system.

Filipe Silva21:12:48

is this something that could work with just the provided shadow-cljs node-repl without any changes to shadow-cljs?

Filipe Silva21:12:18

I was trying to figure out if it could power Calvas testing commands (e.g. "run this test") for cljs codebases

thheller21:12:40

maybe? I can't remember any of the details really

thheller17:12:42

cljs.test is also kinda of a sore spot for me since the entire implementation is so needlessly complex ... uses way too many macros when it doesn't have to

grav17:12:18

If I do a release build while running a watch build, won't they conflict (ie mess up the development process), if I don't have a specific :release {:output-to "... clause in my configuration? (`:target :browser`)

thheller18:12:12

they'll overwrite files yes

thheller18:12:38

but the watch and release themselves won't interfere with each other during compilation

thheller18:12:49

only the final output files

theasp18:12:31

@thheller Is there a way to have builds spit out a native executable using nexe? Obviously I could just run it myself after the build. See https://clojurescript.org/guides/native-executables

Yosevu Kilonzo18:12:51

Hello! I see a section on https://shadow-cljs.org/ about using shadow.resource for non-code resources. I think this is meant for single files only. What approach would I use to require a directory instead?

thheller18:12:05

yeah, you run that separately. you can build a hook to do that if you want if needed

thheller18:12:27

what would requiring a directory do?

thheller18:12:43

but no its for separate files only

Yosevu Kilonzo18:12:41

Ok, thanks. Is there a way to get all the files in a directory?

thheller18:12:38

not built-in no

šŸ‘ 4
theasp18:12:31

@thheller build hook looks like what I want, thanks!

Drew Verlee18:12:39

Is it possible to see the output of the final configuration if your using the :config-merge option? Specifically if i run (shadow/release <build-id> {:config-merge [{compiler-options {:optimizations :advanced}]}) I expect the build to use a configuration similar to as if i had a shadow-cljs.edn: {:builds {<build-id> {:release {:compiler-options {:optimizations :advanced}}} It would be nice to be able to easily verfiy i merged correctly.

thheller18:12:30

yeah thats about it. if you merge something complicated you are probably doing something you shouldn't be doing šŸ˜›

Drew Verlee18:12:20

My hesitation is because its not clear what the entry point of the merge is. The entire shadow-cljs.edn map or are we starting at the release key of the build A) root B) -> <build-id> :release

thheller18:12:38

you are starting with the build config, which already has :release or :dev merged

thheller18:12:08

then your extra merges are applied

Drew Verlee18:12:34

so (shadow/release <build-id> {:config-merge [{compiler-options {:optimizations :advanced}]})` given a shadow-cljs {:builds {<build-id> {:release {:compiler-options {:optimizations :simple}}}`` would be: {:builds {<build-id> {:release {:compiler-options {:optimizations :advanced}}} ?

thheller18:12:25

scrap the :builds map that doesn't exist anymore

thheller18:12:50

you only have {:build-id <build-id> :release {:compiler-options {:optimizations :simple}}}

thheller18:12:12

:build-id is added automatically (taken from the outer map)

thheller18:12:38

so after the first step it only remains as {:build-id <build-id> :compiler-options {...}}

thheller18:12:56

then config-merge is merged in

thheller18:12:10

config merge is basically always merged last so you can be sure that those values are used

Drew Verlee19:12:47

Thanks thheller. You have been a tremendous help. I only hope that i can pay it back at some point šŸ™‚.

Drew Verlee20:12:52

Were observing some unexpected behavior when trying to do some code splitting. This is a different issue then what i asked about yesterday. The questions from yesterday were because i was trying to gather more information about this issue. The issue stated directly is that when we split out a module the client fails to correctly load that module. The specific details of what i'm observing are below. So originally (prior to the app being in a buggy state) we have a shadow-cljs.end that looks like this:

##NOTE "..." just means information we can ignore.
{:modules
  {:main {...}
   :a    {:entries [...] :depends-on #{:main}}
   :b    {:entries [...] :depends-on #{:main}}}
This results in the main module including a namespace (will call it c_ns). The issue is that this namespace is really only a requirement of the a and b namespace (corresponding to the modules we declare above). Its my understanding that if i explicitly create a new module for c_ns then have the other two modules (:a and :b) depend on it. Then the c_ns wont be fetched as part of loading the main module. This is possible because once the modules depend on the namespace explicitly, the Google Closure compiler will know to not put it in the default module (main). Specifically if we make the shadow-cljs file such that its like this:
{:modules
  {:main {...}
   :a    {:entries [...] :depends-on #{:main :c}}
   :b    {:entries [...] :depends-on #{:main :c}
   :c    {:entries [...] :depends-on #{:main}}}
This process seems to work when applied to the first module we tried it on. However, on the second one we tried. It doesn't. In the working version what we see from our network traffic on the browser is. The app loads and we make a GET request for the module we split out. The react components correctly load and everything works as expected. In the version that DOESNT work. The app loads and makes 3 GET requests for the module we split out (possible retries). The react components don't correctly load. Specifically, a component that was loaded as part of react suspense never loads. Its stuck at "suspended = true". This component would correspond to module :a or :b (from above). The components that depend-no the module we are trying to split out. Additionally, This behavior is only observed when we use the compiler optimizations set to Advanced. Which in part is making it difficult for me to understand how to debug the issue, as i'm less sure how to get feedback.

thheller21:12:11

@drewverlee you are overcomplicating your description a bit and at the same time missing important details šŸ˜›

thheller21:12:20

HOW you do you load modules?

thheller21:12:54

assuming that your HTML page only includes <script src="/js/main.js"> or whatever path you have?

thheller21:12:59

that uses shadow.loader?

Drew Verlee17:12:27

@thheller Yes our HTML page includes <script src="/js/main.js"> For the module that isn't working were not using anything from shadow.loader. We were under the impression that just by declaring the modules in our shadow-cljs.edn file they would be re-organized as part of an optimization by the google closure compiler.

Drew Verlee19:12:19

@thheller https://github.com/thheller/shadow-cljs/blob/2bceed2b6ac3b8cf5cae110d319553394aba8156/src/main/shadow/lazy.cljs#L28 This comment is probably relevent to our situtation. At least to understanding the feedback were getting. What specifically does it mean "when the eval failed"

Drew Verlee19:12:40

Its also probably relevent that we have module-loader set to true

thheller20:12:28

so you are using shadow.loader. do you have errors during load?

thheller20:12:44

they should be logged somewhere?

thheller20:12:51

the easiest way to test is just including the modules directly in your html

thheller20:12:09

so just loading things eagerly. all the async loading stuff just complicates debugging

thheller20:12:33

if all that loads fine you can try the async stuff but debugging load issues otherwise is pretty painful

Drew Verlee20:12:38

For the module that is causing an issuue. I have tried both loading using the lazy component macro, which calls shadow lazy load. We also tried it without calling any shadow loader code directly, as we were under the impression that breaking them into modules was sufficient. The might be incorrect. Your suggesting I add logging around the shadow.lazy/load? I'll try including the modules directly in the HTML, thanks!

thheller20:12:41

just add the three moduels in the proper order to your html

thheller20:12:06

if that throws no error during load start testing the async load stuff

thheller20:12:29

kinda hard to make suggestions since I know so little about what you are actually doign

thheller20:12:35

code splitting can be tricky for sure

Drew Verlee21:12:09

Thanks. We dont have async enabled. I assume that makes it less likely there are issues.

thheller21:12:58

of course you have async enabled when using shadow.lazy. that is all async

Drew Verlee22:12:04

Yes, i see what you mean. I was refering to that we dont have the async attribute enabled in our script tag when we load the main.js file.

Drew Verlee16:12:24

So we added the module that was causing the issue to index.html. @thheller What i see from my dev tools console is: "Uncaught TypeEroor: cannot read property of 'prototype' of undefined." at spec/alpha.cljs:1300 at shadow/module/<offending module>/append.js:2 append.js is just : shadow.loader.set_loaded(); So my interpretation of that is that somehow set_loaded is being called with no arguments? Possible resulting in the above error. Does that seem reasonable?

thheller16:12:55

set_loaded takes no arguments so not thats not it

thheller16:12:10

which version is this?

Drew Verlee16:12:15

version "2.8.74"

thheller19:12:33

can you try with either .83 or .68?

Drew Verlee20:12:00

I tried with .83 It seemed to have no effect on what happened.

papachan21:12:07

Is there any quick template with shadow-cljs including react as foreign-libs?

thheller21:12:03

shadow-cljs doesn't even support foreign-libs so no šŸ˜›

4
colinkahn23:12:31

Iā€™m having an issue which I canā€™t reproduce with a minimal case, but goes away if I change the version of shadow Iā€™m using. It seems unrelated to the build or the compiled files (Iā€™ve removed the compiled files and restarted the build). Question is, is there some cache I can clear out outside of those things?

lilactown23:12:15

what is the issue?

colinkahn23:12:32

using st/instrument for some reason it starts to return an empty vector and stops instrumenting my fdefs

colinkahn23:12:29

I dropped back a version of shadow-cljs and it started working again, but eventually stopped, so I bumped the version and again it worked. Really frustrating as I cannot see why it would stop working.

lilactown23:12:13

that is strange. it sounds like it might have to do with the build/analyzer caching? Not sure

lilactown23:12:35

there is another dir, .shadow-cljs, which has a builds dir that has the build cache

lilactown23:12:04

it is typically verboten to remove this as it shouldnā€™t be necessary, but if clearing that out solves it, it might point us in the right direction to why itā€™s doing this

lilactown23:12:16

what exactly are you instrumenting?

colinkahn23:12:41

@U4YGF4NGM nuking .shadow-cljs made it work again

colinkahn23:12:22

Iā€™m instrumenting functions in some unit tests to stub return values.

colinkahn23:12:27

Them failing seems completely unrelated to the code though, I had removed some changes to see if those had caused it before deleting .shadow-cljs and now have reintroduced it and everything is working fine :man-shrugging:

lilactown23:12:24

So your tests namespace instrument the functions inside the implementation namespace?

colinkahn23:12:59

Itā€™s like: impl.cljs <= defnā€™s impl_specs.cljs <= fdefs impl_test.cljs <= st/instrument

lilactown23:12:45

and typically, what kinds of changes cause this to break?

lilactown23:12:03

changing impl.cljs or impl_specs.cljs or impl_test.cljs?

colinkahn23:12:57

code wise I canā€™t pin it to anything Iā€™ve done. just working on files, saving, tests autorefresh and run. At some point the tests stop working and I log st/instrument and itā€™s an empty vector.

colinkahn00:12:12

Now Iā€™m hoping it breaks again so I can inspect things more

colinkahn00:12:29

something weird is that sometimes when I call st/instrumentable-syms itā€™s a set, other times it`s a vector, and when things werenā€™t working I remember running it and it was a vector with a ton of duplicates of the fdefā€™ed syms

lilactown00:12:00

https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/spec/test/alpha.cljc#L69 it looks like calls to instrument mutate some global state in the running compiler process, which probably doesnā€™t play well with the way namespaces are cached while building

šŸ˜¬ 4
lilactown00:12:56

Iā€™m not sure how this works in the vanilla cljs compiler, but I think an issue could be opened to fix this in spec.test

colinkahn00:12:30

@U4YGF4NGM open an issue against ClojureScript itself?