I'm the author of cljs-devtools. I think for development it is perfectly fine to use Chrome Canary. Also I would recommend you to check out this article: https://github.com/binaryage/cljs-devtools/wiki/Figwheel-REP....
My public projects so far:
https://github.com/binaryage/cljs-devtools
https://github.com/binaryage/chromex
https://github.com/darwin/plastic
Sourcemaps have been a big help for debugging in general, though we have had several instances of bugs taking a bit of effort to get to the bottom of because of some deep javascript stacktraces -- for the most part the java side of the compiler hasn't been a big deal. Many of these have been type related bugs, so we're looking into adding some schemas[1] going forward where it seems appropriate. Despite those issues, it has overall been a huge productivity boost. We've also witnessed this story only improving with time.
The community truly is fantastic. Lots of very smart, friendly folks doing interesting things.
[0] https://github.com/bhauman/lein-figwheel [1] https://github.com/Prismatic/schema
I love writing Clojure(Script) code, but I hate reading it. It fits perfectly with the way I think (when I'm writing code), but horribly with the way I try to understand code I wrote months ago.
With that said, the emergence of Elm as a viable alternative to front end functional programming has pushed all my new projects away from ClojureScript. Now, for the author's CS complaints, Elm has:
* Fast compile times, startup time indistinguishable from JS.
* Great error messages.
* Imature tooling, but that's changing quickly.
* Static type checking.
So, maybe op should give Elm a try.
[Edit: clarification]
Would clojure's readability be helped by having a non-lisp pretty-printer? I've been thinking about this a bit - s-exps are great for writing, but fails to take advantage of our advanced visual pattern matching when reading it.
Unfortunately, yes, Elm is restricted to the browser. But this might change in the future. And although it is somewhat tedious to write ports, IME Elm communicates better with JS than ClojureScript. You can just drop any old JS library and write a port for it (it will be async, though).
Sexps alone don't bother me at all. What bothers me (and I only came to this conclusion recently, after reading this[0]) is the interplay between functional code and the absence of type annotations. Sometimes it feels like Lisp just wants you to write clever code, all the time. Clever Python code looks bad. Clever Lisp code looks pretty nice.
[0] http://elbenshira.com/blog/the-end-of-dynamic-languages/
Brandon Bloom's fipp[1] works fine but the Chrome Canary dev tools have support for object formatters. I get reasonable results on .170 just doing a (js/console.log a-map).
I've used Clojure for 2 years - I feel the same way. It's a wonderfull language that exposed me to great ideas and showed me that simple things can be simple but boy does it get nasty when things don't fit the provided primitives and actually start getting complex - the language has no tools to deal with complexity it can't simplify.
Also a - for CLJS from me is that they haven't abstracted out the (do ...) macro from channels (ironic with all those talks harping on how simplicity is about disentangling things). The biggest pain in JS/DOM ecosystem is shitty semantics, poor standard library and callback stacks. ClojureScript fixes first two really well and does a half-assed job at fixing the last - channels are too much overhead for such task (from both performance and conceptual POV - putting a queue in front of every callback is silly in a single threaded model).
I feel like Elm is a language designed to explore an idea not to be practical, this is why I haven't tried using it for anything serious.
TypeScript has potential in theory to bring ES6 + type safety to avoid semantic pitfalls - but in practice it's supposedly biggest strength of leveraging the existing JS ecosystem is also it's greatest weakness in that you're still left there with shitty JS ecosystem with zero consistency, most libraries deal with JS pitfalls in their own unique way which doesn't mesh well with other approaches or with TS, fragmented build, packing, dependency management, module loading tools - all trying to solve the same problem in different and incompatible ways - it's just a pile of junk that wastes more time trying to reuse stuff than it takes to build anything - which is probably why most of it is in the state it is - and very few things are actually maintained so the argument that reinventing something means you need to maintain it yourself is not really convincing.
Dart has a built in package manager, has had tools for dealing with async code for a while now (both async/await and streams), it's familiar to the Java/C# devs but it's surprisingly concise (quite a few nice touches like constructor property-parameter mapping or => getter syntax for tedious stuff), the standard library is great and avoids all the JS pitfalls.
The downside is that you still need JS interop because there's no way around it (for eg. emscripten) - and talking to JS from Dart is still nasty - much more involved than CLJS or TS.
Having used all 3 mentioned for non trivial work I like Dart the most and the new JS interop could make it even better.
The only unpractical part I'd noticed was its perspective on reusing components, as seen in this overview under 'Nesting' [1]. That bit of explicit routing aside, may I ask what dissuaded you from using the language seriously?
[1]: https://gist.github.com/evancz/2b2ba366cae1887fe621#nesting
Myself, I prefer ScalaJS because I already know Scala, the tooling is excellent, it is fast, and the resulting JS is of reasonable size.
Fortunately, it is not an either/or decision. Both compile to JS and can interoperate without too much effort.
Positives: <3 re-frame. It's the first architecture in 15 years of frontend dev that I've been happy with and I've tried pretty much everything. cljs is a better language than es6. I like devcards.
Negatives: I've put two work weeks into dealing with tooling problems. I have a 5 minute build. This mostly doesn't matter because incremental builds but every so often (e.g. Tuesday) I hit a problem and have to bisect with a fresh build at each step.
While I'm happy with the language, I'm less happy than I expected to be. I'm in the process of porting devcards and re-frame patterns to (functional) Typescript for my personal projects. The language is a significant barrier to contribution from a larger community and I get a bigger lift from optional types+autocomplete than I do from protocols and macros.
Edit: Is anybody interested in a set of Sublime-ish keybindings for Cursive? I made the set for my coworkers and for the things I can't do via IdeaVim and they've been working fairly well for the past couple weeks.
It also feels like the author is primarily interested in client-side ClojureScript, in which case the Leiningen start-up time should really only be a problem once per...day? week? I re-start my Clojure(Script) REPL process only when I change underlying dependencies, which isn't frequent enough for it to be a major issue.
The biggest issue for me that I agree with is the immature tooling thing, but that's been getting a lot better since I also blogged about being frustrated with ClojureScript (relevant link: blog.venanti.us/clojurescript-blues/). Vim and the CLJS REPL now work well together, and I've been really impressed by the direction and velocity of Figwheel as a project.
2) it may only hurt once a day/week once you have an established flow going, but when trying to figure things out & start things up, you restart a lot more than that. hence the barrier to entry
2. I think the barrier to starting a new project is unreasonably high, yes, and requires a highly inconvenient amount of configuration familiarity. Unfortunately the gap between just running the ClojureScript compiler on a single namespace file and actually configuring a viable project and build pipeline in Leiningen is quite large and really requires a concerted effort to overcome (or, to have someone nearby who's willing and able to show you what you're doing wrong).
Om.next end to end - Part I: Backend
http://marianoguerra.org/posts/omnext-end-to-end-part-i-back...
Om.next end to end - Part II: Frontend
http://marianoguerra.org/posts/omnext-end-to-end-part-ii-fro...
While coding it is awesome, debugging and maint is hell. I'm off to Typescript land after a great two year trip with ClojureScript. It reminded of everything I loved and hated about a dynamic language.
Honestly wondering: what do you wish for in clj debugging?
lein midje :autotest
More than anything it has completely changed my world view (and I'm a very experienced, older programmer who has seen a bit). I feel very lucky to have had this opportunity.
IMO, some of the issues you raise are genuine, some not.
For example, the JVM startup time issue is never, ever a problem. If it is, you aren't using the tools right.
I use Cursive and figwheel etc, so I find the tooling generally fine and in many ways excellent. The trajectory in this area is good.
Debugging initially can be rough. Knowing about things like cljs-devtools can dramatically improve things. But, yeah, valid point.
And, yes, poor error messages can definitely be a problem initially -- although this has improved over the last year.
To get going, I'd recommend you use this set of technologies:
- use Cursive/InteliiJ https://cursiveclojure.com/
- use reagent, rather than om. http://reagent-project.github.io/
- use figwheel
- use cljs-devtools with Canary for debugging
- use Schema to provide faint typing - https://github.com/Prismatic/schema
- perhaps use clairvoyant for debugging https://github.com/spellhouse/clairvoyant
- use timbre for logging https://github.com/ptaoussanis/timbre
- use re-frame https://github.com/Day8/re-frame (if the app is slightly more complex) <--- warning I'm biased
- perhaps use re-com - https://github.com/Day8/re-com <--- warning I'm biased
- you may also be interested in the head start provided by http://www.luminusweb.net/ for client/server
-
Perhaps just start here: https://github.com/Day8/re-frame-template and work out. (I'm biased)
Good luck.
In javascript, everything is mutable, but w/ new es7
spread/rest syntax it is increasingly easy to just do
immutable anyway. E.g. instead of myobj.x = newx you can
do myobj = {...myobj, x: newx} and everything is immutable
& persistant!
But if I'm reading this right:https://github.com/sebmarkbage/ecmascript-rest-spread
They will be neither immutable nor persistent.
I double checked the date of this article to make sure this wasn't written 6 months ago and posted now.
You should check out the clojurians slack channel, there you can probably get good answers for 85% of the things that are holding you back.
Good luck with it, using clojure/script + cursive clojure + intellij has been the best development experience I've had in 18 years of professional coding! It's 110% worth the investment.
good article overall. a point that was a little irksome was
> chrome devtools is way ahead of your cli repl (and even your editor-integrated repl) in a bunch of important ways
(emphasis added). b/c while i'm not saying the devtools is not ahead of figwheel+cider in some sense, enumerating specific want-to-haves would be more informative.
my main nice-to-have (and maybe there's something out there???) would be a way to set breakpoints for dropping into a repl. b/c of the scarcity of mutable state, it hasn't been such a problem, but there have been one of two times where i could've saved a few minutes by throwing a `(debugger)` or something in.