Migration from plain Clojure to Clojure / ClojureScript

I’m starting to consider what would be needed to make my CLI-matic lib compatible with both Clojure and ClojureScript.

My guess is that:

  1. I should rename non platform specific files to .cljc
  2. I should have the same namespaces defined in both .clj and cljs files (or use reader conditionals)

Would this work? anything I’m missing?

Plus: is there some library that wraps clj/cljs differences, so you can (say) read files, traverse directories, parse dates and other platform-specific stuff in a standard way?

How would you run you code, in Node.js or in a Browser? ClojureScript has much differences from Clojure when you are really running it.

I think Node, as I’m thinking about command-line tools.

1 Like

If you use macros in your code, you might want to look at Macrovich (by Christophe Grand) as it smoothes out the clj/cljs logistics.

I don’t know of any library that abstracts away the JVM/Node file system differences. That would be nice to have tho’!

I am not sure what could be in such a library - files, HTTP client, timing, Date/time manipulation… sounds scary :slight_smile:

Files are tricky because in node land you should be using the async flavors, and that is never easy to fake…

Maybe @Yogthos knows something since he was porting Ring stack to Node.

For date/time, there’s clj-time on the JVM (wrapping Joda Time) and cljs-time for JS and they have very similar APIs so that means you only need to conditionally require the appropriate namespace (with the same alias) to be able to write .cljc code that works on both sides.

That said, Joda Time is deprecated now that Java Time is part of Java 8+. There’s clojure.java-time for wrapping Java Time on the JVM and some folks have expressed interest in a cljs version of that library (presumably wrapping the same JS library as cljs-time wraps?) but someone has to want it enough to create that wrapper.

I think, realistically, not enough people are using ClojureScript on Node to warrant the effort involved to create such abstractions. Clojure’s design as a “hosted language” means that host interop is the recommended way to tackle host-specific stuff and 1. it’s painless enough that folks don’t build wrappers and 2. the hosts implement some of these things so differently that there is no one-size-fits-all abstraction.

1 Like

We have a couple of small services at work running on Macchiato https://macchiato-framework.github.io/ and we haven’t run into any show stoppers so far. We package our apps using Docker, and treat the image similarly to an uberjar.

The main downside of Node is its single threaded nature in my experience. Everything has to be async, and it makes code much harder to reason about, and it makes error handling challenging. Stuff like core.async helps with that to an extent, but I still think it’s far from ideal in practice.

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