If I run npx shadow-cljs run shadow.cljs.build-report client report.html in the reagent project, do I get a build report as produced with advanced CLJS? π§΅
hey. completely missed this thread. seems like you sorted out the sizes? as for using lite mode you can just use deps.edn local root or git dep for cljs. that'll override the shadow-cljs preferred version. since there were no breaking changes that should be just fine. you should also be able to just set :compiler-options {:lite-mode true :elide-to-string true} for it to function.
I have not actually tested that, but see no reason why that wouldn't work.
I did try this and it failed with some mysterious errors. If I'm back at the kbd today I can try again
I mean a dev build will almost certainly not work, but release builds should be fine
I honestly don't quite see the point of lite-mode though. react alone is like 5 times of what is saved, so seems like a drop of water in a very big bucket π
still curious about it though. will try to test myself when I find the time.
deps.edn:
{:paths ["src"]
:aliases
{:dev {:extra-paths ["test" "examples/todomvc/src" "examples/simple/src" "examples/geometry/src" "demo"]
:extra-deps {org.clojure/clojurescript {:git/sha "f9a6856d91e45377391406fc34a581bc4043615e"
:git/url ""}
doo/doo {:mvn/version "0.1.11"}
funcool/promesa {:mvn/version "11.0.678"}
thheller/shadow-cljs {:mvn/version "3.2.1"}}}}}
$ cat shadow-cljs.edn
{:source-paths ["src" "test" "examples/todomvc/src" "examples/simple/src" "examples/geometry/src" "demo"]
:dev-http {8090 {:roots ["site/public" "target/shadow-cljs/client/public" "classpath:public"]}}
:builds
{:client {:target :browser
:output-dir "target/shadow-cljs/client/public/js"
:asset-path "/js"
:modules {:main {:entries [reagentdemo.prod]}}
:devtools {:ignore-warnings true}
:compiler-options {:warnings {:fn-deprecated false}
}}
:test {:target :karma
:output-to "target/shadow-cljs/resources/public/js/karma.js"
:output-dir "target/shadow-cljs/resources/public/js"
:asset-path "js"
:source-map true
:compiler-options {:infer-externs :auto}
:ns-regexp "(reagenttest\\.test.*|reagent\\..*-test)"}}
:deps {:aliases [:dev]}
#_#_:dependencies [[doo "0.1.11"]
[funcool/promesa "11.0.678"]]}
npx shadow-cljs run shadow.cljs.build-report client report.html
https://gist.github.com/borkdude/ce742cb399d5a1d8afd7e98af810268cseems I have to fix the source paths in deps.edn
hmm, those paths already exist in the alias so should be ok
hmm yeah weird. seems like that :jsdoc is incorrect
I have never bothered with type annotations for the closure compiler, so not sure what this means
shadow-cljs uses a newer closure compiler version that regular cljs, so maybe thats why its passing regular tests?
not sure I set anything in shadow-cljs that would affect this otherwise. I even opt out of some jsdoc related warnings
ah, goog-define already infers the type, so it just doubled. dunno why that extra jsdoc is there then https://github.com/clojure/clojurescript/blob/df04ee2c41ce7683b52c5793d0154ca88771f0f7/src/main/clojure/cljs/core.cljc#L758-L762
ah no I just remembered that I do in fact override the goog-define macro
https://github.com/thheller/shadow-cljs/blob/a819bbaad20b021d177f7b0b3564a5972b2da900/src/main/shadow/build/cljs_hacks.cljc#L707 I suspect this is the issue
IIRC I only added this because I wanted to update the closure compiler but CLJS was using an older incompatible version, so had to override. I guess this isn't needed anymore.
@borkdude Reagent shadow-cljs.edn is now updated so that the build from release command doesn't include the test suite, and matches the public site
small suggestions but since reagentdemo.main is only calling (core/init!) you might as well get rid of that one entirely and just use :modules {:main {:init-fn reagentdemo.core/init!}} in the build config
I'm still keeping cljsbuild configs around and this seems work for those also
There is also script to build the demo site with cljs.main + webpack: ./test-environments/bundle-adv/build.sh
β― ls -l target/cljsbuild/prod-npm/public/js/main.js target/shadow-cljs-release/client/public/js/main.js target/bundle-adv/resources/public/js/main.js
-rw-rw-r-- 1 juho juho 551069 loka 6 15:57 target/bundle-adv/resources/public/js/main.js
-rw-rw-r-- 1 juho juho 547944 loka 6 15:58 target/cljsbuild/prod-npm/public/js/main.js
-rw-rw-r-- 1 juho juho 556878 loka 6 15:58 target/shadow-cljs-release/client/public/js/main.js
tiny differences between the artifact sizes with shadow-cljs, cljs.main+webpack, cljsbuild+npm-deps
And with lite?
I guess I can add a new build for that, based on the cljs.main version
if you want to tweak the size a bit you can set :compiler-options {:shadow-keywords true}. shaves off a few pct with no downsides
probably not too much. build doesn't seem to contain that many keywords
Hiccup does contain keywords though?
556878 -> 549788
yeah about what I expected. many different keywords is what I meant to say. that option has the most impact when lots of namespaced keywords are involved. don't see many in the code for that build
I'm getting pretty much the same artifact size for lite-mode + elide-to-string. Even a bit bigger output.
Ah hm the options isn't working correctly for some reason, I see both cljs.core.Vector cljs.core.PersistentVector uses.
Can you push a branch or something with lite mode? Perhaps we can show it to David to see if there is a bug in lite
I'm seeing + react-dom @ npm: 19.1.0 337.58 KB 36.2 % + org.clojure/clojurescript @ mvn: 1.12.42 304.06 KB 32.6 % + demo 116.61 KB 12.5 % + src 36.26 KB 3.9 % which looks a bit much?
is it possible to also see the gzipped sizes for individual packages? I guess not since zipping the whole is more efficient than the parts
Builds reports are generated for release builds, yes. But what do you mean by "a bit much"? As compared to what?
compared to numbers advertised elsewhere about react. I also noticed that the current reagent demo is 150kb gzipped. why has it grown with 100kb (gzipped)? not complaining, just trying to understand. context: https://mastodon.social/@borkdude/115310243716064865
Does it include both the minimized and debug file?
I don't know
when I do a release build, the size is the same
"+" on the row shows the invidual files
compared to numbers advertised elsewhere about reactGotta know what's being used and done exactly to compare apples to apples.
No actual idea but could be that the React is very amenable to tree shaking that GCC doesn't do.
From the context:
> React was 35K-40K gzipped
Just tested - react-dom-client.production.js.gz from 19.2.0 is already 94 kB.
Closure could optimize (tree-shake) JS files, but that breaks many JS libs, so Shadow-cljs doesn't use that for npm deps.
hmm
Shadow-cljs also allows using webpack or other tools for tree-shaking
https://shadow-cljs.github.io/docs/UsersGuide.html#_js_tree_shaking
so if I would run this through esbuild with --minify it could get smaller
yes
minified by esbuild: $ ls -lat /tmp/min.js -rw-r--r-- 1 borkdude wheel 947936 3 okt. 14:58 /tmp/min.js same size basically
No clue how React's react-dom is split into files, but files in v18 seem to be significantly smaller than in v19.
I wrote about using ESBuild a white back: https://www.metosin.fi/blog/2024-09-05-using-shadow-cljs-with-esbuild Though the shadow-cljs integration with :shadow.build/stage there is unnecessarily complex and there should be a better way.
I don't think you can just pass the shadow-cljs output to esbuild
at least if it is the regular browser output
there won't be the es6 module imports etc. there anymore for esbuild to process?
true
:js-provider :external works by finding the cljs ns require forms targetting npm libs -> shadow-cljs writes out a entry file for those libs and then you give just that entry file to esbuild
worth a shot indeed
FWIW, these are the files in the build report:
Source Optimized
node_modules/react-dom/cjs/react-dom-client.production.js 167.43 KB
node_modules/react-dom/cjs/react-dom-server.browser.production.js 84.56 KB
node_modules/react-dom/cjs/react-dom-server-legacy.browser.production.js 81.51 KB
node_modules/react-dom/cjs/react-dom.production.js 3.3 KB
node_modules/react-dom/client.js 273
node_modules/react-dom/index.js 270
node_modules/react-dom/server.browser.js 245those server files being included isn't normal
with js-provider: :main [JS: 581.51 KB] [GZIP: 139.43 KB]
when I then minify and bundle the file with esbuild: same size:
esbuild --bundle --minify target/shadow-cljs/client/public/js/main.js > /tmp/min.js947767oh right you are looking at reagent demo site
that isn't very typical project
no wait I didn't release build yet, just the build report. wait a sec
yes, the demo site, since I was comparing with: https://chr15m.github.io/eucalypt/ which is of course not a fair comparison since eucalypt is just a cheap imitation of reagent
the normal entrypoint for reagent demo site also contains full reagent test suite
which also tests react-dom/server uses
which a normal app wont do
todomvc for example shows 170KB for react-dom
ok, with js-provider external I get 587473.
same with --bundle - it seems esbuild isn't picking up.
ah ok. what is the non-normal entry point for the reagent site or is it always built like this?
hmhm, it could be the site is always built like this
you can switch :modules {:main {:entries [http://reagentdemo.dev]}} -> :modules {:main {:entries [reagentdemo.prod]}}
nice! let me test
Might be it should be included in the config for release builds... maybe I have lost it accidentally at some point
much better: 361617
o wait, this was still with external providr
That's more like it:
Perhaps you are using the merge option at site deploy time
because this looks similar to what's currently deployed
deployed site doens't use shadow-cljs in fact
it is using the lein-cljsbuild version
that is why shadow-cljs config doesn't use that prod entrypoint
I see! I wanted to see the build report, this is why I looked at this
and it using clojurescript compiler npm-deps... which hmm, probably passes React code through Closure Compiler also
I have tested that React is one of JS libs that does seem to work after it goes through Closure Compiler
So the deployed artifact might be different size vs shadow-cljs
looks similar though, 150kb gzipped
compared to current "production" site
just ran a quick test locally bare bones uix app 303kb, 85kb gzipped same in reagent 335kb, 93kb gzipped
> I have tested that React is one of JS libs that does seem to work after it goes through Closure Compiler React's production builds distributed via NPM are in fact built with Closure Compiler
What Closure Compiler or other JS bundler could do, is to through out some exported functions that project doesn't use. Though that would also require that those functions are only users of some parts of React internals so those can be dropped. But Reagent anyone uses big part of the API so likely there isn't much that could be dropped.
Probably they would have split it up in multiple modules if you could save a lot of space, like they did with react-dom/server
I wonder if we can re-test this with CLJS master with lite mode and elide toString
Not sure how to do this with shadow from CLJS master in reagentβs shadow config
@borkdude https://github.com/reagent-project/reagent/pull/642
Cool, I posted the link in #cljs-dev