Hacker News new | comments | ask | show | jobs | submit login
ClojureScript Year in Review (swannodette.github.io)
288 points by pella on Dec 24, 2015 | hide | past | web | favorite | 58 comments



I highly recommend devs (especially JS devs) try out a Clojure/script project. The tooling has improved immensely, and Cursive is one hell of an IDE. JS devs will really appreciate how clearly you can express these seemingly new frontend paradigms (immutability, one way data flow, single source of state) in Clojure.

Not to mention that REPL-driven development and hot-reloading are so pleasant to work in, leading to development environments like this: https://github.com/danielsz/holygrail

I'm curious if any Clojure veterans would weigh in on the state of Boot.. is it gaining traction, or is the consensus to stick with Leiningen?


Trying out Clojure/Script is really too. I recommend starting with Reagent https://reagent-project.github.io/ as it has a minimal API and requires learning only a handful of concepts. Here's all you need to get started:

Install OpenJDK: http://www.azul.com/downloads/zulu/

Install Leiningen: http://leiningen.org/

Create a new project and run it:

lein new reagent myapp

cd myapp

lein figwheel

This will start the live ClojureScript compiler and your app will be available at localhost:3449

You can now navigate to the src/cljs/myapp/core.cljs file and start editing it. Any changes you make will be reflected live in the browser without having to reload the page. I recommend trying the code from the Reagent docs page linked above in the project.


Have you tried out React + ES6 ? whats your opinion on clojurescript versus that.

Especially when you bring in concepts like generators [1] (as a replacement for clojurescript's async), destructuring,etc.

[1] https://babeljs.io/docs/learn-es2015/


I'm working on a React+ES6 project professionally, and use Clojurescript+Reagent for all my hobby projects. I would gladly use cljs+reagent for everything if I could.

First off, cljs allows you to type less. Second, functionality provided by Immutable.JS is built into the language. Third, I can use paredit. I love paredit. Fourth, google closure has amazing code minification, dead code removal and a good standard library. Fifth, I've found figwheel to be better to react-hot-loader, the latter cannot always reload my application. Sixth, devcards. Seventh, incremental compile speed is faster. Eight, macros can greatly simplify code you're writing and allow new syntax to be exposed by libraries (core.async).


thank you for writing such a detailed reply.

But it seems that 4 out of your 8 points are covered by external libraries that are pretty good - Immutable is great... lodash is great... and google closure compiler is usable (https://github.com/mihaip/react-closure-compiler). I use systemjs/jspm as well as its hot reloader and it works great (unless a particular component is legacy JS.. which will be a problem anywhere).

Not really refuting your point, but ES6/ES7 (and from what I'm hearing.. Typescript) with all these libraries have sort of taken over the mindshare that clojurescript used to have.

IMHO the only reason for me would be the package manager. I mean Systemjs/jspm is okay.. but the whole AMD/global/cjs/webpack/requirejs/browserify crap is way too much. Nothing works anywhere in the javascript world .


Google Closure is usable, but only if you write your app in a way that is google closure compatible, the same goes for any dependencies you pull in. In clojurescript, all code you write, and any pure cljs library, is google closure compatible.

Immutable.js is great, but your libraries probably doesn't use it, and you have to make sure you use it everywhere as well. This can lead to subtle bugs that boils down to using .value instead of .get('value'), a problem you'll rarely encounter in cljs where everything is immutable by default.

I haven't used systemjs/jspm, so I can't say anything about that. I can only say that I have yet to encounter a case where figwheel doesn't successfully reload my code, whereas I encounter this in webpack/react-hot-loader all the time.

ES6/ES7/Typescript are great improvements over ES5. But you have to pair it with Immutable.js for it to be comparable to the offering that cljs provides. Even then, when you have a setup that gives many of the same benefits as cljs, you'll have written way more code, and you need to be a bit paranoid to make sure you're using the correct API at the correct place, and that you don't have any libraries that are incompatible with your setup.

In short. While you can have a setup that gives you all the advantages of cljs+om/reagent, it's just a lot easier to do it in clojurescript.


You are completely true. In fact I spent the last couple of days fixing some incompatibility issues with Handsontable - a very popular spreadsheet component.

But that's precisely my point. Is there value in a pure language when you will need to leverage tons of third party libraries...most of which are incompatible? To get anything meaningful done, you would need to write EVERYTHING in cljs...or you could use a component which will be in old js. So where's the tru value of cljs in a real life project.

Let's take Handsontable - to cover all the corner cases that a spreadsheet needs, it would take me an inordinate time. But it does not even play well with npm..forget cljs


I've done a fair bit of integration with handsontable from clojurescript. It has been excellent so far. Clojurescript isn't really a pure language, it just makes some types of purity the default. If you need to get dirty and mutable then that's simple, still simpler than plain js in my opinion.

Clojurescript and Clojure have very good interop with their host language, integrating 3rd party libs is very simple. To be fair, you will have to write the glue code more often than when working in js since there is a smaller user base.


Is your handsontable/cljs work open source? Would love to see it. I have given up on handsontable being usable in a modern js setup. I had to fall back to including it in a script tag and get it to work. Am quite interested to see if I can build it in cljs


Unfortunately it's not, but I find out if that is a possibility.

And now that you mention it you have jogged my memory about having to sidestep our build process in some unfortunate ways. We're certainly not passing it through Google Closure, we have to use the handsontable build scripts to remove unused features.

Getting it to co-exist with React was the real tricky part, but Rum was quite useful in providing the hooks to make handsontable act like a react component.


Yup! Thats precisely what I wanted to see.

Thanks for trying.


To clarify: the react aspect is the part you wanted to see?


The way you got handsontable to work in your setup. That would be awesome - that would be a good learning of how to integrate complex, legacy js packages in cljs.


Well, if you literally have to leverage TONS of third party libraries, most of which are incompatible, then I would at least be glad that my code, the ui framework, the date handling library, the routing library, the ajax and the validation library, was all written using compatible and immutable by default code.

It's better to have a problem with some dependencies, than to have an issue with your entire codebase. So yes, I would argue that clojurescript has value.


I was about to write a comment like Skinneys below, but he/she put it so well.

I found this joke on r/ProgrammerHumor and it strikes me that I've been falling into this trap for the majority of my career.

> You know what we need? Another mostly imperative garbage collected language, that's what. If we just tweak the syntax and feature set just right, it will change everything!"

As Skinney writes, the mix of libs and tools that you base your webapp on might not be what the libs you want to use the next months agree with.

Use of immutable collections are nearly pointless if only parts of your app use it, and you have to carefully maintain barriers that translate to/from them. Clojure(Script) makes their use succinct and natural, something I doubt yet another lib can make ES2015/TypeScript do.


I find ClojureScript to be far preferable. The language is much better designed in my opinion. It's simple and consistent, while being very flexible and expressive. from what I can tell it does everything ES6 does and more right now.

The biggest problem with ES6 is that JavaScript just keeps growing as a language. It has lots of features and quirks already, and more are getting added. This is what you end up dealing with when using ES6 + React (https://i.imgur.com/AjSTP20.png).

I think the problem with this is that it adds mental overhead when you're reading and writing code. Something that looks like it might be doing one thing does something subtly different. This leads to hard to debug errors and wastes you time. It also distracts you from the actual problem you're solving.

I also find tooling for ClojureScript is better in many areas. Instead of having to juggle things like npm, gulp, grunt, and so on. You can use a single build tool like Leiningen that handles all those things. You have a live coding environment with Figwheel, and you get an editor integrated REPL where you can inspect things easily at runtime.

I've been using ClojureScript in prod for about a year now without any issues. I simply wouldn't go back to using Js at this point.


I'm not a boot guru, so take my $0.02 with a grain of salt.

I've been using boot for smaller and experimental projects because by default it feels so much leaner then leiningen does, however, because the support tooling around leiningen is still so further advanced, for project we're putting into production here, those are still all lein based.

The other thing I'd say is, I've found what tool lein vs boot gets minimized over time as the project evolves.

In general, I do think it's gaining traction and its a great project!


I've done Clojure, but haven't had much contact in the last several months, and I haven't been keeping too close tabs on the community. Regarding Boot, I just heard of it the other day for the first time.

This all seems really exciting for Clojurescript. To me, it seems like it is a good option to have code that runs on multiple architectures. The ecosystem was lacking in some basics though, especially interacting w/3d party JS libraries, and I think CLJSJS (or something like it) will probably be one of the most important things for Clojurescript.

Seems like there's a decent quickstart on the Clojurescript github wiki (https://github.com/clojure/clojurescript/wiki/Quick-Start), is there a good next-steps resource that's current?


I have nothing to say on Lein vs Boot, but I'm a long-term emacers with > 10 years and I can't endorse Cursive strongly enough. I've got easily at least 1k hours in my .emacs.d. Suffice it to say, it takes a lot to take away from Emacs/SLIME. Never bought into the Textmate hype during the Ruby days, or the SublimeText hype subsequently because Emacs already had all that functionality if not out of the box, there certainly was someone with an .el I could borrow. It takes a lot for me to leave Emacs, especially for a LISP.

Here's my 2 cents - Cursive is worth it. (Hey Ideogram folks, if you want an endorsement, feel free to use that paragraph in exchange for a lifetime license ;)). For one-off-scripts, for back-end solutions, and what tipped me over the edge, it's CLJS script integration goes beyond acceptable -- it's actually fun to work in-- Cursive is my go-to. Om and Figwheel (optionally with Prismatic Schema if you like type guarantees) makes web development's feedback loop a lot tighter.

Rich Hickey assembled a team of just insanely talented and charismatic(1) developers who not only are a) remarkably intelligent but b) know when to steal ideas and integrate them [none of that too-proud-NIH-syndrome there], and c) know how to interact in a way to that is community-feedback-positive(2) so people contribute. Watch this talk by David Nolen https://www.youtube.com/watch?v=ByNs9TG30E8 (CLJS lead). [Sidebar - He even mentions how that whole immutable, one way data flow, datomic-ish single state idea existed in other languages, but read (2) on that].

Anyways, Cursive + Lein + ClojureScript + Om is the holy grail for me right now. On the other hand, that nREPL/cider/boot setup is what I'd be using as a long-time emacs'er were I to give up Cursive.

(1) Having someone like Hickey or Nolen to shepherd ideas is actually really important in garnering traction. Developers go to conferences and when everyones talking about that 4PM Thursday talk that someone gave, it really resonates within the community for quite a while. I like Perl 6's ideas but if you've ever seen Larry Wall talk, well, yeah. (2) Some communities cough Haskell have great ideas, Lenses, FRP, applying (pun not intended) monoids -> functors -> applicative functors -> monads was genius. But for some reason the barrier to entry is so high (even for me with a fairly advanced math background) that concepts remain isolated within the community. LINQ is a monad (though few know it) and it took Brian Beckman (or Anders, or Bart de Smet, or whomever) to take it into C# to make the concept widely used by the Joe-the-programmer (again, pun not intended).


Hey Ideogram folks, if you want an endorsement, feel free to use that paragraph in exchange for a lifetime license ;)

Well, I'd hate to be accused of buying positive reviews :-). But thanks, I really appreciate it and I'm glad it's working well for you.

One of my main goals for 2016 is to focus heavily on CLJS support to bring it fully up to par with Clojure support. Better REPLs, a much easier getting started story, testing support, a debugger, and as much support as seems to be required for React Native. I'm increasingly convinced that CLJS may turn out to be more important than Clojure, and certainly has the potential to bring a lot more devs to the CLJ(S) world if it manages to take off properly.

One of my main aspirations with Cursive is that it can help make both languages more accessible. I think Clojure support in Cursive is further along that path and I'm hoping to do the same for ClojureScript this year.


I've been a vim user for a number of years and have fiddled with building in Clojure support at different times with repl support, syntax highlighting and other basics. My success was varying and incomplete. Tooling has been a barrier for me learning Clojure. Half the time I want to learn or practice Clojure, I remember gaps in my tooling. Subsequently, I spend a few hours yak-shaving to improve it.

I've contemplated learning Emacs because of the general praise for its workflow in the Clojure community. I even know some basic emacs from bash scripting. Switching just seemed like it would add another learning block to an already long list of tools to learn. Cursive, on the other hand, is based on IntelliJ, which is familiar to me through RubyMine.

Thanks for taking the time to write up about Cursive. You just convinced me to finally install it and give it a shot.


As a fellow vim user and full time clojure dev, I should point out that spacemacs is pretty great for getting the best of vim and emacs in one editor.

But to get up and running and try things out? Use Cursive until you are comfortable, don't get distracted by tooling problems (which there will be).


I've been using boot for about 6 months now and it's wonderful ... for doing build tasks (take my source and create some artifacts). Especially with the improvements just released in boot 2.5.

You will want to understand how pods and filesets work if you are doing anything interesting, as some interactions with them can be confusing if you don't have the right mental model. The wiki is quite good, but the source is a bit messy.

For code reloading type tasks things are bit less nice, mostly because of the immutable nature of pods and filesets that make build tasks so trouble free. That means incremental cljs compilation, cljs repls and auto-test type tasks (for clj and cljs). We have transitioned to just using functions run from the repl to manage our clojurescript tasks and it has been a big improvement.


How does ClojureScript/Reagent/Om/etc interoperable with "legacy" (heh) React + Webpack projects? I'd be interested in using our existing "dumb" React/JSX components with one of these new "Graph-Query-View" systems (Clojure or plain-old-JS)


Reagent allows using any React classes directly, an example can be seen in the cookbook

https://github.com/reagent-project/reagent-cookbook/blob/mas...


That holygrail project looks cool thanks. As a Clojure newbie, I'm not too fond of Lein to be honest.


Parinfer is the craziest lisp exponent ever. I highly recommend any curious and / or skeptical dev to download Atom, install it, and give it a shot. This book also helps: http://funcool.github.io/clojurescript-unraveled

From straight up confusion to basic productivity in just a week, it has also completely removed the learning fear. Highest regards to this beautiful tool that will hopefully bring lisp to the masses.


Thank you for the kind comment :) I'm glad you like atom-parinfer!


Diving into clj/s 4 months ago was such a wonderful, arbitrary decision. The #clojure community on Freenode is friendly and wildly clever. They are delighted to answer your Clojure questions. The language itself is great. It's a terrific language for a CS Sophomore to pick up after learning Scheme and Java.

My one complaint with cljs has been the difficulty of configuring Ring HTTP beyond the trivial SPA defaults: getting it to respond to other URL requests, other types of HTTP requests. I spent close to 3 hours trying to configure it to accept a POST action before finally giving up, frustrated by the opaque stack traces that went >1000 frames deep. 20 minutes later, I had an Apache server up and running. So it wasn't really a big deal, but I can't remember the last time I felt so baffled by a problem that I simply had to throw in the towel.


I put together the Luminus micro-framework http://www.luminusweb.net/ to help with this kind of stuff. The docs provide lots of examples on how to get stuff done. For example, here's the section on doing Ajax with ClojureSCript http://www.luminusweb.net/docs/clojurescript.md#ajax


Thanks for putting this together. This looks like a fantastic tool, and really well-documented. I noticed from a quick perusal of the docs that Luminus still requires a handler function to map URLs to a named page asset (about-page, home-page, etc.) using defroutes -- requiring too, of course, definitions for each of those pages. Could you explain in a few words why that is? Is it a Node requirement? Isn't that a lot of complexity to have to deal with? If so, how do people manage it?

I'm just curious because my only exposure to the HTTP layer so far has been via Apache. Apache is... for lack of a better word, a bro. It's up for just about anything. It seems like the default mode of Apache is to do whatever the HTML recommends. Apache is happy to serve an arbitrary "/about.html" URL, provided it exists, and asynchronously execute any server-side scripts to which it injects a dependency. I don't know if this strictly requires the use of jQuery, but it certainly seems easier to do it that way. Is it even possible to serve a cljs app this way? In light of the fact that jQuery is not compatible with the Google Closure compiler?


If no one has suggested it before: have you tried Compojure? I know very little about http but it was a snap for me. There's even a lein template.


Same here! Except college senior. You are lucky to have found Clojure so young :-)


For devcards, you can see the full strangeloop talk about the tool here: https://www.youtube.com/watch?v=G7Z_g2fnEDg


I meant to link to that one actually. Thanks for the catch, post updated.


Very cool to see such a robust community.

As far as self-compilation, I haven't seen anything on how to compile a ClojureScript project without Java, is there an article somewhere on how to do so?


One of the reasons that ClojureScript is so fast and efficient is that it leans heavily on the Google Closure optimizing compiler. This compiler goes beyond normal "minimzation" and goes into dead code removal, function inlining and a ton of other stuff. That compiler is written in Java. So it's highly unlikely that JVM is removed as a dev-time requirement anytime in the near future.

On the other hand, I have never really seen a need to remove it. Once the CLJS compiler is up and running, incremental compilations on huge codebases (~300 files) takes a fraction of a second. So in the end...I'd rather have the JVM as a requirement if it allows that fast of a dev cycle.


Another reason is that is doesn't do all the things that standard Clojure does, which are the actual cause for slowness, it is not the JVM.

http://blog.ndk.io/2014/02/11/jvm-slow-startup.html



I don't quite follow, this creates a cljs.core "analysis cache". I don't know what an analysis cache, but I guess it is something that's needed to compile ClojureScript code?

Has no one distributed such a cache in a way that it's easier to do a compile without Java installed? Is there not anything as simple as (where cljs-compile is a Node script):

  cljs-compile file.cljs > out.js
yet?


If memory serves, it is certainly possible to get up-and-running with CLJS without needing Java, but I cannot remember how. There is this tool, which might also be helpful: https://github.com/oakmac/cuttle


I'm exploring ClojureScript via the re-frame SPA pattern and it got me really excited about UI development again. What's the best way to sync data with a REST server backend?


I recommend the following: 1) read up on how Om.Next handles remote calls. Not that it's the only way to do it, but it de-couples the async functionality of a remote call from the rendering loop. 2) Just code against something like Google Closure's XHR libraries, making a HTTP call isn't complicated, just wrap basic functions to suit your needs.

But over all, no matter what you use, core.async, or callbacks or whatever, limit the async bits to the edges of your code. Done correctly (Om.Next is a great example) you shouldn't need a whole lot of async bits to get a nice clean app. If you have core.async "go" blocks littered all through your codebase, you're doing something wrong.


I recommend the cljs-ajax library https://github.com/JulianBirch/cljs-ajax


They do seem to be doing really nice things. And from time to time I try to keep up, watching videos on new tools and things.

But I guess I always get hung up on the idea that you should just write in the language that you're targeting, and I wonder about the cost of the (admittedly pretty nice) developer experience of cljs. When you have a bug in production you're stuck debugging the generated JS. This was also my problem with CoffeeScript.


I've been using ClojureScript in production for about a year now. The runtime is very fast, and in some cases it actually outperforms native Js. For example, both Om and Reagent are actually faster than React.js itself (http://www.youtube.com/watch?v=VSdnJDO-xdg&t=9m36s).

Debugging story is very good. You pretty much never have to see the generated JavaScript. ClojureScript uses source maps, so any errors in the compiled Js will map back to the original ClojureScript source that caused them. Chrome dev tools even do syntax highlighting for ClojureScript now.

Having a live dev environment with Figwheel and a REPL goes a long way here as well. You can inspect a lot of things at runtime very easily.

Using immutable data structures by default avoids a lot of the debugging pain as well. You practically never have to trace through a bunch of function calls to find the problem. In most cases the problem is exactly on the line where the error occurred.


What if your thing crashes in IE?


IE 11 supports source maps, so that's helpful. The other nice thing is that you rarely end up dealing with browser specific quirks since all popular ClojureScript libraries piggie back on React.js and the Google Closure library.

These do a great job of handling the platform specific quirks for you. The first app I developed with Reagent actually had to run on IE8, and to my shock and surprised worked without any issues after I added the standard IE shims.

So, overall my experience is that you're better off dealing with IE than with most Js frameworks.


I used to agree with you about writing in the language you are targeting, really strongly agreed. Coffeescript, for example, was something I never took seriously.

Clojurescript, and core.async in particular, changed my mind. It has converted me completely. The debugging issue is much less of an issue than I expected, since other methods of problem solving make more sense in a clojure context than breakpoint style line by line debugging.

Of course sometimes you do need to drop to that level, and it is a bit of a learning curve to debug the generated js, even with the great source maps, but it's not that bad. Overall I am still more productive by a big margin, and it's more enjoyable.


I think that cljs-devtools [1] also deserves honorable mention. Not only does this improve console output, but it improves inspection while doing interactive debugging (e.g., pause on exception) in Chrome.

[1] https://github.com/binaryage/cljs-devtools


Thanks for the plug. I'm glad you find it useful.

I've been working on Dirac - a Chrome DevTools fork for ClojureScript developers. That will be a complementary tool to cljs-devtools: https://github.com/binaryage/dirac


Clojurescript has made me excited about frontend again.


ClojureScript will enrich your mind but at some point you might get tempted, as I have, to switch to ES6/7 via the Babel route and enjoy the benefits of a much more diverse ecosystem, with your ClojureScript-enhanced perspective. Same with Elm and Haskell and prefty much any language wortg learning. In fact, learning a new language esp one drom a different world will always expand your horizon and I can't over recommend ClojureScript as one of those enlightenment languages.


I switched to using ClojureScript in prod last year and couldn't be happier. The Js interop is great, ClojureScript is fast, and the runtime is pretty small. I simply can imagine any reason to bother with ES6/7 at this point as they will offer nothing that's not already available in ClojureScript right now.

You also get a clean and well designed language as opposed to a mountain of kludges that is current state of Js https://twitter.com/capotej/status/677926991513780225


Since the GSoC project mentioned still seems to be incomplete, can anyone suggest a way to use npm/es2015 modules with cljs applications for the browser?

I build the first version of my app with cljs, and it was the cleanest/simplest code I ever wrote. Just the lack of npm interoperability makes in non-viable for me.

Anyone tried systemjs with cljs?


The simplest approach that works for this at the moment is to have something like webpack build a UMD bundle and then add that bundle as a foreign lib.


Really intresting clojure and clojurescript seems to be wonderfully designed and with the advancements that's going to take place in jvm I hope it can be as good at performance as java or Go.


I don't know about Go, but it certainly is as fast as Java. And it can definitely be faster than your average Java program, because you will have a really easy time doing concurrency. That is why it is a neat language, worth investigating.

It is by default slower than Java and Go because the default data structures are immutable. When execution speed is more important than statelessness you can make your data structures mutable.

Read more about that here http://clojure.org/transients

Happy holidays :)




Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: