I my example, I trying to bundle a very simple React page with shadow-cljs, in both dev mode and release mode:
based on new shadow-cljs of importing JavaScript files from a local directory:
https://code.thheller.com/blog/shadow-cljs/2017/11/10/js-dependencies-in-practice.html
{:resolve {"my-thing" {:target :file
:file "path/to/file.js"}}}
which is cool, because shadow-cljs uses Google Closure Compiler to optimize JavaScript.
This is only an experiment though. I asked thheller about that before, shadow-cljs was not designed for JavaScript. So I’m only trying to prove that js dependencies work well. When there are errors or file changes in js, shadow-cljs does not prettify it anyway.
Interesting though these days there are still new bundlers coming out in JavaScript community like http://parceljs.org and GitHub - developit/microbundle: 📦 Zero-configuration bundler for tiny modules. .
1 Like
Confusing to me that the main.js
file is quite large(88k
) even though react
and react-dom
has been moved to lib.js
(104k
).
(ns main
(:require ["app" :as app]))
(defn main! []
(app/main))
(defn reload! []
(app/reload))
(set! js/window.onload main!)
I thought everything would be optimized away since not code is really used in this file. But it has the size of 88k
then something from ClojureScript should be there.
main.js
is basically just cljs.core
which doesn’t get fully eliminated. As I said before I have zero interest in making shadow-cljs
something you would use to build pure JS projects so don’t expect it to be optimized for that.
However I do want to fully support “hybrids” and make use of some JS while the bulk of the app is written in CLJS.
You can greatly simplify your project if you move everything to the src
path and include it via relative paths. No need for the custom :resolve
then.
(ns main
(:require ["./app" :as app]))
Relative paths are not supported by CLJS itself and I’m still working out some details on this myself so consider this feature very alpha. I do want easier interop between CLJS<->JS though and this is one important thing left to finish. It is almost ready but the GCC is getting in the way sometimes.
1 Like
Updated. so many hidden features in shadow-cljs…
I was looking at this as well and thought the same but at the same time the CLJS code seems so basic that I don’t see why most of core would not get eliminated? It’s definitely possible to build 5kb .js
files from ClojureScript.
@jiyinyiyong I wonder what how big main.js
is if you change main.cljs
to this:
(ns main
(:require ["app" :as app]))
(defn main! []
(js/console.log "starting"))
(defn reload! []
(js/console.log "reloading"))
(set! js/window.onload main!)
Maybe also try with and without the require
. Would be weird if that affects dead code elimination though, wouldn’t it?
Setting :build-options {:print-fn :none}
(ie. don’t call built-in enable-console-print!
) and removing all prn
might make things smaller.
If you really want you can build without any CLJS code (JS only) which means cljs.core
won’t even be included so it doesn’t have to be removed in the first place.
Either way there really is very little to gain trying to optimize this. Any real CLJS app will use a lot from cljs.core
so it will stay alive regardless.
The results are the same no matter what I do, add :print-fn :none
, writing js/console.log
, it’s all:
=>> du -ah dist
4.0K dist/index.html
104K dist/lib.js
88K dist/main.js
4.0K dist/manifest.edn
200K dist
I noticed that in the js file I can’t import React as I did in Webpack:
import React from "react"
leads to React.Component
error, which compiles to x$index.default.Component
, while x$index.default
is undefined
. But instead x$index.Component
is the code I wanted it to get.
As a result I have to change that to:
import {Component} from "react"
Yeah this situation is a bit fuzzy right now. "react"
is not distributed as ES6 and CommonJS<->ES6 interop is still being worked on (not usable from CLJS yet).
I might go back to using babel
for all ES6 files since I’m currently using Closure for ES6 inside the project itself but babel
for everything from node_modules
. I wanted to test Closure for project files since they should be :advanced
compatible (in theory). babel
works a bit better for the moment.
I can’t find the link but the “official” spec for ES6/CJS interop for node
is probably how this will work in the future.
2 Likes