This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-03-06
Channels
- # babashka (60)
- # beginners (36)
- # clj-kondo (29)
- # clojure (91)
- # clojure-dev (18)
- # clojure-europe (12)
- # clojure-nl (1)
- # clojure-norway (11)
- # clojure-uk (5)
- # clojuredesign-podcast (8)
- # clojurescript (40)
- # core-typed (74)
- # data-science (8)
- # datomic (9)
- # emacs (22)
- # events (5)
- # fulcro (56)
- # gratitude (3)
- # hyperfiddle (11)
- # lsp (6)
- # malli (36)
- # meander (23)
- # off-topic (50)
- # polylith (4)
- # portal (10)
- # reitit (4)
- # schema (1)
- # shadow-cljs (66)
- # squint (3)
- # tools-deps (16)
When you mix shadow-cljs with many js components, how do you tree shake the end result to reduce the bundle size usually ?
shadow-cljs does not perform tree shaking for npm packages, what is "required" (as in :require
in ns) will stay
I remember you saying this on this group before, that's because I'm asking usually which tool ppl use to reduce JS bundle.
webpack is hairy 🙂
if you use packages that allow direct requires you can usually just manually tweak a bit to get the same result with just shadow-cljs
"Lucide is built with ES Modules, so it's completely tree-shakable.", its a huge file, that you can use in dev mode, but reducing size the final artifact is necessary.
Yeap, I think so.
Do you folks have any example repo using webpack to tree-shake an shadow-cljs project? I'm interested to se the developer experience of using this.
(sorry to intrude)
some restrictions to the REPL and hot-reload apply as JS stuff can no longer be loaded dynamically
ah ok, I will do some studies 🙂 Thanks
can't remember the exact options used but basiscally just input/output and production mode
I've switched to esbuild to process jsx. It's easier, than babel + packages/@ui. I've followed https://shadow-cljs.github.io/docs/UsersGuide.html#js-provider-external. Thomas , in theory , is it possible to join lib.js generated from target/index.js and main.js and tree shake ?
:js-options {
:js-provider :external
:external-index "target/index.js"
:external-index-format :esm
}
To compile with esbuild I'm using ./node_modules/.bin/esbuild target/index.js --bundle --outfile=resources/public/js/app/lib.js
you can use https://shadow-cljs.github.io/docs/UsersGuide.html#_third_party_tool_integration instead of target :browser
and run it completely through esbuild
otherwise no, you cannot and should not join the external file with the regular output
With :js-options {:js-provider :import} the modules must be :modules {:demo {:exports {default demo.lib/hello}}} like in the example ? I'm asking because with :target :browser I'm using :modules :modules {:main {:init-fn dulcis.client/init}}
:exports
creates actual ESM export
, so in case you want to use the output from JS or something
note that I do no recommend this, it comes with more downsides than :js-provider :external
You don't recommend :js-provider :import ?
I don't recommend post processing the shadow-cljs output with a secondary build tool
For development that is more than fine, but If we are bundling many npm dependencies and targetting production, to strip unused code there isn't another way than :js-provider :import and let another tool to be used. Is that right ? What would be the downsides ?
I don't know what these sizes represent. I don't know what you are trying to optimize
did you create a build report and check what is actually in your build? https://shadow-cljs.github.io/docs/UsersGuide.html#build-report
I didn't create a build-report. These sizes represent a bunch of @radix-ui components, that I'm using to test the configuration, and main.js is the entry point of :target :browser shadow-cljs app with just a component on the screen. What I'm trying to achieve is way to tree-shake the three-shakeable code that are bundled in lib.js. It seems to me that if I'm using :js-provider :external that's not possible, because I'm not feeding main.js to a external tool. What I understood from what you said, is that there is another option, :js-provider :import and I'm assuming that it does not generate a target/index.js, and I'll have just one artifact, main.js, and the external tool can process that code and hopefully tree-shake the javascript code.
it is. it doesn't need to see main.js
, everything it needs to know is contained in the external-index
:external-index-format :esm
being the essential part, without that no tree shaking can occur
I'm using :external-index-format :esm
Please tell me , how It can effectively remove js code if it just see the imports in the index.js and do not have access to main.js which has the usage or not of the import ? I've noticed that If I put a library in package.json it only goes to target/index.js if it's imported in cljs code. So the shadow-cljs compiler is already computing what is being imported in target/index.js.
shadow-cljs knows what you used in the code, since it built that. so that is put into the external index.
This one is very small target/index.js
import * as i0 from "react-refresh/runtime";
import * as i1 from "react";
import * as i2 from "react/jsx-runtime";
import * as i3 from "react-dom/client";
import * as i4 from "@ui/components/ui/label";
import * as i5 from "@ui/components/ui/input";
import * as i6 from "@tanstack/react-query";
const ALL = {};
globalThis.shadow$bridge = function(name) {
const ret = ALL[name];
if (ret == undefined) {
throw new Error("Dependency: " + name + " not provided by external JS!");
} else {
return ret;
}
};
ALL["react-refresh/runtime"] = i0;
ALL["react"] = i1;
ALL["react/jsx-runtime"] = i2;
ALL["react-dom/client"] = i3;
ALL["@ui/components/ui/label"] = i4;
ALL["@ui/components/ui/input"] = i5;
ALL["@tanstack/react-query"] = i6;
Oh I see.
The output of a release build is different. Now that's make sense.
Thank you for you patience and support 🙂
Hello! 👋
I'm facing an issue when tree shaking nested references for dependencies imported with :refer
. If I use the dot notation (.-nested parent)
or import it using the :as
reference it seems to be working fine.
Am I missing something or is this a known issue?
(I created a tiny repo with the reproducible issue here: https://github.com/vloth/treeshaking-shadow-repro)
[also let me know if you'd like me to re-ask this in a regular message and not in this thread to keep things separated]
AppShell.Header
is not valid. it just works by accident basically. and what "breaks" exactly? please include actual errors in repros. running stuff takes to long and most of the time I can answer by just seeing the error
sorry, I've added there!
Using it together with reagent, I get an error from react telling me I tried to render undefined
, which cannot be accepted as a valid component.
I did some troubleshooting and it seems like the library itself doesn't change with these syntax changes, so it seems like the undefined
is coming mostly from main.js.
Almost as if the bridge function were not able to connect things as expected