This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-06-30
Channels
- # aleph (33)
- # announcements (2)
- # architecture (1)
- # babashka (4)
- # beginners (26)
- # calva (43)
- # cider (2)
- # clerk (24)
- # clj-kondo (10)
- # clojure (75)
- # clojure-austin (1)
- # clojure-dev (4)
- # clojure-europe (31)
- # clojure-hungary (1)
- # clojure-norway (44)
- # clojurescript (4)
- # cursive (192)
- # datomic (23)
- # dev-tooling (4)
- # emacs (2)
- # fulcro (12)
- # hyperfiddle (3)
- # java (18)
- # jobs (1)
- # kaocha (3)
- # lsp (51)
- # malli (10)
- # off-topic (9)
- # pedestal (3)
- # polylith (14)
- # remote-jobs (1)
- # shadow-cljs (63)
- # vim (6)
I'm looking for advice on how to minimize the size of my build. Right now it's at about 350kb. The only dependecy is a pure cljs library, which itself has no dependencies. I thought I'd read that it was possible to get shadow cljs builds down to ~90 kb in the best case, but in the build report I'm seeing that just cljs/core.cljs itself is 166.75kb, so I don't see how the project could get smaller than that. What's a reasonable lower bound on how small shadow cljs builds can get, and are there any tips that might help me get my build to be smaller?
If the cljs library uses pprint and a bunch of cljs core functions, then there's not much you can do IMO
did you create build report? https://shadow-cljs.github.io/docs/UsersGuide.html#build-report
It does use pprint but I can remove that for the build, it's only included for debugging. The library is one I've written myself, so I can make changes to it to to help reduce the size as well. Does the size of the cljs/core.cljs file depend on the number of different cljs core functions I'm using, or does the whole thing get included if I use any of them? I might be able to avoid using some if that would help
yes, here's the report if it's helpful:
ah ok. I knew pprint was already adding a lot because cljs/pprint.cljs itself was 89.98kb, but if getting rid of that will also shrink cljs/core.cljs then that might be all that I need
82.47kb would be reasonable enough for most use cases, but for this project I'll be uploading all of the code to the ethereum blockchain, so... every kb is $$$
depends on how many core collections and protocols you use. in theory cljs.core can be fully eliminated, but even accessing pr-str
or something print related will keep pretty much everything alive
if you want to dive really deep into optimizations you can run with shadow-cljs release browser --pseudo-names
and wade through the output looking for "big chunks" of code
they usually stand out in some way, running through prettier js or something might help too
ok, good to know. Another thing I've thought about to reduce the size is going through the compiled js file and removing all calls to throw() and more generally any error handling code. The code will be well-tested before it goes live and if there are any bugs then there's no way to update the code once it's on-chain, so there's not really any point in having code for handling errors. There doesn't happen to be a compiler option or anything that would do something like that for me, does there?
its somewhat straightforward to identify what the code belongs to, then you can maybe figure out if you actually need it
gzipped, thankfully.
the --pseudo-names thing sounds very helpful, thanks
as a general tip avoid variadic or multi arity functions. those generate much more code than regular single arity functions
@ellahoeppner honestly, Ethereum is the last place id store compiled CLJS code... yes google closure is amazing at DCE and optimization, but there's so many little things in CLJS that simply are not eliminated by Google closure (unused map keys, unused top-level data structures), ..., and some things, by design, are impossible to tree shake (specs, multimethods, ...) while arithmetic etc on Ethereum costs about 20 gas, storage is 20k gas, so i would try to use google closure itself with vanilla JS to get as many optimization as possible, and prefer brotli over gzip if it is possible to use brotli compression or better yet, store the code elsewhere...
I didn't know eth runs on JS? or is this really just for storage and some other contract thingy? (I know next to nothing about eth)
@hifumi123 I disagree. only because the compiler can't optimize it doesn't mean a human can't. so if you are careful you can write very minimal code. the question is if you are still writing CLJS in the end if you give up too much stuff
I have been able to write very tiny CLJS software, too, but it doesn’t do anything interesting compared to when you can afford bundling all of cljs.core 😛
I think we agree on this point: if you’re give up almost everything CLJS offers to get smaller bundle size, then what is the value of CLJS?
yeah, lots of value in cljs.core for sure but sometimes you have other priorities such as absolute size
butI disagree that switching to "vanilla JS" is necessary, you can achieve the same in just CLJS size wise
Hi, I'm trying to use the npm package @walletconnect/modal-sign-html but it depends on @walletconnect/modal which does some await import. This seems to be an issue (with an error message such as "Uncaught (in promise) Module not provided: @walletconnect/modal-ui"). Is there a way to circumvent this with shadow-cljs right now?
The code is the following one
import{ModalCtrl as t,ThemeCtrl as o,ConfigCtrl as i,OptionsCtrl as n} from "@walletconnect/modal-core";
class d {
constructor(e) {
this.openModal=t.open,
this.closeModal=t.close,
this.subscribeModal=t.subscribe,
this.setTheme=o.setThemeConfig,o.setThemeConfig(e),i.setConfig(e),
this.initUi()
}
async initUi() {
if (typeof window<"u") {
await import("@walletconnect/modal-ui");
const e=document.createElement("wcm-modal");
document.body.insertAdjacentElement("beforeend",e),
n.setIsUiLoaded(!0)
}
}
}
export{d as WalletConnectModal};
do you have a reference explaining the current limitations regarding this feature?
its not supported at all. period. no limited support or anything, just not supported as of today.
and frankly I don't see why they do this in the first place. is it too much to ask your users to require @walletconnect/modal-ui
if they need it?
and this is what I recommend doing too? whats the point of this small nonsensical code?
I believe the recommendation I made the last time is to use webpack instead like this https://shadow-cljs.github.io/docs/UsersGuide.html#js-provider-external
or if I follow this can of worms you can just skip @walletconnect/modal-sign-html and @walletconnect/modal entirely and implement it yourself. its probably less than 50 lines of code. but given the way all these libs seem to be structured webpack seems like a better path, they seem to rely heavily on it.
All right, I'm going to think about doing this right
Thanks
why not just upload the source code? also depending on what you're trying to write, couldn't you bundle nbb with it and would that ever be smaller (but slower)?
sorry, stupid idea then. I thought there might be some cross-over where the cost of loading the interpreter was less
if you're looking for ultra-small files but still want to have some something that looks like CLJS, try #C03U8L2NXNC - you can use esbuild to optimize it to a single file, should usually be under 10kb or so
sorry because this is totally off topic and none of my business, but how did you reply so fast? do you have some sort of notification-driving query for keywords set up?
is there a programatic way to enumerate multiple instances of the same app in the shadow.cljs.devtools.api? eg. I yarn start the same app twice, now in the shadow-cljs web portal I can see that there are two REPLs under Runtimes, in order to connet to a specific one I need their ID (?). I can't see a way to get to that through the API, skimming the shadow-cljs ui code it looks like it tracks them through mutating the DB when connection messages are received
@hifumi123 @zimablue the context here is that I'm creating a generative art piece for an ethereum art platform, http://alba.art. The platform expects me to upload a html file (where all the js that defines the piece is included in inline <script> tags) that will be put on the blockchain, and then people can view the piece through the alba site, which retrieves the code from the blockchain and runs the code in their browser. So just uploading the cljs source code wouldn't work, it needs to be executable js. The code is uploaded to the blockchain so collectors can be assured that the piece will still be accessible many years down the line, as opposed to just being on some private server that could get shut down. Of course I could just write everything in vanilla js instead, but I've developed a graphics library and workflow with cljs that I'm very fond of, so having to give up on cljs entirely would really suck. In the long-run I might try to build up a new library/workflow in js or some language that can target WASM to reduce my file sizes in future projects, but in the short-to-medium run I'll be working with cljs, so the smaller I can get the shadow-cljs build to be, the better.
I have an nginx server that is serving my built JS locally over HTTPS. I'm trying to configure the websocket to connect over HTTPS as well. How do I do this?
I've tried configuring :ssl {:keystore ,,, :password ,,,}
at the top level of my shadow-cljs.edn
, but it continues to try and connect over an insecure websocket connection
DOMException: Failed to construct 'WebSocket': An insecure WebSocket connection may not be initiated from a page loaded over HTTPS.
at Function.eval [as cljs$core$IFn$_invoke$arity$2] (js/compiled//cljs-runtime/shadow.cljs.devtools.client.websocket.js:25:15)
at Function.eval [as cljs$core$IFn$_invoke$arity$1] (js/compiled//cljs-runtime/shadow.cljs.devtools.client.websocket.js:20:52)
at Object.eval [as attempt_connect_BANG_] (js/compiled//cljs-runtime/shadow.cljs.devtools.client.shared.js:481:77)
at Object.shadow$cljs$devtools$client$shared$init_runtime_BANG_ [as init_runtime_BANG_] (js/compiled//cljs-runtime/shadow.cljs.devtools.client.shared.js:969:16)