This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-11-26
Channels
- # announcements (2)
- # aws (4)
- # babashka (5)
- # beginners (91)
- # calva (4)
- # cider (17)
- # clara (13)
- # clj-kondo (14)
- # cljsrn (11)
- # clojure (159)
- # clojure-europe (2)
- # clojure-nl (14)
- # clojure-norway (2)
- # clojure-taiwan (2)
- # clojure-uk (32)
- # clojurescript (101)
- # clojutre (4)
- # cursive (13)
- # data-science (1)
- # datomic (46)
- # emacs (68)
- # figwheel-main (5)
- # fulcro (48)
- # graalvm (7)
- # graphql (6)
- # instaparse (5)
- # joker (4)
- # lambdaisland (1)
- # leiningen (2)
- # malli (9)
- # off-topic (41)
- # pedestal (15)
- # re-frame (47)
- # reagent (7)
- # reitit (14)
- # shadow-cljs (180)
- # spacemacs (58)
- # specter (1)
- # tools-deps (13)
try 2.8.76
and generate a build report and then one with :compiler-options {:shadow-keywords true}
looking to compare the gzip size before/after
in our main bundle,
• before: [JS: 4.19 MB] [GZIP: 1019.18 KB]
• after: [JS: 3.99 MB] [GZIP: 960.59 KB]
it’s my goal in life right now to at least get code splitting going so we can chunk out the loading process better
I only recently joined this project. unfortunately, re-frame is fighting me on that front… our code is laid out in a way that makes it harder to split
If from this experience you learn there is anything you think that would help in future re-frame releases to improve code splitting please let me know and I'll take the feedback into consideration :thumbsup:
w.r.t., it adds to the problems because of the ability for any ns to fire off any event or subscribe to any subscription without noting the defining ns in it's requires
there's an implicit dependency in every ns on the fact that the event / fx / co-fx / subs have been registered already, that doesn't show up in it's dependency graph
Not sure if that will haunt me in the future, but somewhat recently I started requiring namespaces where the events/subs are defined and using fully-qualified keywords with namespace aliases. That way, there's an explicit dependency graph and you never dispatch an event or subscribe to a sub that has not yet been registered.
On my own projects, I also do fully qualified keywords as per @p-himik's comment above. I havn't yet used fully qualified keywords in re-frame for long enough (only ~2 years) to say definitively that long term its a good or bad plan but so far so good. It's not official re-frame guidance but it is an option that gives fully qualified dependencies on all event / fx / co-fx / subs. @U4YGF4NGM
Hey, dudes and dudettes!
I have an unusual question, does shadow-cljs provide anyway to have optimization/minification on for hotreloaded code when running watch? I know that's generally a no no but I have a bit peculiar use-case here.. I'm figuring out to a way to compile code that I use in Screeps, which is a Coding Sandbox game. The thing is that the code works wonderfully when I build a node library in release mode and use that in the game. Naturally the watched dev version includes some Shadow-CLJS-related stuff so that doesn't work. I'm well aware that what I'm asking might be impossible, but I figured if someone smarter/more experienced one would have an idea? Otherwise it's really nice to use shadow-cljs and it's not so bad having to manually build your code for this specific case 🙂
@theamazingekko hot-reload is impossible with optimized code so no its not possible to have a release "watch"
Thanks for the verification, assumed so 🙂
if you run shadow-cljs server
and then shadow-cljs release app
whenever you need while that is running you at least won't pay for the startup cost each time
yup, been taking the REPL-route so far and it's good. Just wondered about the concept :)
Just noticed that running release
twice produces different files. Seems like Closure renames some objects in different ways.
Is it possible to create the same output from the same input?
Just two consecutive release
commands on my local machine. Removed only the js and js.map files in between.
> did it recompile any CLJS?
Probably - it took some time and CPU.
Ah yeah, gensym
is in there somewhere. Although I would expect the order to be the same. But maybe that's not the case, or maybe the order doesn't matter.
Yeah, but since I restart it each time I run release
, the numbers should've been the same. Unless there's some concurrent work being done.
but that only really works if no CLJS compilation occurs .. which of course makes it pointless
Well, one could hope. 🙂 It's pretty often that I make only backend changes but CI runs the same pipeline either way and releases the UI bundle. But it's not a huge deal. And module splitting should make the situation a bit better, I assume. Whenever I finally start using it, that is.
you can check with shadow-cljs release app --verbose
if any actual CLJS compilation occurs
if not the builds should be the same. assuming of course that .shadow-cljs/builds
is preserved between the builds (which may require additional CI config)
Ah, but that's more complicated and probably not worth my time. After all, I use macros and CLJC. Thanks, will try.
Yeah, a bunch of CLJS gets consistently recompiled on each run.
So, I should look out for gensym
and see if I can remove it. Is there anything else that I should look out for that could prevent a cached compilation result from being used?
Huh. Just checked gensym
usages in CLJS files. It's definitely used. Only those files are never recompiled.
I mean if they didn't change they should be cached. unless they have warnings or so.
I'm trying to check a particular file by commenting out suspicious imports and pieces of code and running the release twice.
Ah, prettifying cache files and comparing them is much faster.
Yeah, it's definitely gensym
. But only at some very particular places, and not the others. The same 6 files, each and every time.
The offending calls to gensym
are made by doto
and by cljs-oops
. But I use them in a much greater number of files. It's interesting how only those 6 get different results.
I feel like you are digging into something thats kinda pointless. using when
uses gensym
Yep. At this point, I'm trying to understand why those particular 6 files are affected. And others are not.
No warnings in those files. Only a couple of warnings from transit-js, and it's not used by those files. Nope, don't block anything.
No warnings at all then. Just lines like these
<- Cache read: hgs/platform/abc/core.cljs (8 ms)
-> Compile CLJS: hgs/platform/abc/core.cljs
[...]
<- Compile CLJS: hgs/platform/abc/core.cljs (282 ms)
[...]
<- Cache write: hgs/platform/abc/core.cljs (32 ms)
and the differences in variables' names in the cached JS in {:output {:js "..."}}
.Yep, seems like it:
-> Cache read: hgs/platform/abc/core.cljs
<- Cache read: hgs/platform/abc/core.cljs (8 ms)
-> Compile CLJS: hgs/platform/abc/core.cljs
<- Compile CLJS: hgs/platform/abc/core.cljs (358 ms)
-> Cache write: hgs/platform/abc/core.cljs
<- Cache write: hgs/platform/abc/core.cljs (45 ms)
Just in case it affects something - the file require
s some JS files. Both from NPM and from a dir relative to src
.
hmm then I don't know. you can compare the cache files before/after to see what changed besides the generated code
:compiled-at
and some other timestamp-looking values (transit cached the keys, can't really tell without deserializing).
you can use (shadow.build.cache/read-file (io/file ".shadow-cljs/builds/foo/...."))
in the REPL with the full path to the cache file
*read-cache Ah, that was stupid. The JS files are not changed. But their timestamps are.
Because shadow-cljs watcher works extraordinarily well 🙂 I will study/try hawk for now https://github.com/thheller/shadow-cljs/blob/master/src/main/shadow/util/FileWatcher.java
I thought hawk wraps some native library to give the same api as the native JVM — is that not the case?
> Like most clojure file watchers, hawk wraps the JDK 7 java.nio.file.WatchService API. This works great when Java has a native implementation for your platform of choice. However, this is not the case on OS X, so hawk also wraps the Barbary WatchService to provide performant monitoring even if you’re using a mac. An appropriate implementation is chosen automatically, so all you have to do is install hawk and relax.
yes, using is on macos because of the barbary watchservice. hawk however does not provide the API I want so I had to wrap it.
Fixed it, no cache misses now! And the file name stays the same, so that's great. But why is this step still executed though? Is it really needed given that the output file is already there and none of the cache entries got stale?
<- Closure - Optimizing ... (46580 ms)
@thheller Hi. Would it be possible to skip this step if nothing has changed? Or did something change and --verbose
somehow didn't show it?
there is no option currently but I could add a shadow-cljs release app --skip-optimize-if-unchanged
or something
ie. it can't possibly know that the output files exists when using :module-hash-names true
I think it could, if the manifest or cache contained all the relevant information, like hashes of all the source files that are fed into a particular version of GCC. But I have no idea how fragile that would be.
hi, is it possible to get source maps working with Web Workers? Debugging the following errors is difficult otherwise:
Uncaught Error: nth not supported on this type cljs.core/PersistentArrayMap
at Function.eval [as cljs$core$IFn$_invoke$arity$3] (/js/compiled/cljs-runtime/cljs.core.js:6349)
at eval (/js/compiled/cljs-runtime/orgpad.client.layout.webworker.ops.js:23)
at Object.eval [as cljs$core$IFn$_invoke$arity$3] (/js/compiled/cljs-runtime/cljs.core.js:36362)
at Function.G__27279__2 [as cljs$core$IFn$_invoke$arity$2] (/js/compiled/cljs-runtime/cljs.core.js:14986)
at eval (/js/compiled/cljs-runtime/cljs.core.js:8044)
at Function.eval [as cljs$core$IFn$_invoke$arity$3] (/js/compiled/cljs-runtime/cljs.core.js:8045)
at Object.eval [as cljs$core$IReduce$_reduce$arity$3] (/js/compiled/cljs-runtime/cljs.core.js:10474)
at Function.eval [as cljs$core$IFn$_invoke$arity$3] (/js/compiled/cljs-runtime/cljs.core.js:8198)
at Object.orgpad$client$layout$webworker$ops$apply_ops [as apply_ops] (/js/compiled/cljs-runtime/orgpad.client.layout.webworker.ops.js:177)
at eval (/js/compiled/cljs-runtime/orgpad.client.layout.webworker.handle.js:71)
I am trying to make a bundle with shadow-cljs that uses quil library, that has as transient dependency p5
cat package.json { "dependencies" : { "moment" : "^2.24.0", "p5" : "^0.10.2", "shadow-cljs" : "^2.0.41" } }
cat shadow-cljs.edn {:dependencies [[org.pinkgorilla/gorilla-renderable "2.1.2"] [quil "3.1.0"] [awb99/shapes "0.1.2"] [awb99.fortune "0.0.1"]], :source-paths ["src"], :builds {:gorilla {:target :bootstrap, :output-dir "out/gorilla", :exclude #{cljs.js}, :entries [fortune.core pinkgorilla.ui.gorilla-renderable quil.sketch quil.middleware quil.core "moment"]}}}
t\"; ignoring it"} {:line 98747, :column 13, :message "illegal use of unknown JSDoc tag \"submodule\"; ignoring it"} {:line 98748, :column 13, :message "illegal use of unknown JSDoc tag \"for\"; ignoring it"} {:line 99350, :column 13, :message "illegal use of unknown JSDoc tag \"submodule\"; ignoring it"} {:line 99351, :column 13, :message "illegal use of unknown JSDoc tag \"for\"; ignoring it"}], :resource-name "node_modules/p5/lib/p5.js", :js-requires [], :js-errors [{:line 69565, :column 0, :message "Invalid delete operand. Only properties can be deleted."}], :goog-requires [], :tag :shadow.build.npm/errors, :uses-global-buffer false, :uses-global-process false} ExceptionInfo: errors in file: /home/andreas/Documents/gorilla/kernel-cljs-shadowdeps/node_modules/p5/lib/p5.js shadow.build.npm/get-file-info* (npm.clj:549) shadow.build.npm/get-file-info* (npm.clj:472) shadow.build.npm/get-file-info (npm.clj:586) shadow.build.npm/get-file-info (npm.clj:583) shadow.build.npm/find-resource (npm.clj:677) shadow.build.npm/find-resource (npm.clj:638) shadow.build.resolve/find-npm-resource (resolve.clj:109) shadow.build.resolve/find-npm-resource (resolve.clj:80) shadow.build.resolve/fn--11285 (resolve.clj:235) shadow.build.resolve/fn--11285 (resolve.clj:211) clojure.lang.MultiFn.invoke (MultiFn.java:244) shadow.build.resolve/resolve-string-require (resolve.clj:349) shadow.build.resolve/resolve-string-require (resolve.clj:332) shadow.build.resolve/resolve-require (resolve.clj:545) shadow.build.resolve/resolve-require (resolve.clj:538) shadow.build.resolve/resolve-deps/fn--11240 (resolve.clj:51) clojure.lang.PersistentVector.reduce (PersistentVector.java:343) clojure.core/reduce (core.clj:6827) clojure.core/reduce (core.clj:6810) shadow.cljs.util/reduce-> (util.clj:47) shadow.cljs.util/reduce-> (util.clj:46) shadow.build.resolve/resolve-deps (resolve.clj:49) shadow.build.resolve/resolve-deps (resolve.clj:33) shadow.build.resolve/resolve-symbol-require (resolve.clj:532) shadow.build.resolve/resolve-symbol-require (resolve.clj:491) shadow.build.resolve/resolve-require (resolve.clj:542) shadow.build.resolve/resolve-require (resolve.clj:538) shadow.build.resolve/resolve-deps/fn--11240 (resolve.clj:51) clojure.lang.PersistentVector.reduce (PersistentVector.java:343) clojure.core/reduce (core.clj:6827) clojure.core/reduce (core.clj:6810) shadow.cljs.util/reduce-> (util.clj:47) shadow.cljs.util/reduce-> (util.clj:46) shadow.build.resolve/resolve-deps (resolve.clj:49) shadow.build.resolve/resolve-deps (resolve.clj:33) shadow.build.resolve/resolve-symbol-require (resolve.clj:532) shadow.build.resolve/resolve-symbol-require (resolve.clj:491) shadow.build.resolve/resolve-require (resolve.clj:542) shadow.build.resolve/resolve-require (resolve.clj:538) shadow.build.resolve/resolve-deps/fn--11240 (resolve.clj:51) clojure.lang.PersistentVector.reduce (PersistentVector.java:343) clojure.core/reduce (core.clj:6827) clojure.core/reduce (core.clj:6810) shadow.cljs.util/reduce-> (util.clj:47) shadow.cljs.util/reduce-> (util.clj:46) shadow.build.resolve/resolve-deps (resolve.clj:49) shadow.build.resolve/resolve-deps (resolve.clj:33) shadow.build.resolve/resolve-symbol-require (resolve.clj:532) shadow.build.resolve/resolve-symbol-require (resolve.clj:491) shadow.build.resolve/resolve-require (resolve.clj:542) shadow.build.resolve/resolve-require (resolve.clj:538) shadow.build.resolve/resolve-deps/fn--11240 (resolve.clj:51) clojure.lang.PersistentVector.reduce (PersistentVector.java:343) clojure.core/reduce (core.clj:6827) clojure.core/reduce (core.clj:6810) shadow.cljs.util/reduce-> (util.clj:47) shadow.cljs.util/reduce-> (util.clj:46) shadow.build.resolve/resolve-deps (resolve.clj:49) shadow.build.resolve/resolve-deps (resolve.clj:33) shadow.build.resolve/resolve-symbol-require (resolve.clj:532) shadow.build.resolve/resolve-symbol-require (resolve.clj:491) shadow.build.resolve/resolve-require (resolve.clj:542) shadow.build.resolve/resolve-require (resolve.clj:538) shadow.build.resolve/resolve-entry (resolve.clj:552) shadow.build.resolve/resolve-entry (resolve.clj:551) clojure.lang.PersistentVector.reduce (PersistentVector.java:343) clojure.core/reduce (core.clj:6827) clojure.core/reduce (core.clj:6810) shadow.cljs.util/reduce-> (util.clj:47) shadow.cljs.util/reduce-> (util.clj:46) shadow.build.resolve/resolve-entries (resolve.clj:563) shadow.build.resolve/resolve-entries (resolve.clj:554) shadow.build.targets.bootstrap/resolve (bootstrap.clj:56) shadow.build.targets.bootstrap/resolve (bootstrap.clj:48) shadow.build.targets.bootstrap/process (bootstrap.clj:278) shadow.build.targets.bootstrap/process (bootstrap.clj:271) clojure.lang.Var.invoke (Var.java:384) shadow.build/process-stage/fn--12425 (build.clj:148) shadow.build/process-stage (build.clj:145) shadow.build/process-stage (build.clj:137) error Command failed with exit code 1.
hmm looks like p5.js does something weird ... check what happens in the :line
it lists
:js-errors [{:line 69565, :column 0, :message "Invalid delete operand. Only properties can be deleted."}]
its a bunch of warnings .. which you can ignore. the :js-errors
above is the one causing the crash
Can I see somewhere the version of the npm modules for which you have provided cljsjs wrappers?
So what happened to me is that the clojurescript compiler detected something bad in the npm bundle of p5 ?
well not really .. the code probably runs otherwise. if they'd run their code through a linter that would likely catch it too
I'm using shadow with :target :react-native
(based on the reagent-react-native
template) and connecting to the cljs repl from emacs/cider. One unexpected behavior is that when I evaluate an expression over cider that throws an error, the trace is displayed in the simulator window, and no feedback is given in emacs/cider. Is that expected? Is there a way to get the exception to come back to emacs/cider so I can see it there?
the eval happens in a try/catch so the react-native side probably intercepts the error somehow?
So yeah, seems like something about the react-native environment is intercepting the exception. Any tips on how to track that down?
Yeah no worries, I just tried it with a regular :target :browser
shadow project, and a similar thing happens, it just prints the error in the repl buffer instead of popping up a *cider-error*
buffer. So I'm guessing that this is actually something to do with how shadow emulates piggieback.
Don't mean to belabor this, but if you're curious, there must be something in the piggieback repl protocol that tells cider that an error occured during evaluation, which cider uses to present some UI indicating this. It appears that shadow emulates piggieback in a way that cider doesn't get this info. If there's any interest in tracking this down, I'd be thrilled to help, but if you consider it too low priority, that'd be understandable.
happy to add whatever is needed but I have no energy to spend on tracking yet another cider nrepl issue myself
since there are no docs for any of this it is likely just an nrepl message missing some field or something
Hi, is it possible to get REPL for a Web Worker?
@pavel.klavik not currently no
and concerning the source maps I mentioned above? I am just able to get to Javascript code which is not very useful to debug Clojurescript
source maps in Web Worker
I'm not sure why they don't work. I'd expect them to work. haven't used workers myself for years
sure, I will produce some example and make an issue, thx
outside of these two issues, I am quite happy with Web Workers support in Shadow, super easy to get it working
is there any way to include CSS?
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";