Shadow CLJS + Webpack
Nov 4, 2022In this post, I’ll share how I’ve gotten shadow-cljs
working alongside Webpack using the :esm
target. This allows for Webpack’s tree-shaking of JavaScript dependencies while still having all the benefits of shadow-cljs
.
For Vistaly.com (a product-strategy startup I’m co-founding), we were using large JavaScript libraries (such as AWS Amplify) and because of this, we had a very large bundle size.
Before the switch, our bundle size was 11MB uncompressed 🐢. CloudFront only compresses files under 10MB (source), which meant our users had to wait to download the full 11MB before their app would load.
By switching to ESM + Webpack, our bundle size decreased to 3.7MB uncompressed / 0.81MB compressed (via Brotli compression). To end-users, there was a 93% decrease in the quantity of data that had to be downloaded 🐇.
There were minimal changes needed for this (it was mostly trial and error to get the pieces working well together). First I updated shadow-cljs.edn
. By specifying :js-provider :import
, I’m having shadow-cljs
leave the bundling of JS dependencies to Webpack.
Secondly, I created a webpack.config.js
file. Moving forward, the local running server will be Webpack’s dev server. Hot reloading will still be done by shadow-cljs
. I also added source-map-loader
so that you can view ClojureScript source-maps from within your browser.
Lastly, I had to update our babashka scripts to reflect the changes.
The dev
command changed to utilize npx webpack serve
along with DEV_MODE=true
, while the release
command changed to utilize npx webpack
.
Hope that helped! if anything wasn’t clear or you’re interested in Vistaly, you can find me on the Clojurians Slack channel (@dehli
). Talk soon! 👋