Need input on how to port Calva to ClojureScript

So, some while ago we ported the development process for Calva to shadow-cljs. It felt really good a while, even if only part of the code is in ClojureScript. (We have a v2 branch where we were planning to lay the foundation for faster moving everything over to cljs).

Further, we released a separate formatting extension, Calva Formatter, to separate the concerns some and give people some freedom to configure their VS Code Clojure development some. Calva Formatter is written entirely in ClojureScript (it is very little code). Shadow-cljs gives us access to lots of Clojure libraries which is good when you develop Clojure tooling.

However, what was already a quite painful development process with Calva written in JavaScript and all that entails, got even more painful with ClojureScript. Previously I could fall back on breakpoints and stepping through the code, but now that only works very seldomly and in a very limited way. And for similar reasons the REPL seldom works for solving the particular problems that are hardest to solve. I have spent 20 hours trying to understand why I fail to port the vscode-integration points of Calvas on type-formatting to ClojureScript. (It seems the compiler loses track of some namespaces, but everything is so opaque to me that that is just a very wild guess).

One obvious option is to give up on porting to ClojureScript and instead port to TypeScript, which is the preferred language for VS Code and ease a lot of the pain I had with JavaScript. But I really, really would like to be able to do most of the work in ClojureScript.

I’m thinking of trying to separate out everything that is not VS Code integration to ClojureScript modules and then use them from TypeScript where I could do just very thin wrappers around the modules to integrate. A bit like Clapperton wrapped paredit.js as a VS Code extension. I think that would give me back the REPL for developing the cljs code and the debugger for stepping the TypeScript code. Does that make sense? And if it does, do anyone of you have any experience of how to set up a toolchain that supports it?

Sorry for such open ended questions, I am stumbling with how to describe the problems and options I see. Please feel invited to ask me any questions about things I need to clarify to get help and input on this.

I don’t have any suggestions for you but maybe a bit of “lessons learned” feedback.

When I came to Clojure I had a very large CoffeeScript codebase. I first ported the server-side in pure Clojure and was very happy with that. There was very little server code though since most of it was driven by this gigantic client side app with small API endpoints. At first I didn’t touch the client side because it was working ok enough. When I started trying to port it I still had very little experience with Clojure and didn’t know much about the clojure-way. Naturally I just tried porting what I had to the CLJS syntax literally, basically writing JS in CLJS. This was a horrible experience. I think you are at that place now. It got way better when I stopped looking at the original CoffeeScript code altogether and approached everything fresh with a functional approach. Dropping everything I thought I knew basically. Untangling the OOP mess and just writing pure functions working with data made everything sooo much easier to debug/test.

Luckily I didn’t have to deal with this gigantic OOP API that is vscode so YMMV. TypeScript tooling is seriously impressive and CLJS is nowhere near that.

3 Likes

Thanks for sharing this experience. You are quite right about where the porting of Calva to ClojureScript is at the moment. That is partly what our v2 branch is about. And you are also right about that the OOP API of vscode makes for challenges of its own. That is why I am thinking about separating the vscode integration work and the ”general” work. If I make the cut right, the ”general” work should lend itself well for a purely functional approach.

1 Like

To try out the idea with using TypeScript for the VS Code integration and ClojureScript for everything else I have now released a version of Calva Formatter that is setup like this. It already is a much better development experience than how Calva is setup. I try to describe the how-to of this here:

I’d love me some feedback on this, from anyone who has some little time to check it out. If you do, please branch off from the wip-ontype-cljfmt branch, which is probably/hopefully going to be the new master (and also is implementing the on type formatter using CLJC, instead of JavaScript, like before).

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.