[ClojureScript] Re: Seeking advice for a reducing the size of compiled scripts
I wasn't aware of that :rename-prefix-namespace compiler option. That's awesome, I'll look into it. Thanks -- Note that posts from new members are moderated - please be patient with your first post. --- You received this message because you are subscribed to the Google Groups "ClojureScript" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojurescript+unsubscr...@googlegroups.com. To post to this group, send email to clojurescript@googlegroups.com. Visit this group at https://groups.google.com/group/clojurescript.
[ClojureScript] Re: Seeking advice for a reducing the size of compiled scripts
> > Thomas, my concern with using :modules is polluting the global scope. We > deliver code for other companies to run on their websites and putting > multiple variables on the global scope is too risky. That being said, maybe > I can wrap each module's code in a function that aliases `window` - I > haven't explored that avenue much. > It is possible to isolate the globals and only create one, that however comes at the cost of a few extra bytes for each variable that would otherwise become a global (eg. var foo; becomes $CLJS.foo). See :rename-prefix-namespace compiler option. > When I last looked at where the KBs come from using > https://github.com/danvk/source-map-explorer there were not many > surprises - a lot of the size came from closure's libs, clojurescript.core, > and my application code. The only third party libs I'm still using are > preact and reagent. > Since CLJS is missing all source maps of foreign-libs they will not show in source-map-explorer, so make sure your "bytes" are fully accounted for and not accidentally including something that shouldn't be (usually indicated by a big blank area). shadow-cljs generates far more accurate build reports [1][2] for JS stuff but CLJS is mostly the same so if thats where all the bytes are coming from it won't show anything more. > I agree about cljs being competitive and providing something much better > than what we get with plain js. Sadly, telling customers that our script is > bigger because we use a better programming language doesn't always satisfy > them. ¯\_(ツ)_/¯ > They might care about better code quality which CLJS tends to have (IMHO). ;) [1] https://shadow-cljs.github.io/docs/UsersGuide.html#_build_report [2] https://code.thheller.com/demos/build-report/huge.html -- Note that posts from new members are moderated - please be patient with your first post. --- You received this message because you are subscribed to the Google Groups "ClojureScript" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojurescript+unsubscr...@googlegroups.com. To post to this group, send email to clojurescript@googlegroups.com. Visit this group at https://groups.google.com/group/clojurescript.
[ClojureScript] Re: Seeking advice for a reducing the size of compiled scripts
Thanks Antonin, I wasn't aware that top-level data defs are universally bad for DCE. Yuri, I think you're right in general, but my application can be compiled with particular features excluded so multimethods are problematic even in my application code. And I've found that with re-frame applications unless I'm very disciplined about removing dead code I end up with unused event handlers - I'm sure some people experience the same with multimethods. That's an easy problem to solve, but in closed systems like applications I've always found that static dispatch with a big `case` or something similar works fine. -- Note that posts from new members are moderated - please be patient with your first post. --- You received this message because you are subscribed to the Google Groups "ClojureScript" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojurescript+unsubscr...@googlegroups.com. To post to this group, send email to clojurescript@googlegroups.com. Visit this group at https://groups.google.com/group/clojurescript.
[ClojureScript] Re: Seeking advice for a reducing the size of compiled scripts
> Avoid multimethods and other global registries like re-frame. These thwart DCE because there’s no way to know at compile time that a specific method/handler is never used. Isn't this advice only applicable to libraries which have a lot of multimethods in the implementation? If the project codebase itself (not the libraries) contains multimethods then I suppose they are all needed in production potentially and thus should never be eliminated. -- Note that posts from new members are moderated - please be patient with your first post. --- You received this message because you are subscribed to the Google Groups "ClojureScript" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojurescript+unsubscr...@googlegroups.com. To post to this group, send email to clojurescript@googlegroups.com. Visit this group at https://groups.google.com/group/clojurescript.
[ClojureScript] Re: Seeking advice for a reducing the size of compiled scripts
Here are some of my findings when trying to make cljs-devtools library more DCE friendly: https://github.com/binaryage/cljs-devtools/issues/37#issuecomment-293575471 Not sure if they still apply today, the post is from Apr 2017. good luck, Antonin On Thursday, December 20, 2018 at 5:18:34 PM UTC+1, Tom Connors wrote: > > At work we use clojurescript to implement a front-end with minified and > gzipped assets coming in at around 170KB. If I can’t reduce that > substantially I’ll probably have to rewrite in javascript. I’m posting to > share some ideas I have for reducing the size of the script and to ask for > any additional techniques others have used to get smaller scripts. > > Things I can do right now: > >- Measure the impact of every library: I’ve found that transit adds >about 12KB gzipped and core.async adds even more (probably variable due to >the transformations performed by the go macro). Reagent is >surprisingly light - about 4KB. I’m using preact instead of react, so that >lib is an almost negligible 3KB. Importantly, I’ve found that some APIs >provided by google closure can have surprising impacts on script size. >Don’t use goog.xhr - do direct interop for http requests. >- Avoid multimethods and other global registries like re-frame. These >thwart DCE because there’s no way to know at compile time that a specific >method/handler is never used. >- Remove unnecessary parts of data structures. If you have a literal >vector of maps where each map has a key or two that isn’t used by code >(perhaps it’s just information for developers), those unused keys won’t be >DCE’d >- Make use of goog defines to get rid of code paths that you can >determine to be unnecessary at compile time. >- Avoid using apply for functions that implement a lot of different >arities. The clourescript compiler tends to be really smart about this - > if >you implement 1, 2, and 3 arity versions of a function and only call the >two arity one, the 1 and 3 arity versions can get DCE’d. If you use >apply, however, all the arities end up in the script. >- Do a second round of minification with uglify or some other >minifier. I haven’t tested this in a while, but when I did last time it >saved a KB or two. At least it compresses the Math.imul definition at the >top of the script. > > Aside from dropping heavy libraries, those are all incremental changes. In > order to get really substantial size savings, I think changes would need to > be made to clojurescript. I have no idea about the feasibility of these > things. > >- (ideally) automatically (but probably based on configuration) remove >unused methods of type definitions. For example, cljs.core.UUID implements >the equiv method of Object. Suppose we know at compile time that we >will construct UUIDs but not compare them with anything. It would be great >to be able to remove that method’s definition. I doubt this is possible >without a static type system, but I wonder whether there is some way to >make this configurable that wouldn’t lead to an explosion of configuration >options and inscrutable errors. >- Some functions implement multiple arities for dispatch performance. >I would like to be able to say “I accept the performance hit in exchange >for only implementing one arity of this function”. For instance, >partial implements multiple arities of its own args and of the >function it returns. This could be reduced down to (defn partial [f & > more] >(fn [& args] (apply f (concat more args if we cared more about script >size than runtime performance. > > Any other ideas? > > > -- Note that posts from new members are moderated - please be patient with your first post. --- You received this message because you are subscribed to the Google Groups "ClojureScript" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojurescript+unsubscr...@googlegroups.com. To post to this group, send email to clojurescript@googlegroups.com. Visit this group at https://groups.google.com/group/clojurescript.
[ClojureScript] Re: Seeking advice for a reducing the size of compiled scripts
Nathan, yes, I'm using advanced compilation, thanks. Thomas, my concern with using :modules is polluting the global scope. We deliver code for other companies to run on their websites and putting multiple variables on the global scope is too risky. That being said, maybe I can wrap each module's code in a function that aliases `window` - I haven't explored that avenue much. When I last looked at where the KBs come from using https://github.com/danvk/source-map-explorer there were not many surprises - a lot of the size came from closure's libs, clojurescript.core, and my application code. The only third party libs I'm still using are preact and reagent. I agree about cljs being competitive and providing something much better than what we get with plain js. Sadly, telling customers that our script is bigger because we use a better programming language doesn't always satisfy them. ¯\_(ツ)_/¯ Thanks for the suggestions. -- Note that posts from new members are moderated - please be patient with your first post. --- You received this message because you are subscribed to the Google Groups "ClojureScript" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojurescript+unsubscr...@googlegroups.com. To post to this group, send email to clojurescript@googlegroups.com. Visit this group at https://groups.google.com/group/clojurescript.
[ClojureScript] Re: Seeking advice for a reducing the size of compiled scripts
Did you look into using Code Splitting aka :modules to reduce the size of the initial download? Did you check where your 170KB actually come from? Including things like cljs.pprint can add quite a bit and isn't commonly used in production builds but can't be DCE'd (yet), similarly other namespaces can bloat the final output just by being required. Modifying the compiler to remove certain signatures or other tweaks is likely asking for trouble and there is currently no option to do this. With that being said CLJS output is generally very competitive or even smaller than comparable JS builds if you account for what you are actually using. The Closure Library is also built for maximum compatibility which is less relevant these days but can still save hours of debugging if you care about supporting older systems, at the cost of a few extra bytes. Don't just compare with vanilla JS without immutable datastructures, sane equality semantics and so on. Cheers, Thomas On Thursday, December 20, 2018 at 5:18:34 PM UTC+1, Tom Connors wrote: > > At work we use clojurescript to implement a front-end with minified and > gzipped assets coming in at around 170KB. If I can’t reduce that > substantially I’ll probably have to rewrite in javascript. I’m posting to > share some ideas I have for reducing the size of the script and to ask for > any additional techniques others have used to get smaller scripts. > > Things I can do right now: > >- Measure the impact of every library: I’ve found that transit adds >about 12KB gzipped and core.async adds even more (probably variable due to >the transformations performed by the go macro). Reagent is >surprisingly light - about 4KB. I’m using preact instead of react, so that >lib is an almost negligible 3KB. Importantly, I’ve found that some APIs >provided by google closure can have surprising impacts on script size. >Don’t use goog.xhr - do direct interop for http requests. >- Avoid multimethods and other global registries like re-frame. These >thwart DCE because there’s no way to know at compile time that a specific >method/handler is never used. >- Remove unnecessary parts of data structures. If you have a literal >vector of maps where each map has a key or two that isn’t used by code >(perhaps it’s just information for developers), those unused keys won’t be >DCE’d >- Make use of goog defines to get rid of code paths that you can >determine to be unnecessary at compile time. >- Avoid using apply for functions that implement a lot of different >arities. The clourescript compiler tends to be really smart about this - > if >you implement 1, 2, and 3 arity versions of a function and only call the >two arity one, the 1 and 3 arity versions can get DCE’d. If you use >apply, however, all the arities end up in the script. >- Do a second round of minification with uglify or some other >minifier. I haven’t tested this in a while, but when I did last time it >saved a KB or two. At least it compresses the Math.imul definition at the >top of the script. > > Aside from dropping heavy libraries, those are all incremental changes. In > order to get really substantial size savings, I think changes would need to > be made to clojurescript. I have no idea about the feasibility of these > things. > >- (ideally) automatically (but probably based on configuration) remove >unused methods of type definitions. For example, cljs.core.UUID implements >the equiv method of Object. Suppose we know at compile time that we >will construct UUIDs but not compare them with anything. It would be great >to be able to remove that method’s definition. I doubt this is possible >without a static type system, but I wonder whether there is some way to >make this configurable that wouldn’t lead to an explosion of configuration >options and inscrutable errors. >- Some functions implement multiple arities for dispatch performance. >I would like to be able to say “I accept the performance hit in exchange >for only implementing one arity of this function”. For instance, >partial implements multiple arities of its own args and of the >function it returns. This could be reduced down to (defn partial [f & > more] >(fn [& args] (apply f (concat more args if we cared more about script >size than runtime performance. > > Any other ideas? > > > -- Note that posts from new members are moderated - please be patient with your first post. --- You received this message because you are subscribed to the Google Groups "ClojureScript" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojurescript+unsubscr...@googlegroups.com. To post to this group, send email to clojurescript@googlegroups.com. Visit this group at https://groups.google.com/group/clojurescript.