always-be-clojuring / issues

16 stars 0 forks source link

Migrating from Javascript to Clojurescript #8

Open alex-dixon opened 6 years ago

alex-dixon commented 6 years ago

I've been investigating using JS from CLJS, in particular using React components that have already been written in JS that are not part of a library or npm module.

Observations:

I write this against the background of the State of Clojure 2018 survey, which shows most devs are coming from Javascript. Even if JS devs are sold on the language, they may still walk away without a path to using it. Using JS from CLJS mitigates risk for developers and stakeholders alike. We should show how that migration 1. never really has to take place, 2. how to migrate JS code to CLJS code if or when that's desired.

thheller commented 6 years ago

@alex-dixon shadow-cljs itself can be used via lein or clojure or pretty much anything else that is able to run clojure and build a classpath. I wrote about this some time ago.

What the shadow-cljs "binary" provides is a convenient way to install it via npm and an optimized experience to run it from the CLI (this started before tools.deps was even announced). I still recommend running it standalone because your CLJS really doesn't gain anything by being embedded into your Clojure REPL. Neither the other way around. You just now have to deal with conflicts between your CLJS and CLJ libs. That being said it works perfectly fine embedded.

Tool support for Standalone currently is not great because most tools pretty much only support project.clj. This should get better once deps.edn gets adopted more or tools support shadow-cljs.edn directly.

At this point shadow-cljs provides many different ways for integrating JS and could in theory also build entirely JS-only projects which I have done here. You of course would never do this but taking a project from create-react-app and start adding .cljs files is pretty darn simple. It is also possible to just use webpack to do the final "bundle".

The whole issue is that ClojureScript is built with the Closure Compiler in mind. This means that is assumes that you will run whole-program optimizations. This makes it a terrible fit if you want to write libaries in it and compile those to JS. If you however are able to feed it the entire code the results are enormously better than any other JS tool out there. The entire JS ecosystem is not built with whole-program optimizations in mind and this is sort of a mismatch between Closure and npm. JS tools like prepack or rollup are years behind Closure but a step in the right direction. ES6 also makes things much easier to integrate since its less dynamic than CommonJS.

:npm-deps will not work properly with the current state of npm unless you are very careful to only pick dependencies that provide pure ES6, which is only a tiny fraction of packages at the moment.

If you have a concrete question/example of what you are trying to do I'm fairly certain that shadow-cljs already has a working solution. If not I'll happily add it.