Hey,

I understand what you want to achieve and I definitely want to make the 
whole thing easier but some issues don't have an easy solution.

TL;DR: It's complicated.

First we need to split compilation and bundling.

CLJS->JS compilation just takes one .cljs file and compiles it to .js. To 
do that it needs analyzer data of all CLJS dependencies. If you were to 
publish compiled CLJS to npm you'd need to also ship the analyzer data 
somehow. The other problem is that certain compiler options affect the 
generated JS which means that for every .cljs file there are many possible 
.js results. Another thing is that you also need to account for the 
compiler version since that may also affect the output or the analyzer data 
which then may affect other files.

The second part is bundling things together, which means reducing the 
number of individual files down to a more reasonable number. shadow-cljs 
enables JS tools to do that for us (eg. webpack, create-react-app or any 
other), since those tools use "require" to discover dependencies.

The best option for this however is to use the Closure Compiler but to get 
the whole benefit of it you need to optimize your whole program, which 
includes EVERY .js file. There is promising progress in Closure to support 
optimizing common js and ES6 code but it is not quite there yet and can't 
compile everything. It will be coming to shadow-cljs soon though, it is 
already in CLJS but I didn't hook it up yet since I wanted to solve some 
issues first. 

:npm-module tries to bridge the gap a little but as soon as you don't 
optimize your whole program you need externs to teach Closure about the 
things it can't see. Which means you can still use :advanced compilation 
for the CLJS/Closure parts but the rest of the code remains untouched. It 
also means that you need a second bundler (eg. webpack) to then combine the 
Closure output with the remaining unoptimized parts.

Given all these constraints I don't think it is feasible to publish 
compiled (but unbundled) CLJS code as a library to NPM. It would be 
relatively easy to consume uncompiled .cljs code from NPM packages but 
unless everybody agrees to do that it would just make things a whole lot 
more complicated for everyone. Maven is also a whole lot better than NPM 
IMHO, npm or yarn just have better UX (until something breaks).

:npm-deps is a feature in CLJS that lets you declare which npm packages 
your CLJS code requires to work. Technically this would need a complement 
in package.json to allow declaring which CLJS packages the JS code needs. I 
don't have a solution for that and I was and still am opposed to whole idea 
of :npm-deps. It does however solve the issue from the CLJS perspective, 
just not from the "Play as a Team" JS perspective.

I do want integration to be painless and I do think shadow-cljs already 
makes life easier for some. I am very interested to hear about any other 
pain points people may have with CLJS<->JS interop. I tested webpack, 
create-react-app and create-react-native-app. They are all work reasonably 
well but I haven't gone beyond basic examples.

I really don't have a good solution for the problem since part of the 
solution must come from the JS world and I have basically no idea what 
people are doing over there.

The whole problem basically boils down to which bundler you want to use.

I'm personally only considering the Closure Compiler for that and 
shadow-cljs is trying to make that as easy as possible with support for 
common JS / ES6 coming soon.

If you want to use webpack or so that also works reasonably well already 
but CLJS really is built with the Closure Compiler in mind so the end 
result of this won't be optimal.

If you want both that is always going to require more manual work for 
:externs and come with certain caveats.

I hope that made some sort of sense, I have been thinking about this a lot 
but haven't gotten very far.

/thomas

On Sunday, July 9, 2017 at 3:29:15 AM UTC+2, Kurt Harriger wrote:
>
> Thomas,
>
> First thank you for starting this project!
>
> I recently joined a team at Atlassian that uses ClojureScript to support 
> collaborative editing.  I don't think I need to sell the community here on 
> the advantages of ClojureScript, but I think packaging still needs work.
>
> If you use ClojureScript for your entire UI you probably don't have any 
> issues, but in larger organizations we need to "Play as a Team." It does 
> not seem feasible or reasonable to expect that other teams switch to using 
> the ClosureScript compiler and make their js libraries play nice with 
> closure because the end result will be marginally better, especially given 
> the work involved in ensuring they still work with advanced optimizations 
> may be non-trivial.
>
> The only practical alternative I'm currently aware of is to precompile the 
> ClojureScript with optimizations and have them include this as a script tag 
> in their page.  The disadvantages of this are many:
>
> * separate download - not bundled with other js libraries
> * not commonjs / cannot require / pollutes global namespace 
> * install/upgrade/versioning process is different / change script tag 
> rather than npm/yarn
> * each precompiled ClosureScript library will include closure and cljs 
> again
>
> As we add support for multiple editors I want to split the library into 
> multiple artifacts that can be released separately, however that last 
> bullet point is undesirable.  I have had some success in adding a cljsbuild 
> along side a webpack build, but CommonJS has solved a lot of pain points 
> for JS devs and most modern js devs now expect an npm artifact. 
>
> Although shadow-cljs doesn't solve having different install/version 
> process it does appear to solve the other issues and is better than using a 
> script tag.
>
> I did have a general question though. I understand that if you compile 
> multiple ClosureScript libraries independently each will end up with 
> duplicate bits of closure and cljs core. Shadow-cljs, as I understand it, 
> appears to solve this by first compiling all the ClosureScript code 
> together and exposing it as a commonjs module. But thinking out-loud 
> here...isn't sharing dependencies the problem npm is trying to solve? could 
> we leverage that instead of reinvent it?  
>
> What if google closure libraries and cljs.core were published as their own 
> commonjs npm libraries - precompiled but not minified yet? Couldn't cljs 
> libraries then just 'require' them without resulting in another copy or 
> requiring the closurescirpt compiler (and jvm)?  In my ideal world, I think 
> I would be able to specify :npm-module as the clojurescript compiler target 
> and it would generate js that can be packaged in npm that 'requires' rather 
> than bundles cljs and closure.  Minification can be done downstream with 
> *all* the javascript, not just the cljs code. I also found a closure plugin 
> for webpack https://www.npmjs.com/package/webpack-closure-compiler (I 
> never used it though), so maybe we can still get just as good if not better 
> results doing it later? 
>
> I'm not sure what would be involved in rewriting cljs output to require 
> "require" closure and cljs.core as their own libraries, but maybe the 
> partially solved already with 
> https://github.com/clojure/clojurescript/wiki/JavaScript-Module-Support-(Alpha)
> ?
>
> 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.

Reply via email to